Blame view

ipc/msg.c 27.4 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /*
   * linux/ipc/msg.c
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
4
   * Copyright (C) 1992 Krishna Balasubramanian
1da177e4c   Linus Torvalds   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   Christian Kujau   correct email add...
16
   * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
073115d6b   Steve Grubb   [PATCH] Rework of...
17
18
19
   *
   * support for audit of ipc object properties and permission changes
   * Dustin Kirkland <dustin.kirkland@us.ibm.com>
1e7869373   Kirill Korotaev   [PATCH] IPC names...
20
21
22
23
   *
   * namespaces support
   * OpenVZ, SWsoft Inc.
   * Pavel Emelianov <xemul@openvz.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
   */
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
25
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
  #include <linux/msg.h>
  #include <linux/spinlock.h>
  #include <linux/init.h>
f7bf3df8b   Nadia Derbey   ipc: scale msgmni...
29
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
  #include <linux/proc_fs.h>
  #include <linux/list.h>
  #include <linux/security.h>
84f001e15   Ingo Molnar   sched/headers: Pr...
33
  #include <linux/sched/wake_q.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  #include <linux/syscalls.h>
  #include <linux/audit.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
36
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
37
  #include <linux/rwsem.h>
1e7869373   Kirill Korotaev   [PATCH] IPC names...
38
  #include <linux/nsproxy.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
39
  #include <linux/ipc_namespace.h>
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
40

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  #include <asm/current.h>
7153e4027   Paul McQuade   ipc, kernel: use ...
42
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #include "util.h"
4bb6657dd   Davidlohr Bueso   ipc,msg: document...
44
  /* one msg_receiver structure for each sleeping receiver */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  struct msg_receiver {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
46
47
  	struct list_head	r_list;
  	struct task_struct	*r_tsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48

5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
49
50
51
  	int			r_mode;
  	long			r_msgtype;
  	long			r_maxsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
53
  	struct msg_msg		*r_msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
  };
  
  /* one msg_sender for each sleeping sender */
  struct msg_sender {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
58
59
  	struct list_head	list;
  	struct task_struct	*tsk;
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
60
  	size_t                  msgsz;
1da177e4c   Linus Torvalds   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   Peter Hurley   ipc: implement MS...
67
  #define SEARCH_NUMBER		5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

ed2ddbf88   Pierre Peiffer   IPC: make struct ...
69
  #define msg_ids(ns)	((ns)->ids[IPC_MSG_IDS])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

a5001a0d9   Davidlohr Bueso   ipc,msg: introduc...
71
72
  static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id)
  {
55b7ae501   Davidlohr Bueso   ipc: rename ipc_o...
73
  	struct kern_ipc_perm *ipcp = ipc_obtain_object_idr(&msg_ids(ns), id);
a5001a0d9   Davidlohr Bueso   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   Nadia Derbey   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   Davidlohr Bueso   ipc: fix race wit...
95
96
  static void msg_rcu_free(struct rcu_head *head)
  {
dba4cdd39   Manfred Spraul   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   Davidlohr Bueso   ipc: fix race wit...
99
100
  
  	security_msg_queue_free(msq);
fb259c310   Kees Cook   ipc/msg: remove s...
101
  	kvfree(msq);
52f908904   Kees Cook   ipc/msg: avoid ip...
102
  }
f4566f048   Nadia Derbey   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   Davidlohr Bueso   ipc: rename ids->...
108
   * Called with msg_ids.rwsem held (writer)
f4566f048   Nadia Derbey   ipc: fix wrong co...
109
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
110
  static int newque(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  	struct msg_queue *msq;
51c23b7b7   Manfred Spraul   ipc/msg.c: avoid ...
113
  	int retval;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
114
115
  	key_t key = params->key;
  	int msgflg = params->flg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

fb259c310   Kees Cook   ipc/msg: remove s...
117
118
  	msq = kvmalloc(sizeof(*msq), GFP_KERNEL);
  	if (unlikely(!msq))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  		return -ENOMEM;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
120
  	msq->q_perm.mode = msgflg & S_IRWXUGO;
1da177e4c   Linus Torvalds   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   Kees Cook   ipc/msg: remove s...
126
  		kvfree(msq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  		return retval;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  	msq->q_stime = msq->q_rtime = 0;
50578ea97   Deepa Dinamani   ipc: msg: Make ms...
130
  	msq->q_ctime = ktime_get_real_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	msq->q_cbytes = msq->q_qnum = 0;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
132
  	msq->q_qbytes = ns->msg_ctlmnb;
1da177e4c   Linus Torvalds   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   Nadia Derbey   ipc: store ipcs i...
137

b9a532277   Linus Torvalds   Initialize msg/sh...
138
  	/* ipc_addid() locks msq upon success. */
51c23b7b7   Manfred Spraul   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   Linus Torvalds   Initialize msg/sh...
143
  	}
cf9d5d78d   Davidlohr Bueso   ipc: close open c...
144
  	ipc_unlock_object(&msq->q_perm);
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
145
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

7ca7e564e   Nadia Derbey   ipc: store ipcs i...
147
  	return msq->q_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  }
ed27f9122   Davidlohr Bueso   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   Linus Torvalds   Linux-2.6.12-rc2
157
  {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
158
  	mss->tsk = current;
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
159
  	mss->msgsz = msgsz;
f75a2f358   Davidlohr Bueso   ipc,msg: use curr...
160
  	__set_current_state(TASK_INTERRUPTIBLE);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
161
  	list_add_tail(&mss->list, &msq->q_senders);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
163
  static inline void ss_del(struct msg_sender *mss)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  {
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
165
  	if (mss->list.next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
  		list_del(&mss->list);
  }
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
168
  static void ss_wakeup(struct msg_queue *msq,
d0d6a2a95   Davidlohr Bueso   ipc/msg: make ss_...
169
  		      struct wake_q_head *wake_q, bool kill)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
171
  	struct msg_sender *mss, *t;
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
172
173
  	struct task_struct *stop_tsk = NULL;
  	struct list_head *h = &msq->q_senders;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174

41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
175
  	list_for_each_entry_safe(mss, t, h, list) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
176
177
  		if (kill)
  			mss->list.next = NULL;
ed27f9122   Davidlohr Bueso   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   Davidlohr Bueso   ipc/msg: batch qu...
200
  		wake_q_add(wake_q, mss->tsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
  	}
  }
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
203
204
  static void expunge_all(struct msg_queue *msq, int res,
  			struct wake_q_head *wake_q)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  {
41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
206
  	struct msg_receiver *msr, *t;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
207

41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
208
  	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
209
210
  		wake_q_add(wake_q, msr->r_tsk);
  		WRITE_ONCE(msr->r_msg, ERR_PTR(res));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	}
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
213
214
215
  
  /*
   * freeque() wakes up waiters on the sender and receiver waiting queue,
f4566f048   Nadia Derbey   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   Linus Torvalds   Linux-2.6.12-rc2
218
   *
d9a605e40   Davidlohr Bueso   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   Linus Torvalds   Linux-2.6.12-rc2
221
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
222
  static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  {
41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
224
  	struct msg_msg *msg, *t;
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
225
  	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
194a6b5b9   Waiman Long   sched/wake_q: Ren...
226
  	DEFINE_WAKE_Q(wake_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227

ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
228
  	expunge_all(msq, -EIDRM, &wake_q);
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
229
  	ss_wakeup(msq, &wake_q, true);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
230
  	msg_rmid(ns, msq);
4718787d1   Davidlohr Bueso   ipc,msg: drop msg...
231
  	ipc_unlock_object(&msq->q_perm);
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
232
  	wake_up_q(&wake_q);
4718787d1   Davidlohr Bueso   ipc,msg: drop msg...
233
  	rcu_read_unlock();
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
234

41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
235
  	list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
3ac88a41f   Kirill Korotaev   virtualization of...
236
  		atomic_dec(&ns->msg_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
  		free_msg(msg);
  	}
3ac88a41f   Kirill Korotaev   virtualization of...
239
  	atomic_sub(msq->q_cbytes, &ns->msg_bytes);
dba4cdd39   Manfred Spraul   ipc: merge ipc_rc...
240
  	ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
242
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
243
   * Called with msg_ids.rwsem and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
244
   */
03f02c765   Nadia Derbey   Storing ipcs into...
245
  static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
246
  {
03f02c765   Nadia Derbey   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   Nadia Derbey   ipc: unify the sy...
250
  }
e48fbb699   Heiko Carstens   [CVE-2009-0029] S...
251
  SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  {
1e7869373   Kirill Korotaev   [PATCH] IPC names...
253
  	struct ipc_namespace *ns;
eb66ec44f   Mathias Krause   ipc: constify ipc...
254
255
256
257
  	static const struct ipc_ops msg_ops = {
  		.getnew = newque,
  		.associate = msg_security,
  	};
7748dbfaa   Nadia Derbey   ipc: unify the sy...
258
  	struct ipc_params msg_params;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
259
260
  
  	ns = current->nsproxy->ipc_ns;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
261

7748dbfaa   Nadia Derbey   ipc: unify the sy...
262
263
  	msg_params.key = key;
  	msg_params.flg = msgflg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
264

7748dbfaa   Nadia Derbey   ipc: unify the sy...
265
  	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
267
268
  static inline unsigned long
  copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  {
239521f31   Manfred Spraul   ipc: whitespace c...
270
  	switch (version) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	case IPC_64:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
272
  		return copy_to_user(buf, in, sizeof(*in));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  	case IPC_OLD:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
274
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  		struct msqid_ds out;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
276
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   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   Alexey Dobriyan   kernel-wide: repl...
283
284
  		if (in->msg_cbytes > USHRT_MAX)
  			out.msg_cbytes	= USHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
  		else
  			out.msg_cbytes	= in->msg_cbytes;
  		out.msg_lcbytes		= in->msg_cbytes;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
288
289
  		if (in->msg_qnum > USHRT_MAX)
  			out.msg_qnum	= USHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
  		else
  			out.msg_qnum	= in->msg_qnum;
4be929be3   Alexey Dobriyan   kernel-wide: repl...
292
293
  		if (in->msg_qbytes > USHRT_MAX)
  			out.msg_qbytes	= USHRT_MAX;
1da177e4c   Linus Torvalds   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   Ingo Molnar   [PATCH] ipc/msg.c...
300
301
  		return copy_to_user(buf, &out, sizeof(out));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
  	default:
  		return -EINVAL;
  	}
  }
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
306
  static inline unsigned long
016d7132f   Pierre Peiffer   IPC: get rid of t...
307
  copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  {
239521f31   Manfred Spraul   ipc: whitespace c...
309
  	switch (version) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
311
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  	case IPC_OLD:
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
315
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  		struct msqid_ds tbuf_old;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
317
  		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  			return -EFAULT;
239521f31   Manfred Spraul   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   Linus Torvalds   Linux-2.6.12-rc2
322

5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
323
  		if (tbuf_old.msg_qbytes == 0)
016d7132f   Pierre Peiffer   IPC: get rid of t...
324
  			out->msg_qbytes	= tbuf_old.msg_lqbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  		else
016d7132f   Pierre Peiffer   IPC: get rid of t...
326
  			out->msg_qbytes	= tbuf_old.msg_qbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  
  		return 0;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
329
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
  	default:
  		return -EINVAL;
  	}
  }
a0d092fc2   Pierre Peiffer   IPC/message queue...
334
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
335
   * This function handles some msgctl commands which require the rwsem
a0d092fc2   Pierre Peiffer   IPC/message queue...
336
   * to be held in write mode.
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
337
   * NOTE: no locks must be held, the rwsem is taken inside this function.
a0d092fc2   Pierre Peiffer   IPC/message queue...
338
339
   */
  static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
156d9ed12   Al Viro   msgctl(): split t...
340
  			struct msqid64_ds *msqid64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	struct kern_ipc_perm *ipcp;
a0d092fc2   Pierre Peiffer   IPC/message queue...
343
344
  	struct msg_queue *msq;
  	int err;
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
345
  	down_write(&msg_ids(ns).rwsem);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
346
  	rcu_read_lock();
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
347
  	ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
156d9ed12   Al Viro   msgctl(): split t...
348
  				      &msqid64->msg_perm, msqid64->msg_qbytes);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
349
350
  	if (IS_ERR(ipcp)) {
  		err = PTR_ERR(ipcp);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
351
352
  		goto out_unlock1;
  	}
a0d092fc2   Pierre Peiffer   IPC/message queue...
353

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
354
  	msq = container_of(ipcp, struct msg_queue, q_perm);
a0d092fc2   Pierre Peiffer   IPC/message queue...
355
356
357
  
  	err = security_msg_queue_msgctl(msq, cmd);
  	if (err)
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
358
  		goto out_unlock1;
a0d092fc2   Pierre Peiffer   IPC/message queue...
359
360
361
  
  	switch (cmd) {
  	case IPC_RMID:
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
362
  		ipc_lock_object(&msq->q_perm);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
363
  		/* freeque unlocks the ipc object and rcu */
a0d092fc2   Pierre Peiffer   IPC/message queue...
364
365
366
  		freeque(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
367
  	{
194a6b5b9   Waiman Long   sched/wake_q: Ren...
368
  		DEFINE_WAKE_Q(wake_q);
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
369

156d9ed12   Al Viro   msgctl(): split t...
370
  		if (msqid64->msg_qbytes > ns->msg_ctlmnb &&
a0d092fc2   Pierre Peiffer   IPC/message queue...
371
372
  		    !capable(CAP_SYS_RESOURCE)) {
  			err = -EPERM;
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
373
  			goto out_unlock1;
a0d092fc2   Pierre Peiffer   IPC/message queue...
374
  		}
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
375
  		ipc_lock_object(&msq->q_perm);
156d9ed12   Al Viro   msgctl(): split t...
376
  		err = ipc_update_perm(&msqid64->msg_perm, ipcp);
1efdb69b0   Eric W. Biederman   userns: Convert i...
377
  		if (err)
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
378
  			goto out_unlock0;
1efdb69b0   Eric W. Biederman   userns: Convert i...
379

156d9ed12   Al Viro   msgctl(): split t...
380
  		msq->q_qbytes = msqid64->msg_qbytes;
a0d092fc2   Pierre Peiffer   IPC/message queue...
381

50578ea97   Deepa Dinamani   ipc: msg: Make ms...
382
  		msq->q_ctime = ktime_get_real_seconds();
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
383
384
  		/*
  		 * Sleeping receivers might be excluded by
a0d092fc2   Pierre Peiffer   IPC/message queue...
385
386
  		 * stricter permissions.
  		 */
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
387
  		expunge_all(msq, -EAGAIN, &wake_q);
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
388
389
  		/*
  		 * Sleeping senders might be able to send
a0d092fc2   Pierre Peiffer   IPC/message queue...
390
391
  		 * due to a larger queue size.
  		 */
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
392
  		ss_wakeup(msq, &wake_q, false);
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
393
394
395
396
397
  		ipc_unlock_object(&msq->q_perm);
  		wake_up_q(&wake_q);
  
  		goto out_unlock1;
  	}
a0d092fc2   Pierre Peiffer   IPC/message queue...
398
399
  	default:
  		err = -EINVAL;
15724ecb7   Davidlohr Bueso   ipc,msg: shorten ...
400
  		goto out_unlock1;
a0d092fc2   Pierre Peiffer   IPC/message queue...
401
  	}
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
402
403
404
405
406
  
  out_unlock0:
  	ipc_unlock_object(&msq->q_perm);
  out_unlock1:
  	rcu_read_unlock();
a0d092fc2   Pierre Peiffer   IPC/message queue...
407
  out_up:
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
408
  	up_write(&msg_ids(ns).rwsem);
a0d092fc2   Pierre Peiffer   IPC/message queue...
409
410
  	return err;
  }
156d9ed12   Al Viro   msgctl(): split t...
411
412
  static int msgctl_info(struct ipc_namespace *ns, int msqid,
  			 int cmd, struct msginfo *msginfo)
a0d092fc2   Pierre Peiffer   IPC/message queue...
413
  {
2cafed30f   Davidlohr Bueso   ipc,msg: introduc...
414
  	int err;
156d9ed12   Al Viro   msgctl(): split t...
415
  	int max_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416

156d9ed12   Al Viro   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   Linus Torvalds   Linux-2.6.12-rc2
441
  	}
156d9ed12   Al Viro   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   Davidlohr Bueso   ipc,msg: introduc...
446

156d9ed12   Al Viro   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   Davidlohr Bueso   ipc,msg: make msg...
453

156d9ed12   Al Viro   msgctl(): split t...
454
  	memset(p, 0, sizeof(*p));
ac0ba20ea   Davidlohr Bueso   ipc,msg: make msg...
455

156d9ed12   Al Viro   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   Linus Torvalds   Linux-2.6.12-rc2
461
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  		}
156d9ed12   Al Viro   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   Linus Torvalds   Linux-2.6.12-rc2
468
  			goto out_unlock;
156d9ed12   Al Viro   msgctl(): split t...
469
470
471
  		}
  		success_return = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

156d9ed12   Al Viro   msgctl(): split t...
473
474
475
  	err = -EACCES;
  	if (ipcperms(ns, &msq->q_perm, S_IRUGO))
  		goto out_unlock;
ac0ba20ea   Davidlohr Bueso   ipc,msg: make msg...
476

156d9ed12   Al Viro   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   Davidlohr Bueso   ipc,msg: introduc...
491

156d9ed12   Al Viro   msgctl(): split t...
492
  	return success_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  out_unlock:
ac0ba20ea   Davidlohr Bueso   ipc,msg: make msg...
495
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  	return err;
  }
2cafed30f   Davidlohr Bueso   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   Al Viro   msgctl(): split t...
502
503
  	struct msqid64_ds msqid64;
  	int err;
2cafed30f   Davidlohr Bueso   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   Al Viro   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   Davidlohr Bueso   ipc,msg: introduc...
522
523
  	case MSG_STAT:	/* msqid is an index rather than a msg queue id */
  	case IPC_STAT:
156d9ed12   Al Viro   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   Davidlohr Bueso   ipc,msg: introduc...
530
  	case IPC_SET:
156d9ed12   Al Viro   msgctl(): split t...
531
532
533
  		if (copy_msqid_from_user(&msqid64, buf, version))
  			return -EFAULT;
  		/* fallthru */
2cafed30f   Davidlohr Bueso   ipc,msg: introduc...
534
  	case IPC_RMID:
156d9ed12   Al Viro   msgctl(): split t...
535
  		return msgctl_down(ns, msqid, cmd, &msqid64);
2cafed30f   Davidlohr Bueso   ipc,msg: introduc...
536
537
538
539
  	default:
  		return  -EINVAL;
  	}
  }
469391684   Al Viro   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   Al Viro   ipc: make use of ...
564
  		if (get_compat_ipc64_perm(&out->msg_perm, &p->msg_perm))
469391684   Al Viro   msgctl(): move co...
565
  			return -EFAULT;
469391684   Al Viro   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   Al Viro   ipc: make use of ...
570
  		if (get_compat_ipc_perm(&out->msg_perm, &p->msg_perm))
469391684   Al Viro   msgctl(): move co...
571
  			return -EFAULT;
469391684   Al Viro   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   Al Viro   ipc: make use of ...
584
  		to_compat_ipc64_perm(&v.msg_perm, &in->msg_perm);
469391684   Al Viro   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   Al Viro   ipc: make use of ...
597
  		to_compat_ipc_perm(&v.msg_perm, &in->msg_perm);
469391684   Al Viro   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   Ingo Molnar   [PATCH] ipc/msg.c...
652
  static int testmsg(struct msg_msg *msg, long type, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  {
46c0a8ca3   Paul McQuade   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   Linus Torvalds   Linux-2.6.12-rc2
664
  			return 1;
46c0a8ca3   Paul McQuade   ipc, kernel: clea...
665
666
667
668
669
  		break;
  	case SEARCH_NOTEQUAL:
  		if (msg->m_type != type)
  			return 1;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
  	}
  	return 0;
  }
ee51636ca   Sebastian Andrzej Siewior   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   Linus Torvalds   Linux-2.6.12-rc2
675
  {
41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
676
  	struct msg_receiver *msr, *t;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
677

41239fe82   Nikola Pajkovsky   ipc/msg.c: use li...
678
  	list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
5a06a363e   Ingo Molnar   [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   Linus Torvalds   Linux-2.6.12-rc2
682
  			list_del(&msr->r_list);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
683
  			if (msr->r_maxsize < msg->m_ts) {
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
684
685
  				wake_q_add(wake_q, msr->r_tsk);
  				WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
  			} else {
b488893a3   Pavel Emelyanov   pid namespaces: c...
687
  				msq->q_lrpid = task_pid_vnr(msr->r_tsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  				msq->q_rtime = get_seconds();
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
689

ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
690
691
  				wake_q_add(wake_q, msr->r_tsk);
  				WRITE_ONCE(msr->r_msg, msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
  				return 1;
  			}
  		}
  	}
ffa571daf   Davidlohr Bueso   ipc,msg: document...
696

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
  	return 0;
  }
9b1404c24   Al Viro   msgrcv(2), msgsnd...
699
  static long do_msgsnd(int msqid, long mtype, void __user *mtext,
651971cb7   suzuki   [PATCH] Fix the s...
700
  		size_t msgsz, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
  {
  	struct msg_queue *msq;
  	struct msg_msg *msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  	int err;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
705
  	struct ipc_namespace *ns;
194a6b5b9   Waiman Long   sched/wake_q: Ren...
706
  	DEFINE_WAKE_Q(wake_q);
1e7869373   Kirill Korotaev   [PATCH] IPC names...
707
708
  
  	ns = current->nsproxy->ipc_ns;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
709

1e7869373   Kirill Korotaev   [PATCH] IPC names...
710
  	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  	if (mtype < 1)
  		return -EINVAL;
651971cb7   suzuki   [PATCH] Fix the s...
714
  	msg = load_msg(mtext, msgsz);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
715
  	if (IS_ERR(msg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
  		return PTR_ERR(msg);
  
  	msg->m_type = mtype;
  	msg->m_ts = msgsz;
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
720
721
  	rcu_read_lock();
  	msq = msq_obtain_object_check(ns, msqid);
023a53557   Nadia Derbey   ipc: integrate ip...
722
723
  	if (IS_ERR(msq)) {
  		err = PTR_ERR(msq);
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
724
  		goto out_unlock1;
023a53557   Nadia Derbey   ipc: integrate ip...
725
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726

bebcb928c   Manfred Spraul   ipc/msg.c: Fix lo...
727
  	ipc_lock_object(&msq->q_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
  	for (;;) {
  		struct msg_sender s;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
730
  		err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
731
  		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
bebcb928c   Manfred Spraul   ipc/msg.c: Fix lo...
732
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733

4271b05a2   Davidlohr Bueso   ipc,msg: prevent ...
734
  		/* raced with RMID? */
0f3d2b013   Rafael Aquini   ipc: introduce ip...
735
  		if (!ipc_valid_object(&msq->q_perm)) {
4271b05a2   Davidlohr Bueso   ipc,msg: prevent ...
736
737
738
  			err = -EIDRM;
  			goto out_unlock0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
  		err = security_msg_queue_msgsnd(msq, msg, msgflg);
  		if (err)
bebcb928c   Manfred Spraul   ipc/msg.c: Fix lo...
741
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742

ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
743
  		if (msg_fits_inqueue(msq, msgsz))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
  
  		/* queue full, wait: */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
747
748
  		if (msgflg & IPC_NOWAIT) {
  			err = -EAGAIN;
bebcb928c   Manfred Spraul   ipc/msg.c: Fix lo...
749
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  		}
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
751

ffa571daf   Davidlohr Bueso   ipc,msg: document...
752
  		/* enqueue the sender and prepare to block */
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
753
  		ss_add(msq, &s, msgsz);
6062a8dc0   Rik van Riel   ipc,sem: fine gra...
754

dba4cdd39   Manfred Spraul   ipc: merge ipc_rc...
755
  		if (!ipc_rcu_getref(&msq->q_perm)) {
6062a8dc0   Rik van Riel   ipc,sem: fine gra...
756
  			err = -EIDRM;
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
757
  			goto out_unlock0;
6062a8dc0   Rik van Riel   ipc,sem: fine gra...
758
  		}
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
759
760
  		ipc_unlock_object(&msq->q_perm);
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  		schedule();
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
762
763
  		rcu_read_lock();
  		ipc_lock_object(&msq->q_perm);
dba4cdd39   Manfred Spraul   ipc: merge ipc_rc...
764
  		ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
0f3d2b013   Rafael Aquini   ipc: introduce ip...
765
766
  		/* raced with RMID? */
  		if (!ipc_valid_object(&msq->q_perm)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  			err = -EIDRM;
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
768
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  		}
  		ss_del(&s);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
771

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  		if (signal_pending(current)) {
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
773
  			err = -ERESTARTNOHAND;
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
774
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  		}
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
776

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  	}
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
778

b488893a3   Pavel Emelyanov   pid namespaces: c...
779
  	msq->q_lspid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	msq->q_stime = get_seconds();
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
781
  	if (!pipelined_send(msq, msg, &wake_q)) {
25985edce   Lucas De Marchi   Fix common misspe...
782
  		/* no one is waiting for this message, enqueue it */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
783
  		list_add_tail(&msg->m_list, &msq->q_messages);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
  		msq->q_cbytes += msgsz;
  		msq->q_qnum++;
3ac88a41f   Kirill Korotaev   virtualization of...
786
787
  		atomic_add(msgsz, &ns->msg_bytes);
  		atomic_inc(&ns->msg_hdrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  	}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
789

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
  	err = 0;
  	msg = NULL;
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
792
793
  out_unlock0:
  	ipc_unlock_object(&msq->q_perm);
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
794
  	wake_up_q(&wake_q);
3dd1f784e   Davidlohr Bueso   ipc,msg: shorten ...
795
796
  out_unlock1:
  	rcu_read_unlock();
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
797
  	if (msg != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
  		free_msg(msg);
  	return err;
  }
e48fbb699   Heiko Carstens   [CVE-2009-0029] S...
801
802
  SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
  		int, msgflg)
651971cb7   suzuki   [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   Al Viro   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   Ingo Molnar   [PATCH] ipc/msg.c...
828
  static inline int convert_mode(long *msgtyp, int msgflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  {
8ac6ed585   Peter Hurley   ipc: implement MS...
830
831
  	if (msgflg & MSG_COPY)
  		return SEARCH_NUMBER;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
832
  	/*
1da177e4c   Linus Torvalds   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   Ingo Molnar   [PATCH] ipc/msg.c...
836
  	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  	 */
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
838
  	if (*msgtyp == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  		return SEARCH_ANY;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
840
  	if (*msgtyp < 0) {
999898355   Jiri Slaby   ipc: msg, make ms...
841
842
843
844
  		if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */
  			*msgtyp = LONG_MAX;
  		else
  			*msgtyp = -*msgtyp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
  		return SEARCH_LESSEQUAL;
  	}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
847
  	if (msgflg & MSG_EXCEPT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
  		return SEARCH_NOTEQUAL;
  	return SEARCH_EQUAL;
  }
f9dd87f47   Stanislav Kinsbursky   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   Stanislav Kinsbursky   ipc: introduce me...
864
  #ifdef CONFIG_CHECKPOINT_RESTORE
3fcfe7865   Stanislav Kinsbursky   ipc: add more com...
865
866
867
868
  /*
   * This function creates new kernel message structure, large enough to store
   * bufsz message bytes.
   */
8ac6ed585   Peter Hurley   ipc: implement MS...
869
  static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
870
871
  {
  	struct msg_msg *copy;
4a674f34b   Stanislav Kinsbursky   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   Stanislav Kinsbursky   ipc: simplify fre...
880
  static inline void free_copy(struct msg_msg *copy)
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
881
  {
85398aa8d   Stanislav Kinsbursky   ipc: simplify fre...
882
  	if (copy)
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
883
884
885
  		free_msg(copy);
  }
  #else
8ac6ed585   Peter Hurley   ipc: implement MS...
886
  static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
b30efe277   Stanislav Kinsbursky   ipc: convert prep...
887
888
889
  {
  	return ERR_PTR(-ENOSYS);
  }
85398aa8d   Stanislav Kinsbursky   ipc: simplify fre...
890
891
892
  static inline void free_copy(struct msg_msg *copy)
  {
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
893
  #endif
daaf74cf0   Peter Hurley   ipc: refactor msg...
894
895
  static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
  {
368ae537e   Svenning Sørensen   IPC: bugfix for m...
896
  	struct msg_msg *msg, *found = NULL;
daaf74cf0   Peter Hurley   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   Svenning Sørensen   IPC: bugfix for m...
905
  				found = msg;
daaf74cf0   Peter Hurley   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   Svenning Sørensen   IPC: bugfix for m...
914
  	return found ?: ERR_PTR(-EAGAIN);
daaf74cf0   Peter Hurley   ipc: refactor msg...
915
  }
9b1404c24   Al Viro   msgrcv(2), msgsnd...
916
  static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
917
  	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  	int mode;
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
920
  	struct msg_queue *msq;
1e7869373   Kirill Korotaev   [PATCH] IPC names...
921
  	struct ipc_namespace *ns;
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
922
  	struct msg_msg *msg, *copy = NULL;
194a6b5b9   Waiman Long   sched/wake_q: Ren...
923
  	DEFINE_WAKE_Q(wake_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924

88b9e456b   Peter Hurley   ipc: don't alloca...
925
  	ns = current->nsproxy->ipc_ns;
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
926
  	if (msqid < 0 || (long) bufsz < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  		return -EINVAL;
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
928

4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
929
  	if (msgflg & MSG_COPY) {
4f87dac38   Michael Kerrisk   ipc: Fix 2 bugs i...
930
931
  		if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
  			return -EINVAL;
8ac6ed585   Peter Hurley   ipc: implement MS...
932
  		copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
933
934
935
  		if (IS_ERR(copy))
  			return PTR_ERR(copy);
  	}
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
936
  	mode = convert_mode(&msgtyp, msgflg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937

41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
938
939
  	rcu_read_lock();
  	msq = msq_obtain_object_check(ns, msqid);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
940
  	if (IS_ERR(msq)) {
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
941
  		rcu_read_unlock();
85398aa8d   Stanislav Kinsbursky   ipc: simplify fre...
942
  		free_copy(copy);
023a53557   Nadia Derbey   ipc: integrate ip...
943
  		return PTR_ERR(msq);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
944
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
947
  
  	for (;;) {
  		struct msg_receiver msr_d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
  
  		msg = ERR_PTR(-EACCES);
b0e77598f   Serge E. Hallyn   userns: user name...
950
  		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
951
  			goto out_unlock1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
953
  		ipc_lock_object(&msq->q_perm);
4271b05a2   Davidlohr Bueso   ipc,msg: prevent ...
954
955
  
  		/* raced with RMID? */
0f3d2b013   Rafael Aquini   ipc: introduce ip...
956
  		if (!ipc_valid_object(&msq->q_perm)) {
4271b05a2   Davidlohr Bueso   ipc,msg: prevent ...
957
958
959
  			msg = ERR_PTR(-EIDRM);
  			goto out_unlock0;
  		}
daaf74cf0   Peter Hurley   ipc: refactor msg...
960
  		msg = find_msg(msq, &msgtyp, mode);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
961
962
963
964
965
  		if (!IS_ERR(msg)) {
  			/*
  			 * Found a suitable message.
  			 * Unlink it from the queue.
  			 */
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
966
  			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  				msg = ERR_PTR(-E2BIG);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
968
  				goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  			}
3fcfe7865   Stanislav Kinsbursky   ipc: add more com...
970
971
972
973
  			/*
  			 * If we are copying, then do not unlink message and do
  			 * not update queue parameters.
  			 */
852028af8   Peter Hurley   ipc: remove msg h...
974
975
  			if (msgflg & MSG_COPY) {
  				msg = copy_msg(msg, copy);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
976
  				goto out_unlock0;
852028af8   Peter Hurley   ipc: remove msg h...
977
  			}
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
978

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
  			list_del(&msg->m_list);
  			msq->q_qnum--;
  			msq->q_rtime = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
982
  			msq->q_lrpid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  			msq->q_cbytes -= msg->m_ts;
3ac88a41f   Kirill Korotaev   virtualization of...
984
985
  			atomic_sub(msg->m_ts, &ns->msg_bytes);
  			atomic_dec(&ns->msg_hdrs);
ed27f9122   Davidlohr Bueso   ipc/msg: avoid wa...
986
  			ss_wakeup(msq, &wake_q, false);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
987
988
  
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  		}
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
990

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
  		/* No message waiting. Wait for a message */
  		if (msgflg & IPC_NOWAIT) {
  			msg = ERR_PTR(-ENOMSG);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
994
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  		}
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
996

5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
997
  		list_add_tail(&msr_d.r_list, &msq->q_receivers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
  		msr_d.r_tsk = current;
  		msr_d.r_msgtype = msgtyp;
  		msr_d.r_mode = mode;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
1001
  		if (msgflg & MSG_NOERROR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
  			msr_d.r_maxsize = INT_MAX;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
1003
  		else
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
1004
  			msr_d.r_maxsize = bufsz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
  		msr_d.r_msg = ERR_PTR(-EAGAIN);
f75a2f358   Davidlohr Bueso   ipc,msg: use curr...
1006
  		__set_current_state(TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007

41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1008
1009
  		ipc_unlock_object(&msq->q_perm);
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  		schedule();
ee51636ca   Sebastian Andrzej Siewior   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   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
  		 */
  		rcu_read_lock();
ee51636ca   Sebastian Andrzej Siewior   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   Davidlohr Bueso   ipc,msg: provide ...
1027
  		 *
ee51636ca   Sebastian Andrzej Siewior   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   Linus Torvalds   Linux-2.6.12-rc2
1030
  		 */
ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
1031
  		msg = READ_ONCE(msr_d.r_msg);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1032
1033
  		if (msg != ERR_PTR(-EAGAIN))
  			goto out_unlock1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034

ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
1035
1036
1037
1038
  		 /*
  		  * ... or see -EAGAIN, acquire the lock to check the message
  		  * again.
  		  */
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1039
  		ipc_lock_object(&msq->q_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040

ee51636ca   Sebastian Andrzej Siewior   ipc/msg: implemen...
1041
  		msg = msr_d.r_msg;
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
1042
  		if (msg != ERR_PTR(-EAGAIN))
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1043
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
  
  		list_del(&msr_d.r_list);
  		if (signal_pending(current)) {
  			msg = ERR_PTR(-ERESTARTNOHAND);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1048
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
  		}
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1050
1051
  
  		ipc_unlock_object(&msq->q_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  	}
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1053
1054
1055
  
  out_unlock0:
  	ipc_unlock_object(&msq->q_perm);
e3658538b   Davidlohr Bueso   ipc/msg: batch qu...
1056
  	wake_up_q(&wake_q);
41a0d523d   Davidlohr Bueso   ipc,msg: shorten ...
1057
1058
  out_unlock1:
  	rcu_read_unlock();
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
1059
  	if (IS_ERR(msg)) {
85398aa8d   Stanislav Kinsbursky   ipc: simplify fre...
1060
  		free_copy(copy);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
1061
  		return PTR_ERR(msg);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
1062
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063

f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
1064
  	bufsz = msg_handler(buf, msg, bufsz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
  	free_msg(msg);
5a06a363e   Ingo Molnar   [PATCH] ipc/msg.c...
1066

f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
1067
  	return bufsz;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
  }
e48fbb699   Heiko Carstens   [CVE-2009-0029] S...
1069
1070
  SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
  		long, msgtyp, int, msgflg)
651971cb7   suzuki   [PATCH] Fix the s...
1071
  {
f9dd87f47   Stanislav Kinsbursky   ipc: message queu...
1072
  	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
651971cb7   suzuki   [PATCH] Fix the s...
1073
  }
9b1404c24   Al Viro   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   Davidlohr Bueso   ipc,msg: move som...
1096

0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
1097
  int msg_init_ns(struct ipc_namespace *ns)
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1098
1099
1100
  {
  	ns->msg_ctlmax = MSGMAX;
  	ns->msg_ctlmnb = MSGMNB;
0050ee059   Manfred Spraul   ipc/msg: increase...
1101
  	ns->msg_ctlmni = MSGMNI;
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1102
1103
1104
  
  	atomic_set(&ns->msg_bytes, 0);
  	atomic_set(&ns->msg_hdrs, 0);
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
1105
  	return ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
3440a6bd1   Davidlohr Bueso   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   Guillaume Knispel   ipc: optimize sem...
1113
  	rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht);
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1114
1115
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1117
  static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
  {
1efdb69b0   Eric W. Biederman   userns: Convert i...
1119
  	struct user_namespace *user_ns = seq_user_ns(s);
ade9f91b3   Kees Cook   ipc: add missing ...
1120
1121
  	struct kern_ipc_perm *ipcp = it;
  	struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1122

7f032d6ef   Joe Perches   ipc: remove use o...
1123
  	seq_printf(s,
50578ea97   Deepa Dinamani   ipc: msg: Make ms...
1124
1125
  		   "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10llu %10llu %10llu
  ",
7f032d6ef   Joe Perches   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   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
  }
  #endif
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1144

0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
1145
  int __init msg_init(void)
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1146
  {
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
1147
  	const int err = msg_init_ns(&init_ipc_ns);
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1148

3440a6bd1   Davidlohr Bueso   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   Guillaume Knispel   ipc: optimize sem...
1153
  	return err;
3440a6bd1   Davidlohr Bueso   ipc,msg: move som...
1154
  }