diff options
Diffstat (limited to 'ipc/msg.c')
| -rw-r--r-- | ipc/msg.c | 37 |
1 files changed, 24 insertions, 13 deletions
| @@ -698,10 +698,11 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 698 | msg->m_type = mtype; | 698 | msg->m_type = mtype; |
| 699 | msg->m_ts = msgsz; | 699 | msg->m_ts = msgsz; |
| 700 | 700 | ||
| 701 | msq = msg_lock_check(ns, msqid); | 701 | rcu_read_lock(); |
| 702 | msq = msq_obtain_object_check(ns, msqid); | ||
| 702 | if (IS_ERR(msq)) { | 703 | if (IS_ERR(msq)) { |
| 703 | err = PTR_ERR(msq); | 704 | err = PTR_ERR(msq); |
| 704 | goto out_free; | 705 | goto out_unlock1; |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 707 | for (;;) { | 708 | for (;;) { |
| @@ -709,11 +710,11 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 709 | 710 | ||
| 710 | err = -EACCES; | 711 | err = -EACCES; |
| 711 | if (ipcperms(ns, &msq->q_perm, S_IWUGO)) | 712 | if (ipcperms(ns, &msq->q_perm, S_IWUGO)) |
| 712 | goto out_unlock_free; | 713 | goto out_unlock1; |
| 713 | 714 | ||
| 714 | err = security_msg_queue_msgsnd(msq, msg, msgflg); | 715 | err = security_msg_queue_msgsnd(msq, msg, msgflg); |
| 715 | if (err) | 716 | if (err) |
| 716 | goto out_unlock_free; | 717 | goto out_unlock1; |
| 717 | 718 | ||
| 718 | if (msgsz + msq->q_cbytes <= msq->q_qbytes && | 719 | if (msgsz + msq->q_cbytes <= msq->q_qbytes && |
| 719 | 1 + msq->q_qnum <= msq->q_qbytes) { | 720 | 1 + msq->q_qnum <= msq->q_qbytes) { |
| @@ -723,32 +724,41 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 723 | /* queue full, wait: */ | 724 | /* queue full, wait: */ |
| 724 | if (msgflg & IPC_NOWAIT) { | 725 | if (msgflg & IPC_NOWAIT) { |
| 725 | err = -EAGAIN; | 726 | err = -EAGAIN; |
| 726 | goto out_unlock_free; | 727 | goto out_unlock1; |
| 727 | } | 728 | } |
| 729 | |||
| 730 | ipc_lock_object(&msq->q_perm); | ||
| 728 | ss_add(msq, &s); | 731 | ss_add(msq, &s); |
| 729 | 732 | ||
| 730 | if (!ipc_rcu_getref(msq)) { | 733 | if (!ipc_rcu_getref(msq)) { |
| 731 | err = -EIDRM; | 734 | err = -EIDRM; |
| 732 | goto out_unlock_free; | 735 | goto out_unlock0; |
| 733 | } | 736 | } |
| 734 | 737 | ||
| 735 | msg_unlock(msq); | 738 | ipc_unlock_object(&msq->q_perm); |
| 739 | rcu_read_unlock(); | ||
| 736 | schedule(); | 740 | schedule(); |
| 737 | 741 | ||
| 738 | ipc_lock_by_ptr(&msq->q_perm); | 742 | rcu_read_lock(); |
| 743 | ipc_lock_object(&msq->q_perm); | ||
| 744 | |||
| 739 | ipc_rcu_putref(msq); | 745 | ipc_rcu_putref(msq); |
| 740 | if (msq->q_perm.deleted) { | 746 | if (msq->q_perm.deleted) { |
| 741 | err = -EIDRM; | 747 | err = -EIDRM; |
| 742 | goto out_unlock_free; | 748 | goto out_unlock0; |
| 743 | } | 749 | } |
| 750 | |||
| 744 | ss_del(&s); | 751 | ss_del(&s); |
| 745 | 752 | ||
| 746 | if (signal_pending(current)) { | 753 | if (signal_pending(current)) { |
| 747 | err = -ERESTARTNOHAND; | 754 | err = -ERESTARTNOHAND; |
| 748 | goto out_unlock_free; | 755 | goto out_unlock0; |
| 749 | } | 756 | } |
| 757 | |||
| 758 | ipc_unlock_object(&msq->q_perm); | ||
| 750 | } | 759 | } |
| 751 | 760 | ||
| 761 | ipc_lock_object(&msq->q_perm); | ||
| 752 | msq->q_lspid = task_tgid_vnr(current); | 762 | msq->q_lspid = task_tgid_vnr(current); |
| 753 | msq->q_stime = get_seconds(); | 763 | msq->q_stime = get_seconds(); |
| 754 | 764 | ||
| @@ -764,9 +774,10 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
| 764 | err = 0; | 774 | err = 0; |
| 765 | msg = NULL; | 775 | msg = NULL; |
| 766 | 776 | ||
| 767 | out_unlock_free: | 777 | out_unlock0: |
| 768 | msg_unlock(msq); | 778 | ipc_unlock_object(&msq->q_perm); |
| 769 | out_free: | 779 | out_unlock1: |
| 780 | rcu_read_unlock(); | ||
| 770 | if (msg != NULL) | 781 | if (msg != NULL) |
| 771 | free_msg(msg); | 782 | free_msg(msg); |
| 772 | return err; | 783 | return err; |
