Blame view
ipc/msg.c
27.4 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
/* * linux/ipc/msg.c |
5a06a363e [PATCH] ipc/msg.c... |
4 |
* Copyright (C) 1992 Krishna Balasubramanian |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 8 9 10 11 12 13 14 15 |
* * Removed all the remaining kerneld mess * Catch the -EFAULT stuff properly * Use GFP_KERNEL for messages as in 1.2 * Fixed up the unchecked user space derefs * Copyright (C) 1998 Alan Cox & Andi Kleen * * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com> * * mostly rewritten, threaded and wake-one semantics added * MSGMAX limit removed, sysctl's added |
624dffcbc correct email add... |
16 |
* (c) 1999 Manfred Spraul <manfred@colorfullife.com> |
073115d6b [PATCH] Rework of... |
17 18 19 |
* * support for audit of ipc object properties and permission changes * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
1e7869373 [PATCH] IPC names... |
20 21 22 23 |
* * namespaces support * OpenVZ, SWsoft Inc. * Pavel Emelianov <xemul@openvz.org> |
1da177e4c Linux-2.6.12-rc2 |
24 |
*/ |
c59ede7b7 [PATCH] move capa... |
25 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
26 27 28 |
#include <linux/msg.h> #include <linux/spinlock.h> #include <linux/init.h> |
f7bf3df8b ipc: scale msgmni... |
29 |
#include <linux/mm.h> |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 |
#include <linux/proc_fs.h> #include <linux/list.h> #include <linux/security.h> |
84f001e15 sched/headers: Pr... |
33 |
#include <linux/sched/wake_q.h> |
1da177e4c Linux-2.6.12-rc2 |
34 35 |
#include <linux/syscalls.h> #include <linux/audit.h> |
19b4946ca [PATCH] ipc: conv... |
36 |
#include <linux/seq_file.h> |
3e148c799 fix idr_find() lo... |
37 |
#include <linux/rwsem.h> |
1e7869373 [PATCH] IPC names... |
38 |
#include <linux/nsproxy.h> |
ae5e1b22f namespaces: move ... |
39 |
#include <linux/ipc_namespace.h> |
5f921ae96 [PATCH] sem2mutex... |
40 |
|
1da177e4c Linux-2.6.12-rc2 |
41 |
#include <asm/current.h> |
7153e4027 ipc, kernel: use ... |
42 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
43 |
#include "util.h" |
4bb6657dd ipc,msg: document... |
44 |
/* one msg_receiver structure for each sleeping receiver */ |
1da177e4c Linux-2.6.12-rc2 |
45 |
struct msg_receiver { |
5a06a363e [PATCH] ipc/msg.c... |
46 47 |
struct list_head r_list; struct task_struct *r_tsk; |
1da177e4c Linux-2.6.12-rc2 |
48 |
|
5a06a363e [PATCH] ipc/msg.c... |
49 50 51 |
int r_mode; long r_msgtype; long r_maxsize; |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
ee51636ca ipc/msg: implemen... |
53 |
struct msg_msg *r_msg; |
1da177e4c Linux-2.6.12-rc2 |
54 55 56 57 |
}; /* one msg_sender for each sleeping sender */ struct msg_sender { |
5a06a363e [PATCH] ipc/msg.c... |
58 59 |
struct list_head list; struct task_struct *tsk; |
ed27f9122 ipc/msg: avoid wa... |
60 |
size_t msgsz; |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 64 65 66 |
}; #define SEARCH_ANY 1 #define SEARCH_EQUAL 2 #define SEARCH_NOTEQUAL 3 #define SEARCH_LESSEQUAL 4 |
8ac6ed585 ipc: implement MS... |
67 |
#define SEARCH_NUMBER 5 |
1da177e4c Linux-2.6.12-rc2 |
68 |
|
ed2ddbf88 IPC: make struct ... |
69 |
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) |
1da177e4c Linux-2.6.12-rc2 |
70 |
|
a5001a0d9 ipc,msg: introduc... |
71 72 |
static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id) { |
55b7ae501 ipc: rename ipc_o... |
73 |
struct kern_ipc_perm *ipcp = ipc_obtain_object_idr(&msg_ids(ns), id); |
a5001a0d9 ipc,msg: introduc... |
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
if (IS_ERR(ipcp)) return ERR_CAST(ipcp); return container_of(ipcp, struct msg_queue, q_perm); } static inline struct msg_queue *msq_obtain_object_check(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&msg_ids(ns), id); if (IS_ERR(ipcp)) return ERR_CAST(ipcp); return container_of(ipcp, struct msg_queue, q_perm); } |
7ca7e564e ipc: store ipcs i... |
91 92 93 94 |
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s) { ipc_rmid(&msg_ids(ns), &s->q_perm); } |
53dad6d3a ipc: fix race wit... |
95 96 |
static void msg_rcu_free(struct rcu_head *head) { |
dba4cdd39 ipc: merge ipc_rc... |
97 98 |
struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu); struct msg_queue *msq = container_of(p, struct msg_queue, q_perm); |
53dad6d3a ipc: fix race wit... |
99 100 |
security_msg_queue_free(msq); |
fb259c310 ipc/msg: remove s... |
101 |
kvfree(msq); |
52f908904 ipc/msg: avoid ip... |
102 |
} |
f4566f048 ipc: fix wrong co... |
103 104 105 106 107 |
/** * newque - Create a new msg queue * @ns: namespace * @params: ptr to the structure that contains the key and msgflg * |
d9a605e40 ipc: rename ids->... |
108 |
* Called with msg_ids.rwsem held (writer) |
f4566f048 ipc: fix wrong co... |
109 |
*/ |
7748dbfaa ipc: unify the sy... |
110 |
static int newque(struct ipc_namespace *ns, struct ipc_params *params) |
1da177e4c Linux-2.6.12-rc2 |
111 |
{ |
1da177e4c Linux-2.6.12-rc2 |
112 |
struct msg_queue *msq; |
51c23b7b7 ipc/msg.c: avoid ... |
113 |
int retval; |
7748dbfaa ipc: unify the sy... |
114 115 |
key_t key = params->key; int msgflg = params->flg; |
1da177e4c Linux-2.6.12-rc2 |
116 |
|
fb259c310 ipc/msg: remove s... |
117 118 |
msq = kvmalloc(sizeof(*msq), GFP_KERNEL); if (unlikely(!msq)) |
1da177e4c Linux-2.6.12-rc2 |
119 |
return -ENOMEM; |
5a06a363e [PATCH] ipc/msg.c... |
120 |
msq->q_perm.mode = msgflg & S_IRWXUGO; |
1da177e4c Linux-2.6.12-rc2 |
121 122 123 124 125 |
msq->q_perm.key = key; msq->q_perm.security = NULL; retval = security_msg_queue_alloc(msq); if (retval) { |
fb259c310 ipc/msg: remove s... |
126 |
kvfree(msq); |
1da177e4c Linux-2.6.12-rc2 |
127 128 |
return retval; } |
1da177e4c Linux-2.6.12-rc2 |
129 |
msq->q_stime = msq->q_rtime = 0; |
50578ea97 ipc: msg: Make ms... |
130 |
msq->q_ctime = ktime_get_real_seconds(); |
1da177e4c Linux-2.6.12-rc2 |
131 |
msq->q_cbytes = msq->q_qnum = 0; |
1e7869373 [PATCH] IPC names... |
132 |
msq->q_qbytes = ns->msg_ctlmnb; |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 |
msq->q_lspid = msq->q_lrpid = 0; INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); |
7ca7e564e ipc: store ipcs i... |
137 |
|
b9a532277 Initialize msg/sh... |
138 |
/* ipc_addid() locks msq upon success. */ |
51c23b7b7 ipc/msg.c: avoid ... |
139 140 141 142 |
retval = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); if (retval < 0) { call_rcu(&msq->q_perm.rcu, msg_rcu_free); return retval; |
b9a532277 Initialize msg/sh... |
143 |
} |
cf9d5d78d ipc: close open c... |
144 |
ipc_unlock_object(&msq->q_perm); |
dbfcd91f0 ipc: move rcu loc... |
145 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
146 |
|
7ca7e564e ipc: store ipcs i... |
147 |
return msq->q_perm.id; |
1da177e4c Linux-2.6.12-rc2 |
148 |
} |
ed27f9122 ipc/msg: avoid wa... |
149 150 151 152 153 154 155 156 |
static inline bool msg_fits_inqueue(struct msg_queue *msq, size_t msgsz) { return msgsz + msq->q_cbytes <= msq->q_qbytes && 1 + msq->q_qnum <= msq->q_qbytes; } static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss, size_t msgsz) |
1da177e4c Linux-2.6.12-rc2 |
157 |
{ |
5a06a363e [PATCH] ipc/msg.c... |
158 |
mss->tsk = current; |
ed27f9122 ipc/msg: avoid wa... |
159 |
mss->msgsz = msgsz; |
f75a2f358 ipc,msg: use curr... |
160 |
__set_current_state(TASK_INTERRUPTIBLE); |
5a06a363e [PATCH] ipc/msg.c... |
161 |
list_add_tail(&mss->list, &msq->q_senders); |
1da177e4c Linux-2.6.12-rc2 |
162 |
} |
5a06a363e [PATCH] ipc/msg.c... |
163 |
static inline void ss_del(struct msg_sender *mss) |
1da177e4c Linux-2.6.12-rc2 |
164 |
{ |
ed27f9122 ipc/msg: avoid wa... |
165 |
if (mss->list.next) |
1da177e4c Linux-2.6.12-rc2 |
166 167 |
list_del(&mss->list); } |
ed27f9122 ipc/msg: avoid wa... |
168 |
static void ss_wakeup(struct msg_queue *msq, |
d0d6a2a95 ipc/msg: make ss_... |
169 |
struct wake_q_head *wake_q, bool kill) |
1da177e4c Linux-2.6.12-rc2 |
170 |
{ |
41239fe82 ipc/msg.c: use li... |
171 |
struct msg_sender *mss, *t; |
ed27f9122 ipc/msg: avoid wa... |
172 173 |
struct task_struct *stop_tsk = NULL; struct list_head *h = &msq->q_senders; |
1da177e4c Linux-2.6.12-rc2 |
174 |
|
41239fe82 ipc/msg.c: use li... |
175 |
list_for_each_entry_safe(mss, t, h, list) { |
5a06a363e [PATCH] ipc/msg.c... |
176 177 |
if (kill) mss->list.next = NULL; |
ed27f9122 ipc/msg: avoid wa... |
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
/* * Stop at the first task we don't wakeup, * we've already iterated the original * sender queue. */ else if (stop_tsk == mss->tsk) break; /* * We are not in an EIDRM scenario here, therefore * verify that we really need to wakeup the task. * To maintain current semantics and wakeup order, * move the sender to the tail on behalf of the * blocked task. */ else if (!msg_fits_inqueue(msq, mss->msgsz)) { if (!stop_tsk) stop_tsk = mss->tsk; list_move_tail(&mss->list, &msq->q_senders); continue; } |
e3658538b ipc/msg: batch qu... |
200 |
wake_q_add(wake_q, mss->tsk); |
1da177e4c Linux-2.6.12-rc2 |
201 202 |
} } |
ee51636ca ipc/msg: implemen... |
203 204 |
static void expunge_all(struct msg_queue *msq, int res, struct wake_q_head *wake_q) |
1da177e4c Linux-2.6.12-rc2 |
205 |
{ |
41239fe82 ipc/msg.c: use li... |
206 |
struct msg_receiver *msr, *t; |
5a06a363e [PATCH] ipc/msg.c... |
207 |
|
41239fe82 ipc/msg.c: use li... |
208 |
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
ee51636ca ipc/msg: implemen... |
209 210 |
wake_q_add(wake_q, msr->r_tsk); WRITE_ONCE(msr->r_msg, ERR_PTR(res)); |
1da177e4c Linux-2.6.12-rc2 |
211 212 |
} } |
5a06a363e [PATCH] ipc/msg.c... |
213 214 215 |
/* * freeque() wakes up waiters on the sender and receiver waiting queue, |
f4566f048 ipc: fix wrong co... |
216 217 |
* removes the message queue from message queue ID IDR, and cleans up all the * messages associated with this queue. |
1da177e4c Linux-2.6.12-rc2 |
218 |
* |
d9a605e40 ipc: rename ids->... |
219 220 |
* msg_ids.rwsem (writer) and the spinlock for this message queue are held * before freeque() is called. msg_ids.rwsem remains locked on exit. |
1da177e4c Linux-2.6.12-rc2 |
221 |
*/ |
01b8b07a5 IPC: consolidate ... |
222 |
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) |
1da177e4c Linux-2.6.12-rc2 |
223 |
{ |
41239fe82 ipc/msg.c: use li... |
224 |
struct msg_msg *msg, *t; |
01b8b07a5 IPC: consolidate ... |
225 |
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); |
194a6b5b9 sched/wake_q: Ren... |
226 |
DEFINE_WAKE_Q(wake_q); |
1da177e4c Linux-2.6.12-rc2 |
227 |
|
ee51636ca ipc/msg: implemen... |
228 |
expunge_all(msq, -EIDRM, &wake_q); |
ed27f9122 ipc/msg: avoid wa... |
229 |
ss_wakeup(msq, &wake_q, true); |
7ca7e564e ipc: store ipcs i... |
230 |
msg_rmid(ns, msq); |
4718787d1 ipc,msg: drop msg... |
231 |
ipc_unlock_object(&msq->q_perm); |
ee51636ca ipc/msg: implemen... |
232 |
wake_up_q(&wake_q); |
4718787d1 ipc,msg: drop msg... |
233 |
rcu_read_unlock(); |
5a06a363e [PATCH] ipc/msg.c... |
234 |
|
41239fe82 ipc/msg.c: use li... |
235 |
list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) { |
3ac88a41f virtualization of... |
236 |
atomic_dec(&ns->msg_hdrs); |
1da177e4c Linux-2.6.12-rc2 |
237 238 |
free_msg(msg); } |
3ac88a41f virtualization of... |
239 |
atomic_sub(msq->q_cbytes, &ns->msg_bytes); |
dba4cdd39 ipc: merge ipc_rc... |
240 |
ipc_rcu_putref(&msq->q_perm, msg_rcu_free); |
1da177e4c Linux-2.6.12-rc2 |
241 |
} |
f4566f048 ipc: fix wrong co... |
242 |
/* |
d9a605e40 ipc: rename ids->... |
243 |
* Called with msg_ids.rwsem and ipcp locked. |
f4566f048 ipc: fix wrong co... |
244 |
*/ |
03f02c765 Storing ipcs into... |
245 |
static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) |
7748dbfaa ipc: unify the sy... |
246 |
{ |
03f02c765 Storing ipcs into... |
247 248 249 |
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); return security_msg_queue_associate(msq, msgflg); |
7748dbfaa ipc: unify the sy... |
250 |
} |
e48fbb699 [CVE-2009-0029] S... |
251 |
SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) |
1da177e4c Linux-2.6.12-rc2 |
252 |
{ |
1e7869373 [PATCH] IPC names... |
253 |
struct ipc_namespace *ns; |
eb66ec44f ipc: constify ipc... |
254 255 256 257 |
static const struct ipc_ops msg_ops = { .getnew = newque, .associate = msg_security, }; |
7748dbfaa ipc: unify the sy... |
258 |
struct ipc_params msg_params; |
1e7869373 [PATCH] IPC names... |
259 260 |
ns = current->nsproxy->ipc_ns; |
7ca7e564e ipc: store ipcs i... |
261 |
|
7748dbfaa ipc: unify the sy... |
262 263 |
msg_params.key = key; msg_params.flg = msgflg; |
5a06a363e [PATCH] ipc/msg.c... |
264 |
|
7748dbfaa ipc: unify the sy... |
265 |
return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); |
1da177e4c Linux-2.6.12-rc2 |
266 |
} |
5a06a363e [PATCH] ipc/msg.c... |
267 268 |
static inline unsigned long copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) |
1da177e4c Linux-2.6.12-rc2 |
269 |
{ |
239521f31 ipc: whitespace c... |
270 |
switch (version) { |
1da177e4c Linux-2.6.12-rc2 |
271 |
case IPC_64: |
5a06a363e [PATCH] ipc/msg.c... |
272 |
return copy_to_user(buf, in, sizeof(*in)); |
1da177e4c Linux-2.6.12-rc2 |
273 |
case IPC_OLD: |
5a06a363e [PATCH] ipc/msg.c... |
274 |
{ |
1da177e4c Linux-2.6.12-rc2 |
275 |
struct msqid_ds out; |
5a06a363e [PATCH] ipc/msg.c... |
276 |
memset(&out, 0, sizeof(out)); |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 281 282 |
ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm); out.msg_stime = in->msg_stime; out.msg_rtime = in->msg_rtime; out.msg_ctime = in->msg_ctime; |
4be929be3 kernel-wide: repl... |
283 284 |
if (in->msg_cbytes > USHRT_MAX) out.msg_cbytes = USHRT_MAX; |
1da177e4c Linux-2.6.12-rc2 |
285 286 287 |
else out.msg_cbytes = in->msg_cbytes; out.msg_lcbytes = in->msg_cbytes; |
4be929be3 kernel-wide: repl... |
288 289 |
if (in->msg_qnum > USHRT_MAX) out.msg_qnum = USHRT_MAX; |
1da177e4c Linux-2.6.12-rc2 |
290 291 |
else out.msg_qnum = in->msg_qnum; |
4be929be3 kernel-wide: repl... |
292 293 |
if (in->msg_qbytes > USHRT_MAX) out.msg_qbytes = USHRT_MAX; |
1da177e4c Linux-2.6.12-rc2 |
294 295 296 297 298 299 |
else out.msg_qbytes = in->msg_qbytes; out.msg_lqbytes = in->msg_qbytes; out.msg_lspid = in->msg_lspid; out.msg_lrpid = in->msg_lrpid; |
5a06a363e [PATCH] ipc/msg.c... |
300 301 |
return copy_to_user(buf, &out, sizeof(out)); } |
1da177e4c Linux-2.6.12-rc2 |
302 303 304 305 |
default: return -EINVAL; } } |
5a06a363e [PATCH] ipc/msg.c... |
306 |
static inline unsigned long |
016d7132f IPC: get rid of t... |
307 |
copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) |
1da177e4c Linux-2.6.12-rc2 |
308 |
{ |
239521f31 ipc: whitespace c... |
309 |
switch (version) { |
1da177e4c Linux-2.6.12-rc2 |
310 |
case IPC_64: |
016d7132f IPC: get rid of t... |
311 |
if (copy_from_user(out, buf, sizeof(*out))) |
1da177e4c Linux-2.6.12-rc2 |
312 |
return -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
313 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
314 |
case IPC_OLD: |
5a06a363e [PATCH] ipc/msg.c... |
315 |
{ |
1da177e4c Linux-2.6.12-rc2 |
316 |
struct msqid_ds tbuf_old; |
5a06a363e [PATCH] ipc/msg.c... |
317 |
if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) |
1da177e4c Linux-2.6.12-rc2 |
318 |
return -EFAULT; |
239521f31 ipc: whitespace c... |
319 320 321 |
out->msg_perm.uid = tbuf_old.msg_perm.uid; out->msg_perm.gid = tbuf_old.msg_perm.gid; out->msg_perm.mode = tbuf_old.msg_perm.mode; |
1da177e4c Linux-2.6.12-rc2 |
322 |
|
5a06a363e [PATCH] ipc/msg.c... |
323 |
if (tbuf_old.msg_qbytes == 0) |
016d7132f IPC: get rid of t... |
324 |
out->msg_qbytes = tbuf_old.msg_lqbytes; |
1da177e4c Linux-2.6.12-rc2 |
325 |
else |
016d7132f IPC: get rid of t... |
326 |
out->msg_qbytes = tbuf_old.msg_qbytes; |
1da177e4c Linux-2.6.12-rc2 |
327 328 |
return 0; |
5a06a363e [PATCH] ipc/msg.c... |
329 |
} |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 333 |
default: return -EINVAL; } } |
a0d092fc2 IPC/message queue... |
334 |
/* |
d9a605e40 ipc: rename ids->... |
335 |
* This function handles some msgctl commands which require the rwsem |
a0d092fc2 IPC/message queue... |
336 |
* to be held in write mode. |
d9a605e40 ipc: rename ids->... |
337 |
* NOTE: no locks must be held, the rwsem is taken inside this function. |
a0d092fc2 IPC/message queue... |
338 339 |
*/ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, |
156d9ed12 msgctl(): split t... |
340 |
struct msqid64_ds *msqid64) |
1da177e4c Linux-2.6.12-rc2 |
341 |
{ |
1da177e4c Linux-2.6.12-rc2 |
342 |
struct kern_ipc_perm *ipcp; |
a0d092fc2 IPC/message queue... |
343 344 |
struct msg_queue *msq; int err; |
d9a605e40 ipc: rename ids->... |
345 |
down_write(&msg_ids(ns).rwsem); |
7b4cc5d84 ipc: move locking... |
346 |
rcu_read_lock(); |
15724ecb7 ipc,msg: shorten ... |
347 |
ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, |
156d9ed12 msgctl(): split t... |
348 |
&msqid64->msg_perm, msqid64->msg_qbytes); |
7b4cc5d84 ipc: move locking... |
349 350 |
if (IS_ERR(ipcp)) { err = PTR_ERR(ipcp); |
7b4cc5d84 ipc: move locking... |
351 352 |
goto out_unlock1; } |
a0d092fc2 IPC/message queue... |
353 |
|
a5f75e7f2 IPC: consolidate ... |
354 |
msq = container_of(ipcp, struct msg_queue, q_perm); |
a0d092fc2 IPC/message queue... |
355 356 357 |
err = security_msg_queue_msgctl(msq, cmd); if (err) |
15724ecb7 ipc,msg: shorten ... |
358 |
goto out_unlock1; |
a0d092fc2 IPC/message queue... |
359 360 361 |
switch (cmd) { case IPC_RMID: |
15724ecb7 ipc,msg: shorten ... |
362 |
ipc_lock_object(&msq->q_perm); |
7b4cc5d84 ipc: move locking... |
363 |
/* freeque unlocks the ipc object and rcu */ |
a0d092fc2 IPC/message queue... |
364 365 366 |
freeque(ns, ipcp); goto out_up; case IPC_SET: |
e3658538b ipc/msg: batch qu... |
367 |
{ |
194a6b5b9 sched/wake_q: Ren... |
368 |
DEFINE_WAKE_Q(wake_q); |
e3658538b ipc/msg: batch qu... |
369 |
|
156d9ed12 msgctl(): split t... |
370 |
if (msqid64->msg_qbytes > ns->msg_ctlmnb && |
a0d092fc2 IPC/message queue... |
371 372 |
!capable(CAP_SYS_RESOURCE)) { err = -EPERM; |
15724ecb7 ipc,msg: shorten ... |
373 |
goto out_unlock1; |
a0d092fc2 IPC/message queue... |
374 |
} |
15724ecb7 ipc,msg: shorten ... |
375 |
ipc_lock_object(&msq->q_perm); |
156d9ed12 msgctl(): split t... |
376 |
err = ipc_update_perm(&msqid64->msg_perm, ipcp); |
1efdb69b0 userns: Convert i... |
377 |
if (err) |
7b4cc5d84 ipc: move locking... |
378 |
goto out_unlock0; |
1efdb69b0 userns: Convert i... |
379 |
|
156d9ed12 msgctl(): split t... |
380 |
msq->q_qbytes = msqid64->msg_qbytes; |
a0d092fc2 IPC/message queue... |
381 |
|
50578ea97 ipc: msg: Make ms... |
382 |
msq->q_ctime = ktime_get_real_seconds(); |
e3658538b ipc/msg: batch qu... |
383 384 |
/* * Sleeping receivers might be excluded by |
a0d092fc2 IPC/message queue... |
385 386 |
* stricter permissions. */ |
ee51636ca ipc/msg: implemen... |
387 |
expunge_all(msq, -EAGAIN, &wake_q); |
e3658538b ipc/msg: batch qu... |
388 389 |
/* * Sleeping senders might be able to send |
a0d092fc2 IPC/message queue... |
390 391 |
* due to a larger queue size. */ |
ed27f9122 ipc/msg: avoid wa... |
392 |
ss_wakeup(msq, &wake_q, false); |
e3658538b ipc/msg: batch qu... |
393 394 395 396 397 |
ipc_unlock_object(&msq->q_perm); wake_up_q(&wake_q); goto out_unlock1; } |
a0d092fc2 IPC/message queue... |
398 399 |
default: err = -EINVAL; |
15724ecb7 ipc,msg: shorten ... |
400 |
goto out_unlock1; |
a0d092fc2 IPC/message queue... |
401 |
} |
7b4cc5d84 ipc: move locking... |
402 403 404 405 406 |
out_unlock0: ipc_unlock_object(&msq->q_perm); out_unlock1: rcu_read_unlock(); |
a0d092fc2 IPC/message queue... |
407 |
out_up: |
d9a605e40 ipc: rename ids->... |
408 |
up_write(&msg_ids(ns).rwsem); |
a0d092fc2 IPC/message queue... |
409 410 |
return err; } |
156d9ed12 msgctl(): split t... |
411 412 |
static int msgctl_info(struct ipc_namespace *ns, int msqid, int cmd, struct msginfo *msginfo) |
a0d092fc2 IPC/message queue... |
413 |
{ |
2cafed30f ipc,msg: introduc... |
414 |
int err; |
156d9ed12 msgctl(): split t... |
415 |
int max_id; |
1da177e4c Linux-2.6.12-rc2 |
416 |
|
156d9ed12 msgctl(): split t... |
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
/* * We must not return kernel stack data. * due to padding, it's not enough * to set all member fields. */ err = security_msg_queue_msgctl(NULL, cmd); if (err) return err; memset(msginfo, 0, sizeof(*msginfo)); msginfo->msgmni = ns->msg_ctlmni; msginfo->msgmax = ns->msg_ctlmax; msginfo->msgmnb = ns->msg_ctlmnb; msginfo->msgssz = MSGSSZ; msginfo->msgseg = MSGSEG; down_read(&msg_ids(ns).rwsem); if (cmd == MSG_INFO) { msginfo->msgpool = msg_ids(ns).in_use; msginfo->msgmap = atomic_read(&ns->msg_hdrs); msginfo->msgtql = atomic_read(&ns->msg_bytes); } else { msginfo->msgmap = MSGMAP; msginfo->msgpool = MSGPOOL; msginfo->msgtql = MSGTQL; |
1da177e4c Linux-2.6.12-rc2 |
441 |
} |
156d9ed12 msgctl(): split t... |
442 443 444 445 |
max_id = ipc_get_maxid(&msg_ids(ns)); up_read(&msg_ids(ns).rwsem); return (max_id < 0) ? 0 : max_id; } |
2cafed30f ipc,msg: introduc... |
446 |
|
156d9ed12 msgctl(): split t... |
447 448 449 450 451 452 |
static int msgctl_stat(struct ipc_namespace *ns, int msqid, int cmd, struct msqid64_ds *p) { int err; struct msg_queue *msq; int success_return; |
ac0ba20ea ipc,msg: make msg... |
453 |
|
156d9ed12 msgctl(): split t... |
454 |
memset(p, 0, sizeof(*p)); |
ac0ba20ea ipc,msg: make msg... |
455 |
|
156d9ed12 msgctl(): split t... |
456 457 458 459 460 |
rcu_read_lock(); if (cmd == MSG_STAT) { msq = msq_obtain_object(ns, msqid); if (IS_ERR(msq)) { err = PTR_ERR(msq); |
1da177e4c Linux-2.6.12-rc2 |
461 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
462 |
} |
156d9ed12 msgctl(): split t... |
463 464 465 466 467 |
success_return = msq->q_perm.id; } else { msq = msq_obtain_object_check(ns, msqid); if (IS_ERR(msq)) { err = PTR_ERR(msq); |
1da177e4c Linux-2.6.12-rc2 |
468 |
goto out_unlock; |
156d9ed12 msgctl(): split t... |
469 470 471 |
} success_return = 0; } |
1da177e4c Linux-2.6.12-rc2 |
472 |
|
156d9ed12 msgctl(): split t... |
473 474 475 |
err = -EACCES; if (ipcperms(ns, &msq->q_perm, S_IRUGO)) goto out_unlock; |
ac0ba20ea ipc,msg: make msg... |
476 |
|
156d9ed12 msgctl(): split t... |
477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
err = security_msg_queue_msgctl(msq, cmd); if (err) goto out_unlock; kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm); p->msg_stime = msq->q_stime; p->msg_rtime = msq->q_rtime; p->msg_ctime = msq->q_ctime; p->msg_cbytes = msq->q_cbytes; p->msg_qnum = msq->q_qnum; p->msg_qbytes = msq->q_qbytes; p->msg_lspid = msq->q_lspid; p->msg_lrpid = msq->q_lrpid; rcu_read_unlock(); |
2cafed30f ipc,msg: introduc... |
491 |
|
156d9ed12 msgctl(): split t... |
492 |
return success_return; |
1da177e4c Linux-2.6.12-rc2 |
493 |
|
1da177e4c Linux-2.6.12-rc2 |
494 |
out_unlock: |
ac0ba20ea ipc,msg: make msg... |
495 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
496 497 |
return err; } |
2cafed30f ipc,msg: introduc... |
498 499 500 501 |
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) { int version; struct ipc_namespace *ns; |
156d9ed12 msgctl(): split t... |
502 503 |
struct msqid64_ds msqid64; int err; |
2cafed30f ipc,msg: introduc... |
504 505 506 507 508 509 510 511 512 |
if (msqid < 0 || cmd < 0) return -EINVAL; version = ipc_parse_version(&cmd); ns = current->nsproxy->ipc_ns; switch (cmd) { case IPC_INFO: |
156d9ed12 msgctl(): split t... |
513 514 515 516 517 518 519 520 521 |
case MSG_INFO: { struct msginfo msginfo; err = msgctl_info(ns, msqid, cmd, &msginfo); if (err < 0) return err; if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) err = -EFAULT; return err; } |
2cafed30f ipc,msg: introduc... |
522 523 |
case MSG_STAT: /* msqid is an index rather than a msg queue id */ case IPC_STAT: |
156d9ed12 msgctl(): split t... |
524 525 526 527 528 529 |
err = msgctl_stat(ns, msqid, cmd, &msqid64); if (err < 0) return err; if (copy_msqid_to_user(buf, &msqid64, version)) err = -EFAULT; return err; |
2cafed30f ipc,msg: introduc... |
530 |
case IPC_SET: |
156d9ed12 msgctl(): split t... |
531 532 533 |
if (copy_msqid_from_user(&msqid64, buf, version)) return -EFAULT; /* fallthru */ |
2cafed30f ipc,msg: introduc... |
534 |
case IPC_RMID: |
156d9ed12 msgctl(): split t... |
535 |
return msgctl_down(ns, msqid, cmd, &msqid64); |
2cafed30f ipc,msg: introduc... |
536 537 538 539 |
default: return -EINVAL; } } |
469391684 msgctl(): move co... |
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
#ifdef CONFIG_COMPAT struct compat_msqid_ds { struct compat_ipc_perm msg_perm; compat_uptr_t msg_first; compat_uptr_t msg_last; compat_time_t msg_stime; compat_time_t msg_rtime; compat_time_t msg_ctime; compat_ulong_t msg_lcbytes; compat_ulong_t msg_lqbytes; unsigned short msg_cbytes; unsigned short msg_qnum; unsigned short msg_qbytes; compat_ipc_pid_t msg_lspid; compat_ipc_pid_t msg_lrpid; }; static int copy_compat_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) { memset(out, 0, sizeof(*out)); if (version == IPC_64) { struct compat_msqid64_ds *p = buf; |
28327fae6 ipc: make use of ... |
564 |
if (get_compat_ipc64_perm(&out->msg_perm, &p->msg_perm)) |
469391684 msgctl(): move co... |
565 |
return -EFAULT; |
469391684 msgctl(): move co... |
566 567 568 569 |
if (get_user(out->msg_qbytes, &p->msg_qbytes)) return -EFAULT; } else { struct compat_msqid_ds *p = buf; |
28327fae6 ipc: make use of ... |
570 |
if (get_compat_ipc_perm(&out->msg_perm, &p->msg_perm)) |
469391684 msgctl(): move co... |
571 |
return -EFAULT; |
469391684 msgctl(): move co... |
572 573 574 575 576 577 578 579 580 581 582 583 |
if (get_user(out->msg_qbytes, &p->msg_qbytes)) return -EFAULT; } return 0; } static int copy_compat_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) { if (version == IPC_64) { struct compat_msqid64_ds v; memset(&v, 0, sizeof(v)); |
28327fae6 ipc: make use of ... |
584 |
to_compat_ipc64_perm(&v.msg_perm, &in->msg_perm); |
469391684 msgctl(): move co... |
585 586 587 588 589 590 591 592 593 594 595 596 |
v.msg_stime = in->msg_stime; v.msg_rtime = in->msg_rtime; v.msg_ctime = in->msg_ctime; v.msg_cbytes = in->msg_cbytes; v.msg_qnum = in->msg_qnum; v.msg_qbytes = in->msg_qbytes; v.msg_lspid = in->msg_lspid; v.msg_lrpid = in->msg_lrpid; return copy_to_user(buf, &v, sizeof(v)); } else { struct compat_msqid_ds v; memset(&v, 0, sizeof(v)); |
28327fae6 ipc: make use of ... |
597 |
to_compat_ipc_perm(&v.msg_perm, &in->msg_perm); |
469391684 msgctl(): move co... |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
v.msg_stime = in->msg_stime; v.msg_rtime = in->msg_rtime; v.msg_ctime = in->msg_ctime; v.msg_cbytes = in->msg_cbytes; v.msg_qnum = in->msg_qnum; v.msg_qbytes = in->msg_qbytes; v.msg_lspid = in->msg_lspid; v.msg_lrpid = in->msg_lrpid; return copy_to_user(buf, &v, sizeof(v)); } } COMPAT_SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, void __user *, uptr) { struct ipc_namespace *ns; int err; struct msqid64_ds msqid64; int version = compat_ipc_parse_version(&cmd); ns = current->nsproxy->ipc_ns; if (msqid < 0 || cmd < 0) return -EINVAL; switch (cmd & (~IPC_64)) { case IPC_INFO: case MSG_INFO: { struct msginfo msginfo; err = msgctl_info(ns, msqid, cmd, &msginfo); if (err < 0) return err; if (copy_to_user(uptr, &msginfo, sizeof(struct msginfo))) err = -EFAULT; return err; } case IPC_STAT: case MSG_STAT: err = msgctl_stat(ns, msqid, cmd, &msqid64); if (err < 0) return err; if (copy_compat_msqid_to_user(uptr, &msqid64, version)) err = -EFAULT; return err; case IPC_SET: if (copy_compat_msqid_from_user(&msqid64, uptr, version)) return -EFAULT; /* fallthru */ case IPC_RMID: return msgctl_down(ns, msqid, cmd, &msqid64); default: return -EINVAL; } } #endif |
5a06a363e [PATCH] ipc/msg.c... |
652 |
static int testmsg(struct msg_msg *msg, long type, int mode) |
1da177e4c Linux-2.6.12-rc2 |
653 |
{ |
46c0a8ca3 ipc, kernel: clea... |
654 655 656 657 658 659 660 661 662 663 |
switch (mode) { case SEARCH_ANY: case SEARCH_NUMBER: return 1; case SEARCH_LESSEQUAL: if (msg->m_type <= type) return 1; break; case SEARCH_EQUAL: if (msg->m_type == type) |
1da177e4c Linux-2.6.12-rc2 |
664 |
return 1; |
46c0a8ca3 ipc, kernel: clea... |
665 666 667 668 669 |
break; case SEARCH_NOTEQUAL: if (msg->m_type != type) return 1; break; |
1da177e4c Linux-2.6.12-rc2 |
670 671 672 |
} return 0; } |
ee51636ca ipc/msg: implemen... |
673 674 |
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg, struct wake_q_head *wake_q) |
1da177e4c Linux-2.6.12-rc2 |
675 |
{ |
41239fe82 ipc/msg.c: use li... |
676 |
struct msg_receiver *msr, *t; |
5a06a363e [PATCH] ipc/msg.c... |
677 |
|
41239fe82 ipc/msg.c: use li... |
678 |
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
5a06a363e [PATCH] ipc/msg.c... |
679 680 681 |
if (testmsg(msg, msr->r_msgtype, msr->r_mode) && !security_msg_queue_msgrcv(msq, msg, msr->r_tsk, msr->r_msgtype, msr->r_mode)) { |
1da177e4c Linux-2.6.12-rc2 |
682 |
list_del(&msr->r_list); |
5a06a363e [PATCH] ipc/msg.c... |
683 |
if (msr->r_maxsize < msg->m_ts) { |
ee51636ca ipc/msg: implemen... |
684 685 |
wake_q_add(wake_q, msr->r_tsk); WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG)); |
1da177e4c Linux-2.6.12-rc2 |
686 |
} else { |
b488893a3 pid namespaces: c... |
687 |
msq->q_lrpid = task_pid_vnr(msr->r_tsk); |
1da177e4c Linux-2.6.12-rc2 |
688 |
msq->q_rtime = get_seconds(); |
5a06a363e [PATCH] ipc/msg.c... |
689 |
|
ee51636ca ipc/msg: implemen... |
690 691 |
wake_q_add(wake_q, msr->r_tsk); WRITE_ONCE(msr->r_msg, msg); |
1da177e4c Linux-2.6.12-rc2 |
692 693 694 695 |
return 1; } } } |
ffa571daf ipc,msg: document... |
696 |
|
1da177e4c Linux-2.6.12-rc2 |
697 698 |
return 0; } |
9b1404c24 msgrcv(2), msgsnd... |
699 |
static long do_msgsnd(int msqid, long mtype, void __user *mtext, |
651971cb7 [PATCH] Fix the s... |
700 |
size_t msgsz, int msgflg) |
1da177e4c Linux-2.6.12-rc2 |
701 702 703 |
{ struct msg_queue *msq; struct msg_msg *msg; |
1da177e4c Linux-2.6.12-rc2 |
704 |
int err; |
1e7869373 [PATCH] IPC names... |
705 |
struct ipc_namespace *ns; |
194a6b5b9 sched/wake_q: Ren... |
706 |
DEFINE_WAKE_Q(wake_q); |
1e7869373 [PATCH] IPC names... |
707 708 |
ns = current->nsproxy->ipc_ns; |
5a06a363e [PATCH] ipc/msg.c... |
709 |
|
1e7869373 [PATCH] IPC names... |
710 |
if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) |
1da177e4c Linux-2.6.12-rc2 |
711 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
712 713 |
if (mtype < 1) return -EINVAL; |
651971cb7 [PATCH] Fix the s... |
714 |
msg = load_msg(mtext, msgsz); |
5a06a363e [PATCH] ipc/msg.c... |
715 |
if (IS_ERR(msg)) |
1da177e4c Linux-2.6.12-rc2 |
716 717 718 719 |
return PTR_ERR(msg); msg->m_type = mtype; msg->m_ts = msgsz; |
3dd1f784e ipc,msg: shorten ... |
720 721 |
rcu_read_lock(); msq = msq_obtain_object_check(ns, msqid); |
023a53557 ipc: integrate ip... |
722 723 |
if (IS_ERR(msq)) { err = PTR_ERR(msq); |
3dd1f784e ipc,msg: shorten ... |
724 |
goto out_unlock1; |
023a53557 ipc: integrate ip... |
725 |
} |
1da177e4c Linux-2.6.12-rc2 |
726 |
|
bebcb928c ipc/msg.c: Fix lo... |
727 |
ipc_lock_object(&msq->q_perm); |
1da177e4c Linux-2.6.12-rc2 |
728 729 |
for (;;) { struct msg_sender s; |
5a06a363e [PATCH] ipc/msg.c... |
730 |
err = -EACCES; |
b0e77598f userns: user name... |
731 |
if (ipcperms(ns, &msq->q_perm, S_IWUGO)) |
bebcb928c ipc/msg.c: Fix lo... |
732 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
733 |
|
4271b05a2 ipc,msg: prevent ... |
734 |
/* raced with RMID? */ |
0f3d2b013 ipc: introduce ip... |
735 |
if (!ipc_valid_object(&msq->q_perm)) { |
4271b05a2 ipc,msg: prevent ... |
736 737 738 |
err = -EIDRM; goto out_unlock0; } |
1da177e4c Linux-2.6.12-rc2 |
739 740 |
err = security_msg_queue_msgsnd(msq, msg, msgflg); if (err) |
bebcb928c ipc/msg.c: Fix lo... |
741 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
742 |
|
ed27f9122 ipc/msg: avoid wa... |
743 |
if (msg_fits_inqueue(msq, msgsz)) |
1da177e4c Linux-2.6.12-rc2 |
744 |
break; |
1da177e4c Linux-2.6.12-rc2 |
745 746 |
/* queue full, wait: */ |
5a06a363e [PATCH] ipc/msg.c... |
747 748 |
if (msgflg & IPC_NOWAIT) { err = -EAGAIN; |
bebcb928c ipc/msg.c: Fix lo... |
749 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
750 |
} |
3dd1f784e ipc,msg: shorten ... |
751 |
|
ffa571daf ipc,msg: document... |
752 |
/* enqueue the sender and prepare to block */ |
ed27f9122 ipc/msg: avoid wa... |
753 |
ss_add(msq, &s, msgsz); |
6062a8dc0 ipc,sem: fine gra... |
754 |
|
dba4cdd39 ipc: merge ipc_rc... |
755 |
if (!ipc_rcu_getref(&msq->q_perm)) { |
6062a8dc0 ipc,sem: fine gra... |
756 |
err = -EIDRM; |
3dd1f784e ipc,msg: shorten ... |
757 |
goto out_unlock0; |
6062a8dc0 ipc,sem: fine gra... |
758 |
} |
3dd1f784e ipc,msg: shorten ... |
759 760 |
ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
761 |
schedule(); |
3dd1f784e ipc,msg: shorten ... |
762 763 |
rcu_read_lock(); ipc_lock_object(&msq->q_perm); |
dba4cdd39 ipc: merge ipc_rc... |
764 |
ipc_rcu_putref(&msq->q_perm, msg_rcu_free); |
0f3d2b013 ipc: introduce ip... |
765 766 |
/* raced with RMID? */ if (!ipc_valid_object(&msq->q_perm)) { |
1da177e4c Linux-2.6.12-rc2 |
767 |
err = -EIDRM; |
3dd1f784e ipc,msg: shorten ... |
768 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
769 770 |
} ss_del(&s); |
5a06a363e [PATCH] ipc/msg.c... |
771 |
|
1da177e4c Linux-2.6.12-rc2 |
772 |
if (signal_pending(current)) { |
5a06a363e [PATCH] ipc/msg.c... |
773 |
err = -ERESTARTNOHAND; |
3dd1f784e ipc,msg: shorten ... |
774 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
775 |
} |
3dd1f784e ipc,msg: shorten ... |
776 |
|
1da177e4c Linux-2.6.12-rc2 |
777 |
} |
ed27f9122 ipc/msg: avoid wa... |
778 |
|
b488893a3 pid namespaces: c... |
779 |
msq->q_lspid = task_tgid_vnr(current); |
1da177e4c Linux-2.6.12-rc2 |
780 |
msq->q_stime = get_seconds(); |
ee51636ca ipc/msg: implemen... |
781 |
if (!pipelined_send(msq, msg, &wake_q)) { |
25985edce Fix common misspe... |
782 |
/* no one is waiting for this message, enqueue it */ |
5a06a363e [PATCH] ipc/msg.c... |
783 |
list_add_tail(&msg->m_list, &msq->q_messages); |
1da177e4c Linux-2.6.12-rc2 |
784 785 |
msq->q_cbytes += msgsz; msq->q_qnum++; |
3ac88a41f virtualization of... |
786 787 |
atomic_add(msgsz, &ns->msg_bytes); atomic_inc(&ns->msg_hdrs); |
1da177e4c Linux-2.6.12-rc2 |
788 |
} |
5a06a363e [PATCH] ipc/msg.c... |
789 |
|
1da177e4c Linux-2.6.12-rc2 |
790 791 |
err = 0; msg = NULL; |
3dd1f784e ipc,msg: shorten ... |
792 793 |
out_unlock0: ipc_unlock_object(&msq->q_perm); |
ee51636ca ipc/msg: implemen... |
794 |
wake_up_q(&wake_q); |
3dd1f784e ipc,msg: shorten ... |
795 796 |
out_unlock1: rcu_read_unlock(); |
5a06a363e [PATCH] ipc/msg.c... |
797 |
if (msg != NULL) |
1da177e4c Linux-2.6.12-rc2 |
798 799 800 |
free_msg(msg); return err; } |
e48fbb699 [CVE-2009-0029] S... |
801 802 |
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, int, msgflg) |
651971cb7 [PATCH] Fix the s... |
803 804 805 806 807 808 809 |
{ long mtype; if (get_user(mtype, &msgp->mtype)) return -EFAULT; return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); } |
9b1404c24 msgrcv(2), msgsnd... |
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
#ifdef CONFIG_COMPAT struct compat_msgbuf { compat_long_t mtype; char mtext[1]; }; COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, compat_ssize_t, msgsz, int, msgflg) { struct compat_msgbuf __user *up = compat_ptr(msgp); compat_long_t mtype; if (get_user(mtype, &up->mtype)) return -EFAULT; return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); } #endif |
5a06a363e [PATCH] ipc/msg.c... |
828 |
static inline int convert_mode(long *msgtyp, int msgflg) |
1da177e4c Linux-2.6.12-rc2 |
829 |
{ |
8ac6ed585 ipc: implement MS... |
830 831 |
if (msgflg & MSG_COPY) return SEARCH_NUMBER; |
5a06a363e [PATCH] ipc/msg.c... |
832 |
/* |
1da177e4c Linux-2.6.12-rc2 |
833 834 835 |
* find message of correct type. * msgtyp = 0 => get first. * msgtyp > 0 => get first message of matching type. |
5a06a363e [PATCH] ipc/msg.c... |
836 |
* msgtyp < 0 => get message with least type must be < abs(msgtype). |
1da177e4c Linux-2.6.12-rc2 |
837 |
*/ |
5a06a363e [PATCH] ipc/msg.c... |
838 |
if (*msgtyp == 0) |
1da177e4c Linux-2.6.12-rc2 |
839 |
return SEARCH_ANY; |
5a06a363e [PATCH] ipc/msg.c... |
840 |
if (*msgtyp < 0) { |
999898355 ipc: msg, make ms... |
841 842 843 844 |
if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */ *msgtyp = LONG_MAX; else *msgtyp = -*msgtyp; |
1da177e4c Linux-2.6.12-rc2 |
845 846 |
return SEARCH_LESSEQUAL; } |
5a06a363e [PATCH] ipc/msg.c... |
847 |
if (msgflg & MSG_EXCEPT) |
1da177e4c Linux-2.6.12-rc2 |
848 849 850 |
return SEARCH_NOTEQUAL; return SEARCH_EQUAL; } |
f9dd87f47 ipc: message queu... |
851 852 853 854 855 856 857 858 859 860 861 862 863 |
static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) { struct msgbuf __user *msgp = dest; size_t msgsz; if (put_user(msg->m_type, &msgp->mtype)) return -EFAULT; msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; if (store_msg(msgp->mtext, msg, msgsz)) return -EFAULT; return msgsz; } |
4a674f34b ipc: introduce me... |
864 |
#ifdef CONFIG_CHECKPOINT_RESTORE |
3fcfe7865 ipc: add more com... |
865 866 867 868 |
/* * This function creates new kernel message structure, large enough to store * bufsz message bytes. */ |
8ac6ed585 ipc: implement MS... |
869 |
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz) |
4a674f34b ipc: introduce me... |
870 871 |
{ struct msg_msg *copy; |
4a674f34b ipc: introduce me... |
872 873 874 875 876 877 878 879 |
/* * Create dummy message to copy real message to. */ copy = load_msg(buf, bufsz); if (!IS_ERR(copy)) copy->m_ts = bufsz; return copy; } |
85398aa8d ipc: simplify fre... |
880 |
static inline void free_copy(struct msg_msg *copy) |
4a674f34b ipc: introduce me... |
881 |
{ |
85398aa8d ipc: simplify fre... |
882 |
if (copy) |
4a674f34b ipc: introduce me... |
883 884 885 |
free_msg(copy); } #else |
8ac6ed585 ipc: implement MS... |
886 |
static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz) |
b30efe277 ipc: convert prep... |
887 888 889 |
{ return ERR_PTR(-ENOSYS); } |
85398aa8d ipc: simplify fre... |
890 891 892 |
static inline void free_copy(struct msg_msg *copy) { } |
4a674f34b ipc: introduce me... |
893 |
#endif |
daaf74cf0 ipc: refactor msg... |
894 895 |
static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode) { |
368ae537e IPC: bugfix for m... |
896 |
struct msg_msg *msg, *found = NULL; |
daaf74cf0 ipc: refactor msg... |
897 898 899 900 901 902 903 904 |
long count = 0; list_for_each_entry(msg, &msq->q_messages, m_list) { if (testmsg(msg, *msgtyp, mode) && !security_msg_queue_msgrcv(msq, msg, current, *msgtyp, mode)) { if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) { *msgtyp = msg->m_type - 1; |
368ae537e IPC: bugfix for m... |
905 |
found = msg; |
daaf74cf0 ipc: refactor msg... |
906 907 908 909 910 911 912 913 |
} else if (mode == SEARCH_NUMBER) { if (*msgtyp == count) return msg; } else return msg; count++; } } |
368ae537e IPC: bugfix for m... |
914 |
return found ?: ERR_PTR(-EAGAIN); |
daaf74cf0 ipc: refactor msg... |
915 |
} |
9b1404c24 msgrcv(2), msgsnd... |
916 |
static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg, |
f9dd87f47 ipc: message queu... |
917 |
long (*msg_handler)(void __user *, struct msg_msg *, size_t)) |
1da177e4c Linux-2.6.12-rc2 |
918 |
{ |
1da177e4c Linux-2.6.12-rc2 |
919 |
int mode; |
41a0d523d ipc,msg: shorten ... |
920 |
struct msg_queue *msq; |
1e7869373 [PATCH] IPC names... |
921 |
struct ipc_namespace *ns; |
41a0d523d ipc,msg: shorten ... |
922 |
struct msg_msg *msg, *copy = NULL; |
194a6b5b9 sched/wake_q: Ren... |
923 |
DEFINE_WAKE_Q(wake_q); |
1da177e4c Linux-2.6.12-rc2 |
924 |
|
88b9e456b ipc: don't alloca... |
925 |
ns = current->nsproxy->ipc_ns; |
f9dd87f47 ipc: message queu... |
926 |
if (msqid < 0 || (long) bufsz < 0) |
1da177e4c Linux-2.6.12-rc2 |
927 |
return -EINVAL; |
41a0d523d ipc,msg: shorten ... |
928 |
|
4a674f34b ipc: introduce me... |
929 |
if (msgflg & MSG_COPY) { |
4f87dac38 ipc: Fix 2 bugs i... |
930 931 |
if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT)) return -EINVAL; |
8ac6ed585 ipc: implement MS... |
932 |
copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); |
4a674f34b ipc: introduce me... |
933 934 935 |
if (IS_ERR(copy)) return PTR_ERR(copy); } |
5a06a363e [PATCH] ipc/msg.c... |
936 |
mode = convert_mode(&msgtyp, msgflg); |
1da177e4c Linux-2.6.12-rc2 |
937 |
|
41a0d523d ipc,msg: shorten ... |
938 939 |
rcu_read_lock(); msq = msq_obtain_object_check(ns, msqid); |
4a674f34b ipc: introduce me... |
940 |
if (IS_ERR(msq)) { |
41a0d523d ipc,msg: shorten ... |
941 |
rcu_read_unlock(); |
85398aa8d ipc: simplify fre... |
942 |
free_copy(copy); |
023a53557 ipc: integrate ip... |
943 |
return PTR_ERR(msq); |
4a674f34b ipc: introduce me... |
944 |
} |
1da177e4c Linux-2.6.12-rc2 |
945 946 947 |
for (;;) { struct msg_receiver msr_d; |
1da177e4c Linux-2.6.12-rc2 |
948 949 |
msg = ERR_PTR(-EACCES); |
b0e77598f userns: user name... |
950 |
if (ipcperms(ns, &msq->q_perm, S_IRUGO)) |
41a0d523d ipc,msg: shorten ... |
951 |
goto out_unlock1; |
1da177e4c Linux-2.6.12-rc2 |
952 |
|
41a0d523d ipc,msg: shorten ... |
953 |
ipc_lock_object(&msq->q_perm); |
4271b05a2 ipc,msg: prevent ... |
954 955 |
/* raced with RMID? */ |
0f3d2b013 ipc: introduce ip... |
956 |
if (!ipc_valid_object(&msq->q_perm)) { |
4271b05a2 ipc,msg: prevent ... |
957 958 959 |
msg = ERR_PTR(-EIDRM); goto out_unlock0; } |
daaf74cf0 ipc: refactor msg... |
960 |
msg = find_msg(msq, &msgtyp, mode); |
5a06a363e [PATCH] ipc/msg.c... |
961 962 963 964 965 |
if (!IS_ERR(msg)) { /* * Found a suitable message. * Unlink it from the queue. */ |
f9dd87f47 ipc: message queu... |
966 |
if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { |
1da177e4c Linux-2.6.12-rc2 |
967 |
msg = ERR_PTR(-E2BIG); |
41a0d523d ipc,msg: shorten ... |
968 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
969 |
} |
3fcfe7865 ipc: add more com... |
970 971 972 973 |
/* * If we are copying, then do not unlink message and do * not update queue parameters. */ |
852028af8 ipc: remove msg h... |
974 975 |
if (msgflg & MSG_COPY) { msg = copy_msg(msg, copy); |
41a0d523d ipc,msg: shorten ... |
976 |
goto out_unlock0; |
852028af8 ipc: remove msg h... |
977 |
} |
41a0d523d ipc,msg: shorten ... |
978 |
|
1da177e4c Linux-2.6.12-rc2 |
979 980 981 |
list_del(&msg->m_list); msq->q_qnum--; msq->q_rtime = get_seconds(); |
b488893a3 pid namespaces: c... |
982 |
msq->q_lrpid = task_tgid_vnr(current); |
1da177e4c Linux-2.6.12-rc2 |
983 |
msq->q_cbytes -= msg->m_ts; |
3ac88a41f virtualization of... |
984 985 |
atomic_sub(msg->m_ts, &ns->msg_bytes); atomic_dec(&ns->msg_hdrs); |
ed27f9122 ipc/msg: avoid wa... |
986 |
ss_wakeup(msq, &wake_q, false); |
41a0d523d ipc,msg: shorten ... |
987 988 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
989 |
} |
41a0d523d ipc,msg: shorten ... |
990 |
|
1da177e4c Linux-2.6.12-rc2 |
991 992 993 |
/* No message waiting. Wait for a message */ if (msgflg & IPC_NOWAIT) { msg = ERR_PTR(-ENOMSG); |
41a0d523d ipc,msg: shorten ... |
994 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
995 |
} |
41a0d523d ipc,msg: shorten ... |
996 |
|
5a06a363e [PATCH] ipc/msg.c... |
997 |
list_add_tail(&msr_d.r_list, &msq->q_receivers); |
1da177e4c Linux-2.6.12-rc2 |
998 999 1000 |
msr_d.r_tsk = current; msr_d.r_msgtype = msgtyp; msr_d.r_mode = mode; |
5a06a363e [PATCH] ipc/msg.c... |
1001 |
if (msgflg & MSG_NOERROR) |
1da177e4c Linux-2.6.12-rc2 |
1002 |
msr_d.r_maxsize = INT_MAX; |
5a06a363e [PATCH] ipc/msg.c... |
1003 |
else |
f9dd87f47 ipc: message queu... |
1004 |
msr_d.r_maxsize = bufsz; |
1da177e4c Linux-2.6.12-rc2 |
1005 |
msr_d.r_msg = ERR_PTR(-EAGAIN); |
f75a2f358 ipc,msg: use curr... |
1006 |
__set_current_state(TASK_INTERRUPTIBLE); |
1da177e4c Linux-2.6.12-rc2 |
1007 |
|
41a0d523d ipc,msg: shorten ... |
1008 1009 |
ipc_unlock_object(&msq->q_perm); rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
1010 |
schedule(); |
ee51636ca ipc/msg: implemen... |
1011 1012 1013 1014 1015 1016 |
/* * Lockless receive, part 1: * We don't hold a reference to the queue and getting a * reference would defeat the idea of a lockless operation, * thus the code relies on rcu to guarantee the existence of * msq: |
1da177e4c Linux-2.6.12-rc2 |
1017 1018 |
* Prior to destruction, expunge_all(-EIRDM) changes r_msg. * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. |
1da177e4c Linux-2.6.12-rc2 |
1019 1020 |
*/ rcu_read_lock(); |
ee51636ca ipc/msg: implemen... |
1021 1022 1023 1024 1025 1026 |
/* * Lockless receive, part 2: * The work in pipelined_send() and expunge_all(): * - Set pointer to message * - Queue the receiver task for later wakeup * - Wake up the process after the lock is dropped. |
ff35e5ef8 ipc,msg: provide ... |
1027 |
* |
ee51636ca ipc/msg: implemen... |
1028 1029 |
* Should the process wake up before this wakeup (due to a * signal) it will either see the message and continue ... |
1da177e4c Linux-2.6.12-rc2 |
1030 |
*/ |
ee51636ca ipc/msg: implemen... |
1031 |
msg = READ_ONCE(msr_d.r_msg); |
41a0d523d ipc,msg: shorten ... |
1032 1033 |
if (msg != ERR_PTR(-EAGAIN)) goto out_unlock1; |
1da177e4c Linux-2.6.12-rc2 |
1034 |
|
ee51636ca ipc/msg: implemen... |
1035 1036 1037 1038 |
/* * ... or see -EAGAIN, acquire the lock to check the message * again. */ |
41a0d523d ipc,msg: shorten ... |
1039 |
ipc_lock_object(&msq->q_perm); |
1da177e4c Linux-2.6.12-rc2 |
1040 |
|
ee51636ca ipc/msg: implemen... |
1041 |
msg = msr_d.r_msg; |
5a06a363e [PATCH] ipc/msg.c... |
1042 |
if (msg != ERR_PTR(-EAGAIN)) |
41a0d523d ipc,msg: shorten ... |
1043 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
1044 1045 1046 1047 |
list_del(&msr_d.r_list); if (signal_pending(current)) { msg = ERR_PTR(-ERESTARTNOHAND); |
41a0d523d ipc,msg: shorten ... |
1048 |
goto out_unlock0; |
1da177e4c Linux-2.6.12-rc2 |
1049 |
} |
41a0d523d ipc,msg: shorten ... |
1050 1051 |
ipc_unlock_object(&msq->q_perm); |
1da177e4c Linux-2.6.12-rc2 |
1052 |
} |
41a0d523d ipc,msg: shorten ... |
1053 1054 1055 |
out_unlock0: ipc_unlock_object(&msq->q_perm); |
e3658538b ipc/msg: batch qu... |
1056 |
wake_up_q(&wake_q); |
41a0d523d ipc,msg: shorten ... |
1057 1058 |
out_unlock1: rcu_read_unlock(); |
4a674f34b ipc: introduce me... |
1059 |
if (IS_ERR(msg)) { |
85398aa8d ipc: simplify fre... |
1060 |
free_copy(copy); |
5a06a363e [PATCH] ipc/msg.c... |
1061 |
return PTR_ERR(msg); |
4a674f34b ipc: introduce me... |
1062 |
} |
1da177e4c Linux-2.6.12-rc2 |
1063 |
|
f9dd87f47 ipc: message queu... |
1064 |
bufsz = msg_handler(buf, msg, bufsz); |
1da177e4c Linux-2.6.12-rc2 |
1065 |
free_msg(msg); |
5a06a363e [PATCH] ipc/msg.c... |
1066 |
|
f9dd87f47 ipc: message queu... |
1067 |
return bufsz; |
1da177e4c Linux-2.6.12-rc2 |
1068 |
} |
e48fbb699 [CVE-2009-0029] S... |
1069 1070 |
SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) |
651971cb7 [PATCH] Fix the s... |
1071 |
{ |
f9dd87f47 ipc: message queu... |
1072 |
return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill); |
651971cb7 [PATCH] Fix the s... |
1073 |
} |
9b1404c24 msgrcv(2), msgsnd... |
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
#ifdef CONFIG_COMPAT static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) { struct compat_msgbuf __user *msgp = dest; size_t msgsz; if (put_user(msg->m_type, &msgp->mtype)) return -EFAULT; msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; if (store_msg(msgp->mtext, msg, msgsz)) return -EFAULT; return msgsz; } COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg) { return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp, msgflg, compat_do_msg_fill); } #endif |
3440a6bd1 ipc,msg: move som... |
1096 |
|
0cfb6aee7 ipc: optimize sem... |
1097 |
int msg_init_ns(struct ipc_namespace *ns) |
3440a6bd1 ipc,msg: move som... |
1098 1099 1100 |
{ ns->msg_ctlmax = MSGMAX; ns->msg_ctlmnb = MSGMNB; |
0050ee059 ipc/msg: increase... |
1101 |
ns->msg_ctlmni = MSGMNI; |
3440a6bd1 ipc,msg: move som... |
1102 1103 1104 |
atomic_set(&ns->msg_bytes, 0); atomic_set(&ns->msg_hdrs, 0); |
0cfb6aee7 ipc: optimize sem... |
1105 |
return ipc_init_ids(&ns->ids[IPC_MSG_IDS]); |
3440a6bd1 ipc,msg: move som... |
1106 1107 1108 1109 1110 1111 1112 |
} #ifdef CONFIG_IPC_NS void msg_exit_ns(struct ipc_namespace *ns) { free_ipcs(ns, &msg_ids(ns), freeque); idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); |
0cfb6aee7 ipc: optimize sem... |
1113 |
rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht); |
3440a6bd1 ipc,msg: move som... |
1114 1115 |
} #endif |
1da177e4c Linux-2.6.12-rc2 |
1116 |
#ifdef CONFIG_PROC_FS |
19b4946ca [PATCH] ipc: conv... |
1117 |
static int sysvipc_msg_proc_show(struct seq_file *s, void *it) |
1da177e4c Linux-2.6.12-rc2 |
1118 |
{ |
1efdb69b0 userns: Convert i... |
1119 |
struct user_namespace *user_ns = seq_user_ns(s); |
ade9f91b3 ipc: add missing ... |
1120 1121 |
struct kern_ipc_perm *ipcp = it; struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); |
19b4946ca [PATCH] ipc: conv... |
1122 |
|
7f032d6ef ipc: remove use o... |
1123 |
seq_printf(s, |
50578ea97 ipc: msg: Make ms... |
1124 1125 |
"%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10llu %10llu %10llu ", |
7f032d6ef ipc: remove use o... |
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
msq->q_perm.key, msq->q_perm.id, msq->q_perm.mode, msq->q_cbytes, msq->q_qnum, msq->q_lspid, msq->q_lrpid, from_kuid_munged(user_ns, msq->q_perm.uid), from_kgid_munged(user_ns, msq->q_perm.gid), from_kuid_munged(user_ns, msq->q_perm.cuid), from_kgid_munged(user_ns, msq->q_perm.cgid), msq->q_stime, msq->q_rtime, msq->q_ctime); return 0; |
1da177e4c Linux-2.6.12-rc2 |
1142 1143 |
} #endif |
3440a6bd1 ipc,msg: move som... |
1144 |
|
0cfb6aee7 ipc: optimize sem... |
1145 |
int __init msg_init(void) |
3440a6bd1 ipc,msg: move som... |
1146 |
{ |
0cfb6aee7 ipc: optimize sem... |
1147 |
const int err = msg_init_ns(&init_ipc_ns); |
3440a6bd1 ipc,msg: move som... |
1148 |
|
3440a6bd1 ipc,msg: move som... |
1149 1150 1151 1152 |
ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime ", IPC_MSG_IDS, sysvipc_msg_proc_show); |
0cfb6aee7 ipc: optimize sem... |
1153 |
return err; |
3440a6bd1 ipc,msg: move som... |
1154 |
} |