diff options
author | Davidlohr Bueso <davidlohr.bueso@hp.com> | 2013-07-08 19:01:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-10-18 10:45:46 -0400 |
commit | ac9bc6e396285ab732dd869c3edb353662134022 (patch) | |
tree | 182b0be2e0238d96e02c8669e372c254d6ea81a1 /ipc/msg.c | |
parent | 115d40dbef93b70e6f32732b0fdd5903c1f7fce4 (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.c | 24 |
1 files changed, 17 insertions, 7 deletions
@@ -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 | } |
451 | out_unlock: | 458 | |
452 | msg_unlock(msq); | 459 | out_unlock0: |
460 | ipc_unlock_object(&msq->q_perm); | ||
461 | out_unlock1: | ||
462 | rcu_read_unlock(); | ||
453 | out_up: | 463 | out_up: |
454 | up_write(&msg_ids(ns).rw_mutex); | 464 | up_write(&msg_ids(ns).rw_mutex); |
455 | return err; | 465 | return err; |