Blame view

ipc/msgutil.c 3.61 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f30c22695   Uwe Zeisberger   fix file specific...
2
   * linux/ipc/msgutil.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
   * Copyright (C) 1999, 2004 Manfred Spraul
   *
   * This file is released under GNU General Public Licence version 2 or
   * (at your option) any later version.
   *
   * See the file COPYING for more details.
   */
  
  #include <linux/spinlock.h>
  #include <linux/init.h>
  #include <linux/security.h>
  #include <linux/slab.h>
  #include <linux/ipc.h>
404015308   Al Viro   security: trim se...
16
  #include <linux/msg.h>
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
17
  #include <linux/ipc_namespace.h>
404015308   Al Viro   security: trim se...
18
  #include <linux/utsname.h>
0bb80f240   David Howells   proc: Split the n...
19
  #include <linux/proc_ns.h>
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
20
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  #include "util.h"
7eafd7c74   Serge E. Hallyn   namespaces: ipc n...
23
  DEFINE_SPINLOCK(mq_lock);
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
24
25
26
27
28
29
  /*
   * The next 2 defines are here bc this is the only file
   * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
   * and not CONFIG_IPC_NS.
   */
  struct ipc_namespace init_ipc_ns = {
a2e0602c3   Elena Reshetova   ipc: convert ipc_...
30
  	.count		= REFCOUNT_INIT(1),
b515498f5   Serge E. Hallyn   userns: add a use...
31
  	.user_ns = &init_user_ns,
435d5f4bb   Al Viro   common object emb...
32
  	.ns.inum = PROC_IPC_INIT_INO,
33c429405   Al Viro   copy address of p...
33
34
35
  #ifdef CONFIG_IPC_NS
  	.ns.ops = &ipcns_operations,
  #endif
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
36
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  struct msg_msgseg {
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
38
  	struct msg_msgseg *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  	/* the next part of the message follows immediately */
  };
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
41
42
  #define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
  #define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

be5f4b335   Peter Hurley   ipc: separate msg...
44

4e9b45a19   Mathias Krause   ipc, msg: fix mes...
45
  static struct msg_msg *alloc_msg(size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  {
  	struct msg_msg *msg;
  	struct msg_msgseg **pseg;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
49
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

3d8fa456d   Peter Hurley   ipc: clamp with m...
51
  	alen = min(len, DATALEN_MSG);
8c8d4d452   Aristeu Rozanski   ipc: account for ...
52
  	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	if (msg == NULL)
be5f4b335   Peter Hurley   ipc: separate msg...
54
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
  
  	msg->next = NULL;
  	msg->security = NULL;
be5f4b335   Peter Hurley   ipc: separate msg...
58
59
60
61
62
  	len -= alen;
  	pseg = &msg->next;
  	while (len > 0) {
  		struct msg_msgseg *seg;
  		alen = min(len, DATALEN_SEG);
8c8d4d452   Aristeu Rozanski   ipc: account for ...
63
  		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
be5f4b335   Peter Hurley   ipc: separate msg...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  		if (seg == NULL)
  			goto out_err;
  		*pseg = seg;
  		seg->next = NULL;
  		pseg = &seg->next;
  		len -= alen;
  	}
  
  	return msg;
  
  out_err:
  	free_msg(msg);
  	return NULL;
  }
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
78
  struct msg_msg *load_msg(const void __user *src, size_t len)
be5f4b335   Peter Hurley   ipc: separate msg...
79
80
81
  {
  	struct msg_msg *msg;
  	struct msg_msgseg *seg;
2b3097a29   Peter Hurley   ipc: set EFAULT a...
82
  	int err = -EFAULT;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
83
  	size_t alen;
be5f4b335   Peter Hurley   ipc: separate msg...
84
85
86
87
88
89
  
  	msg = alloc_msg(len);
  	if (msg == NULL)
  		return ERR_PTR(-ENOMEM);
  
  	alen = min(len, DATALEN_MSG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
90
  	if (copy_from_user(msg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

da085d459   Peter Hurley   ipc: tighten msg ...
93
94
95
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		src = (char __user *)src + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
96
  		alen = min(len, DATALEN_SEG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
97
  		if (copy_from_user(seg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
  	}
  
  	err = security_msg_msg_alloc(msg);
  	if (err)
  		goto out_err;
  
  	return msg;
  
  out_err:
  	free_msg(msg);
  	return ERR_PTR(err);
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
111
112
113
114
  #ifdef CONFIG_CHECKPOINT_RESTORE
  struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
  {
  	struct msg_msgseg *dst_pseg, *src_pseg;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
115
116
  	size_t len = src->m_ts;
  	size_t alen;
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
117

4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
118
119
  	if (src->m_ts > dst->m_ts)
  		return ERR_PTR(-EINVAL);
3d8fa456d   Peter Hurley   ipc: clamp with m...
120
  	alen = min(len, DATALEN_MSG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
121
  	memcpy(dst + 1, src + 1, alen);
da085d459   Peter Hurley   ipc: tighten msg ...
122
123
124
125
126
  	for (dst_pseg = dst->next, src_pseg = src->next;
  	     src_pseg != NULL;
  	     dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
  
  		len -= alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
127
  		alen = min(len, DATALEN_SEG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
128
  		memcpy(dst_pseg + 1, src_pseg + 1, alen);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
129
130
131
132
133
134
135
  	}
  
  	dst->m_type = src->m_type;
  	dst->m_ts = src->m_ts;
  
  	return dst;
  }
51eeacaa0   Stanislav Kinsbursky   ipc: simplify mes...
136
137
138
139
140
  #else
  struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
  {
  	return ERR_PTR(-ENOSYS);
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
141
  #endif
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
142
  int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  {
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
144
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  	struct msg_msgseg *seg;
3d8fa456d   Peter Hurley   ipc: clamp with m...
146
  	alen = min(len, DATALEN_MSG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  	if (copy_to_user(dest, msg + 1, alen))
  		return -1;
da085d459   Peter Hurley   ipc: tighten msg ...
149
150
151
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		dest = (char __user *)dest + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
152
  		alen = min(len, DATALEN_SEG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
  		if (copy_to_user(dest, seg + 1, alen))
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  	}
  	return 0;
  }
  
  void free_msg(struct msg_msg *msg)
  {
  	struct msg_msgseg *seg;
  
  	security_msg_msg_free(msg);
  
  	seg = msg->next;
  	kfree(msg);
  	while (seg != NULL) {
  		struct msg_msgseg *tmp = seg->next;
  		kfree(seg);
  		seg = tmp;
  	}
  }