aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-07-08 19:01:12 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-18 10:45:46 -0400
commitac9bc6e396285ab732dd869c3edb353662134022 (patch)
tree182b0be2e0238d96e02c8669e372c254d6ea81a1 /ipc/msg.c
parent115d40dbef93b70e6f32732b0fdd5903c1f7fce4 (diff)
ipc: move locking out of ipcctl_pre_down_nolock
commit 7b4cc5d8411bd4e9d61d8714f53859740cf830c2 upstream. This function currently acquires both the rw_mutex and the rcu lock on successful lookups, leaving the callers to explicitly unlock them, creating another two level locking situation. Make the callers (including those that still use ipcctl_pre_down()) explicitly lock and unlock the rwsem and rcu lock. Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 56bff33457b2..6c1609d572cc 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -407,31 +407,38 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
407 return -EFAULT; 407 return -EFAULT;
408 } 408 }
409 409
410 down_write(&msg_ids(ns).rw_mutex);
411 rcu_read_lock();
412
410 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd, 413 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
411 &msqid64.msg_perm, msqid64.msg_qbytes); 414 &msqid64.msg_perm, msqid64.msg_qbytes);
412 if (IS_ERR(ipcp)) 415 if (IS_ERR(ipcp)) {
413 return PTR_ERR(ipcp); 416 err = PTR_ERR(ipcp);
417 /* the ipc lock is not held upon failure */
418 goto out_unlock1;
419 }
414 420
415 msq = container_of(ipcp, struct msg_queue, q_perm); 421 msq = container_of(ipcp, struct msg_queue, q_perm);
416 422
417 err = security_msg_queue_msgctl(msq, cmd); 423 err = security_msg_queue_msgctl(msq, cmd);
418 if (err) 424 if (err)
419 goto out_unlock; 425 goto out_unlock0;
420 426
421 switch (cmd) { 427 switch (cmd) {
422 case IPC_RMID: 428 case IPC_RMID:
429 /* freeque unlocks the ipc object and rcu */
423 freeque(ns, ipcp); 430 freeque(ns, ipcp);
424 goto out_up; 431 goto out_up;
425 case IPC_SET: 432 case IPC_SET:
426 if (msqid64.msg_qbytes > ns->msg_ctlmnb && 433 if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
427 !capable(CAP_SYS_RESOURCE)) { 434 !capable(CAP_SYS_RESOURCE)) {
428 err = -EPERM; 435 err = -EPERM;
429 goto out_unlock; 436 goto out_unlock0;
430 } 437 }
431 438
432 err = ipc_update_perm(&msqid64.msg_perm, ipcp); 439 err = ipc_update_perm(&msqid64.msg_perm, ipcp);
433 if (err) 440 if (err)
434 goto out_unlock; 441 goto out_unlock0;
435 442
436 msq->q_qbytes = msqid64.msg_qbytes; 443 msq->q_qbytes = msqid64.msg_qbytes;
437 444
@@ -448,8 +455,11 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
448 default: 455 default:
449 err = -EINVAL; 456 err = -EINVAL;
450 } 457 }
451out_unlock: 458
452 msg_unlock(msq); 459out_unlock0:
460 ipc_unlock_object(&msq->q_perm);
461out_unlock1:
462 rcu_read_unlock();
453out_up: 463out_up:
454 up_write(&msg_ids(ns).rw_mutex); 464 up_write(&msg_ids(ns).rw_mutex);
455 return err; 465 return err;