diff options
Diffstat (limited to 'ipc/msg.c')
-rw-r--r-- | ipc/msg.c | 46 |
1 files changed, 32 insertions, 14 deletions
@@ -253,8 +253,14 @@ static void expunge_all(struct msg_queue *msq, int res) | |||
253 | struct msg_receiver *msr, *t; | 253 | struct msg_receiver *msr, *t; |
254 | 254 | ||
255 | list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { | 255 | list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { |
256 | msr->r_msg = NULL; | 256 | msr->r_msg = NULL; /* initialize expunge ordering */ |
257 | wake_up_process(msr->r_tsk); | 257 | wake_up_process(msr->r_tsk); |
258 | /* | ||
259 | * Ensure that the wakeup is visible before setting r_msg as | ||
260 | * the receiving end depends on it: either spinning on a nil, | ||
261 | * or dealing with -EAGAIN cases. See lockless receive part 1 | ||
262 | * and 2 in do_msgrcv(). | ||
263 | */ | ||
258 | smp_mb(); | 264 | smp_mb(); |
259 | msr->r_msg = ERR_PTR(res); | 265 | msr->r_msg = ERR_PTR(res); |
260 | } | 266 | } |
@@ -318,7 +324,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) | |||
318 | static inline unsigned long | 324 | static inline unsigned long |
319 | copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) | 325 | copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) |
320 | { | 326 | { |
321 | switch(version) { | 327 | switch (version) { |
322 | case IPC_64: | 328 | case IPC_64: |
323 | return copy_to_user(buf, in, sizeof(*in)); | 329 | return copy_to_user(buf, in, sizeof(*in)); |
324 | case IPC_OLD: | 330 | case IPC_OLD: |
@@ -363,7 +369,7 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) | |||
363 | static inline unsigned long | 369 | static inline unsigned long |
364 | copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) | 370 | copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) |
365 | { | 371 | { |
366 | switch(version) { | 372 | switch (version) { |
367 | case IPC_64: | 373 | case IPC_64: |
368 | if (copy_from_user(out, buf, sizeof(*out))) | 374 | if (copy_from_user(out, buf, sizeof(*out))) |
369 | return -EFAULT; | 375 | return -EFAULT; |
@@ -375,9 +381,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) | |||
375 | if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) | 381 | if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) |
376 | return -EFAULT; | 382 | return -EFAULT; |
377 | 383 | ||
378 | out->msg_perm.uid = tbuf_old.msg_perm.uid; | 384 | out->msg_perm.uid = tbuf_old.msg_perm.uid; |
379 | out->msg_perm.gid = tbuf_old.msg_perm.gid; | 385 | out->msg_perm.gid = tbuf_old.msg_perm.gid; |
380 | out->msg_perm.mode = tbuf_old.msg_perm.mode; | 386 | out->msg_perm.mode = tbuf_old.msg_perm.mode; |
381 | 387 | ||
382 | if (tbuf_old.msg_qbytes == 0) | 388 | if (tbuf_old.msg_qbytes == 0) |
383 | out->msg_qbytes = tbuf_old.msg_lqbytes; | 389 | out->msg_qbytes = tbuf_old.msg_lqbytes; |
@@ -606,13 +612,13 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) | |||
606 | 612 | ||
607 | static int testmsg(struct msg_msg *msg, long type, int mode) | 613 | static int testmsg(struct msg_msg *msg, long type, int mode) |
608 | { | 614 | { |
609 | switch(mode) | 615 | switch (mode) |
610 | { | 616 | { |
611 | case SEARCH_ANY: | 617 | case SEARCH_ANY: |
612 | case SEARCH_NUMBER: | 618 | case SEARCH_NUMBER: |
613 | return 1; | 619 | return 1; |
614 | case SEARCH_LESSEQUAL: | 620 | case SEARCH_LESSEQUAL: |
615 | if (msg->m_type <=type) | 621 | if (msg->m_type <= type) |
616 | return 1; | 622 | return 1; |
617 | break; | 623 | break; |
618 | case SEARCH_EQUAL: | 624 | case SEARCH_EQUAL: |
@@ -638,15 +644,22 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) | |||
638 | 644 | ||
639 | list_del(&msr->r_list); | 645 | list_del(&msr->r_list); |
640 | if (msr->r_maxsize < msg->m_ts) { | 646 | if (msr->r_maxsize < msg->m_ts) { |
647 | /* initialize pipelined send ordering */ | ||
641 | msr->r_msg = NULL; | 648 | msr->r_msg = NULL; |
642 | wake_up_process(msr->r_tsk); | 649 | wake_up_process(msr->r_tsk); |
643 | smp_mb(); | 650 | smp_mb(); /* see barrier comment below */ |
644 | msr->r_msg = ERR_PTR(-E2BIG); | 651 | msr->r_msg = ERR_PTR(-E2BIG); |
645 | } else { | 652 | } else { |
646 | msr->r_msg = NULL; | 653 | msr->r_msg = NULL; |
647 | msq->q_lrpid = task_pid_vnr(msr->r_tsk); | 654 | msq->q_lrpid = task_pid_vnr(msr->r_tsk); |
648 | msq->q_rtime = get_seconds(); | 655 | msq->q_rtime = get_seconds(); |
649 | wake_up_process(msr->r_tsk); | 656 | wake_up_process(msr->r_tsk); |
657 | /* | ||
658 | * Ensure that the wakeup is visible before | ||
659 | * setting r_msg, as the receiving end depends | ||
660 | * on it. See lockless receive part 1 and 2 in | ||
661 | * do_msgrcv(). | ||
662 | */ | ||
650 | smp_mb(); | 663 | smp_mb(); |
651 | msr->r_msg = msg; | 664 | msr->r_msg = msg; |
652 | 665 | ||
@@ -654,6 +667,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg) | |||
654 | } | 667 | } |
655 | } | 668 | } |
656 | } | 669 | } |
670 | |||
657 | return 0; | 671 | return 0; |
658 | } | 672 | } |
659 | 673 | ||
@@ -696,7 +710,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
696 | goto out_unlock0; | 710 | goto out_unlock0; |
697 | 711 | ||
698 | /* raced with RMID? */ | 712 | /* raced with RMID? */ |
699 | if (msq->q_perm.deleted) { | 713 | if (!ipc_valid_object(&msq->q_perm)) { |
700 | err = -EIDRM; | 714 | err = -EIDRM; |
701 | goto out_unlock0; | 715 | goto out_unlock0; |
702 | } | 716 | } |
@@ -716,6 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
716 | goto out_unlock0; | 730 | goto out_unlock0; |
717 | } | 731 | } |
718 | 732 | ||
733 | /* enqueue the sender and prepare to block */ | ||
719 | ss_add(msq, &s); | 734 | ss_add(msq, &s); |
720 | 735 | ||
721 | if (!ipc_rcu_getref(msq)) { | 736 | if (!ipc_rcu_getref(msq)) { |
@@ -731,7 +746,8 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext, | |||
731 | ipc_lock_object(&msq->q_perm); | 746 | ipc_lock_object(&msq->q_perm); |
732 | 747 | ||
733 | ipc_rcu_putref(msq, ipc_rcu_free); | 748 | ipc_rcu_putref(msq, ipc_rcu_free); |
734 | if (msq->q_perm.deleted) { | 749 | /* raced with RMID? */ |
750 | if (!ipc_valid_object(&msq->q_perm)) { | ||
735 | err = -EIDRM; | 751 | err = -EIDRM; |
736 | goto out_unlock0; | 752 | goto out_unlock0; |
737 | } | 753 | } |
@@ -885,6 +901,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
885 | return -EINVAL; | 901 | return -EINVAL; |
886 | 902 | ||
887 | if (msgflg & MSG_COPY) { | 903 | if (msgflg & MSG_COPY) { |
904 | if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT)) | ||
905 | return -EINVAL; | ||
888 | copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); | 906 | copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); |
889 | if (IS_ERR(copy)) | 907 | if (IS_ERR(copy)) |
890 | return PTR_ERR(copy); | 908 | return PTR_ERR(copy); |
@@ -909,7 +927,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
909 | ipc_lock_object(&msq->q_perm); | 927 | ipc_lock_object(&msq->q_perm); |
910 | 928 | ||
911 | /* raced with RMID? */ | 929 | /* raced with RMID? */ |
912 | if (msq->q_perm.deleted) { | 930 | if (!ipc_valid_object(&msq->q_perm)) { |
913 | msg = ERR_PTR(-EIDRM); | 931 | msg = ERR_PTR(-EIDRM); |
914 | goto out_unlock0; | 932 | goto out_unlock0; |
915 | } | 933 | } |
@@ -983,7 +1001,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
983 | * wake_up_process(). There is a race with exit(), see | 1001 | * wake_up_process(). There is a race with exit(), see |
984 | * ipc/mqueue.c for the details. | 1002 | * ipc/mqueue.c for the details. |
985 | */ | 1003 | */ |
986 | msg = (struct msg_msg*)msr_d.r_msg; | 1004 | msg = (struct msg_msg *)msr_d.r_msg; |
987 | while (msg == NULL) { | 1005 | while (msg == NULL) { |
988 | cpu_relax(); | 1006 | cpu_relax(); |
989 | msg = (struct msg_msg *)msr_d.r_msg; | 1007 | msg = (struct msg_msg *)msr_d.r_msg; |
@@ -1004,7 +1022,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
1004 | /* Lockless receive, part 4: | 1022 | /* Lockless receive, part 4: |
1005 | * Repeat test after acquiring the spinlock. | 1023 | * Repeat test after acquiring the spinlock. |
1006 | */ | 1024 | */ |
1007 | msg = (struct msg_msg*)msr_d.r_msg; | 1025 | msg = (struct msg_msg *)msr_d.r_msg; |
1008 | if (msg != ERR_PTR(-EAGAIN)) | 1026 | if (msg != ERR_PTR(-EAGAIN)) |
1009 | goto out_unlock0; | 1027 | goto out_unlock0; |
1010 | 1028 | ||