aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2013-11-22 18:57:08 -0500
committerEric Paris <eparis@redhat.com>2013-11-22 18:57:54 -0500
commitfc582aef7dcc27a7120cf232c1e76c569c7b6eab (patch)
tree7d275dd4ceab6067b91e9a25a5f6338b425fbccd /ipc/msg.c
parent9175c9d2aed528800175ef81c90569d00d23f9be (diff)
parent5e01dc7b26d9f24f39abace5da98ccbd6a5ceb52 (diff)
Merge tag 'v3.12'
Linux 3.12 Conflicts: fs/exec.c
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 9f29d9e89bac..558aa91186b6 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -70,8 +70,6 @@ struct msg_sender {
70 70
71#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) 71#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
72 72
73#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
74
75static void freeque(struct ipc_namespace *, struct kern_ipc_perm *); 73static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
76static int newque(struct ipc_namespace *, struct ipc_params *); 74static int newque(struct ipc_namespace *, struct ipc_params *);
77#ifdef CONFIG_PROC_FS 75#ifdef CONFIG_PROC_FS
@@ -167,12 +165,21 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
167 ipc_rmid(&msg_ids(ns), &s->q_perm); 165 ipc_rmid(&msg_ids(ns), &s->q_perm);
168} 166}
169 167
168static void msg_rcu_free(struct rcu_head *head)
169{
170 struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
171 struct msg_queue *msq = ipc_rcu_to_struct(p);
172
173 security_msg_queue_free(msq);
174 ipc_rcu_free(head);
175}
176
170/** 177/**
171 * newque - Create a new msg queue 178 * newque - Create a new msg queue
172 * @ns: namespace 179 * @ns: namespace
173 * @params: ptr to the structure that contains the key and msgflg 180 * @params: ptr to the structure that contains the key and msgflg
174 * 181 *
175 * Called with msg_ids.rw_mutex held (writer) 182 * Called with msg_ids.rwsem held (writer)
176 */ 183 */
177static int newque(struct ipc_namespace *ns, struct ipc_params *params) 184static int newque(struct ipc_namespace *ns, struct ipc_params *params)
178{ 185{
@@ -191,15 +198,14 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
191 msq->q_perm.security = NULL; 198 msq->q_perm.security = NULL;
192 retval = security_msg_queue_alloc(msq); 199 retval = security_msg_queue_alloc(msq);
193 if (retval) { 200 if (retval) {
194 ipc_rcu_putref(msq); 201 ipc_rcu_putref(msq, ipc_rcu_free);
195 return retval; 202 return retval;
196 } 203 }
197 204
198 /* ipc_addid() locks msq upon success. */ 205 /* ipc_addid() locks msq upon success. */
199 id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); 206 id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
200 if (id < 0) { 207 if (id < 0) {
201 security_msg_queue_free(msq); 208 ipc_rcu_putref(msq, msg_rcu_free);
202 ipc_rcu_putref(msq);
203 return id; 209 return id;
204 } 210 }
205 211
@@ -259,8 +265,8 @@ static void expunge_all(struct msg_queue *msq, int res)
259 * removes the message queue from message queue ID IDR, and cleans up all the 265 * removes the message queue from message queue ID IDR, and cleans up all the
260 * messages associated with this queue. 266 * messages associated with this queue.
261 * 267 *
262 * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held 268 * msg_ids.rwsem (writer) and the spinlock for this message queue are held
263 * before freeque() is called. msg_ids.rw_mutex remains locked on exit. 269 * before freeque() is called. msg_ids.rwsem remains locked on exit.
264 */ 270 */
265static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) 271static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
266{ 272{
@@ -270,19 +276,19 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
270 expunge_all(msq, -EIDRM); 276 expunge_all(msq, -EIDRM);
271 ss_wakeup(&msq->q_senders, 1); 277 ss_wakeup(&msq->q_senders, 1);
272 msg_rmid(ns, msq); 278 msg_rmid(ns, msq);
273 msg_unlock(msq); 279 ipc_unlock_object(&msq->q_perm);
280 rcu_read_unlock();
274 281
275 list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) { 282 list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
276 atomic_dec(&ns->msg_hdrs); 283 atomic_dec(&ns->msg_hdrs);
277 free_msg(msg); 284 free_msg(msg);
278 } 285 }
279 atomic_sub(msq->q_cbytes, &ns->msg_bytes); 286 atomic_sub(msq->q_cbytes, &ns->msg_bytes);
280 security_msg_queue_free(msq); 287 ipc_rcu_putref(msq, msg_rcu_free);
281 ipc_rcu_putref(msq);
282} 288}
283 289
284/* 290/*
285 * Called with msg_ids.rw_mutex and ipcp locked. 291 * Called with msg_ids.rwsem and ipcp locked.
286 */ 292 */
287static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) 293static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
288{ 294{
@@ -386,9 +392,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
386} 392}
387 393
388/* 394/*
389 * This function handles some msgctl commands which require the rw_mutex 395 * This function handles some msgctl commands which require the rwsem
390 * to be held in write mode. 396 * to be held in write mode.
391 * NOTE: no locks must be held, the rw_mutex is taken inside this function. 397 * NOTE: no locks must be held, the rwsem is taken inside this function.
392 */ 398 */
393static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd, 399static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
394 struct msqid_ds __user *buf, int version) 400 struct msqid_ds __user *buf, int version)
@@ -403,7 +409,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
403 return -EFAULT; 409 return -EFAULT;
404 } 410 }
405 411
406 down_write(&msg_ids(ns).rw_mutex); 412 down_write(&msg_ids(ns).rwsem);
407 rcu_read_lock(); 413 rcu_read_lock();
408 414
409 ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd, 415 ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
@@ -459,7 +465,7 @@ out_unlock0:
459out_unlock1: 465out_unlock1:
460 rcu_read_unlock(); 466 rcu_read_unlock();
461out_up: 467out_up:
462 up_write(&msg_ids(ns).rw_mutex); 468 up_write(&msg_ids(ns).rwsem);
463 return err; 469 return err;
464} 470}
465 471
@@ -494,7 +500,7 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
494 msginfo.msgmnb = ns->msg_ctlmnb; 500 msginfo.msgmnb = ns->msg_ctlmnb;
495 msginfo.msgssz = MSGSSZ; 501 msginfo.msgssz = MSGSSZ;
496 msginfo.msgseg = MSGSEG; 502 msginfo.msgseg = MSGSEG;
497 down_read(&msg_ids(ns).rw_mutex); 503 down_read(&msg_ids(ns).rwsem);
498 if (cmd == MSG_INFO) { 504 if (cmd == MSG_INFO) {
499 msginfo.msgpool = msg_ids(ns).in_use; 505 msginfo.msgpool = msg_ids(ns).in_use;
500 msginfo.msgmap = atomic_read(&ns->msg_hdrs); 506 msginfo.msgmap = atomic_read(&ns->msg_hdrs);
@@ -505,7 +511,7 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
505 msginfo.msgtql = MSGTQL; 511 msginfo.msgtql = MSGTQL;
506 } 512 }
507 max_id = ipc_get_maxid(&msg_ids(ns)); 513 max_id = ipc_get_maxid(&msg_ids(ns));
508 up_read(&msg_ids(ns).rw_mutex); 514 up_read(&msg_ids(ns).rwsem);
509 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) 515 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
510 return -EFAULT; 516 return -EFAULT;
511 return (max_id < 0) ? 0 : max_id; 517 return (max_id < 0) ? 0 : max_id;
@@ -680,16 +686,24 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
680 goto out_unlock1; 686 goto out_unlock1;
681 } 687 }
682 688
689 ipc_lock_object(&msq->q_perm);
690
683 for (;;) { 691 for (;;) {
684 struct msg_sender s; 692 struct msg_sender s;
685 693
686 err = -EACCES; 694 err = -EACCES;
687 if (ipcperms(ns, &msq->q_perm, S_IWUGO)) 695 if (ipcperms(ns, &msq->q_perm, S_IWUGO))
688 goto out_unlock1; 696 goto out_unlock0;
697
698 /* raced with RMID? */
699 if (msq->q_perm.deleted) {
700 err = -EIDRM;
701 goto out_unlock0;
702 }
689 703
690 err = security_msg_queue_msgsnd(msq, msg, msgflg); 704 err = security_msg_queue_msgsnd(msq, msg, msgflg);
691 if (err) 705 if (err)
692 goto out_unlock1; 706 goto out_unlock0;
693 707
694 if (msgsz + msq->q_cbytes <= msq->q_qbytes && 708 if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
695 1 + msq->q_qnum <= msq->q_qbytes) { 709 1 + msq->q_qnum <= msq->q_qbytes) {
@@ -699,10 +713,9 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
699 /* queue full, wait: */ 713 /* queue full, wait: */
700 if (msgflg & IPC_NOWAIT) { 714 if (msgflg & IPC_NOWAIT) {
701 err = -EAGAIN; 715 err = -EAGAIN;
702 goto out_unlock1; 716 goto out_unlock0;
703 } 717 }
704 718
705 ipc_lock_object(&msq->q_perm);
706 ss_add(msq, &s); 719 ss_add(msq, &s);
707 720
708 if (!ipc_rcu_getref(msq)) { 721 if (!ipc_rcu_getref(msq)) {
@@ -717,7 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
717 rcu_read_lock(); 730 rcu_read_lock();
718 ipc_lock_object(&msq->q_perm); 731 ipc_lock_object(&msq->q_perm);
719 732
720 ipc_rcu_putref(msq); 733 ipc_rcu_putref(msq, ipc_rcu_free);
721 if (msq->q_perm.deleted) { 734 if (msq->q_perm.deleted) {
722 err = -EIDRM; 735 err = -EIDRM;
723 goto out_unlock0; 736 goto out_unlock0;
@@ -730,10 +743,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
730 goto out_unlock0; 743 goto out_unlock0;
731 } 744 }
732 745
733 ipc_unlock_object(&msq->q_perm);
734 } 746 }
735
736 ipc_lock_object(&msq->q_perm);
737 msq->q_lspid = task_tgid_vnr(current); 747 msq->q_lspid = task_tgid_vnr(current);
738 msq->q_stime = get_seconds(); 748 msq->q_stime = get_seconds();
739 749
@@ -897,6 +907,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
897 goto out_unlock1; 907 goto out_unlock1;
898 908
899 ipc_lock_object(&msq->q_perm); 909 ipc_lock_object(&msq->q_perm);
910
911 /* raced with RMID? */
912 if (msq->q_perm.deleted) {
913 msg = ERR_PTR(-EIDRM);
914 goto out_unlock0;
915 }
916
900 msg = find_msg(msq, &msgtyp, mode); 917 msg = find_msg(msq, &msgtyp, mode);
901 if (!IS_ERR(msg)) { 918 if (!IS_ERR(msg)) {
902 /* 919 /*