hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/ipc/msg.c
....@@ -61,6 +61,16 @@
6161 struct list_head q_senders;
6262 } __randomize_layout;
6363
64
+/*
65
+ * MSG_BARRIER Locking:
66
+ *
67
+ * Similar to the optimization used in ipc/mqueue.c, one syscall return path
68
+ * does not acquire any locks when it sees that a message exists in
69
+ * msg_receiver.r_msg. Therefore r_msg is set using smp_store_release()
70
+ * and accessed using READ_ONCE()+smp_acquire__after_ctrl_dep(). In addition,
71
+ * wake_q_add_safe() is used. See ipc/mqueue.c for more details
72
+ */
73
+
6474 /* one msg_receiver structure for each sleeping receiver */
6575 struct msg_receiver {
6676 struct list_head r_list;
....@@ -137,7 +147,7 @@
137147 key_t key = params->key;
138148 int msgflg = params->flg;
139149
140
- msq = kvmalloc(sizeof(*msq), GFP_KERNEL);
150
+ msq = kvmalloc(sizeof(*msq), GFP_KERNEL_ACCOUNT);
141151 if (unlikely(!msq))
142152 return -ENOMEM;
143153
....@@ -184,6 +194,10 @@
184194 {
185195 mss->tsk = current;
186196 mss->msgsz = msgsz;
197
+ /*
198
+ * No memory barrier required: we did ipc_lock_object(),
199
+ * and the waker obtains that lock before calling wake_q_add().
200
+ */
187201 __set_current_state(TASK_INTERRUPTIBLE);
188202 list_add_tail(&mss->list, &msq->q_senders);
189203 }
....@@ -237,8 +251,13 @@
237251 struct msg_receiver *msr, *t;
238252
239253 list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
240
- wake_q_add(wake_q, msr->r_tsk);
241
- WRITE_ONCE(msr->r_msg, ERR_PTR(res));
254
+ struct task_struct *r_tsk;
255
+
256
+ r_tsk = get_task_struct(msr->r_tsk);
257
+
258
+ /* see MSG_BARRIER for purpose/pairing */
259
+ smp_store_release(&msr->r_msg, ERR_PTR(res));
260
+ wake_q_add_safe(wake_q, r_tsk);
242261 }
243262 }
244263
....@@ -251,6 +270,8 @@
251270 * before freeque() is called. msg_ids.rwsem remains locked on exit.
252271 */
253272 static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
273
+ __releases(RCU)
274
+ __releases(&msq->q_perm)
254275 {
255276 struct msg_msg *msg, *t;
256277 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
....@@ -567,9 +588,8 @@
567588 return err;
568589 }
569590
570
-long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
591
+static long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf, int version)
571592 {
572
- int version;
573593 struct ipc_namespace *ns;
574594 struct msqid64_ds msqid64;
575595 int err;
....@@ -577,7 +597,6 @@
577597 if (msqid < 0 || cmd < 0)
578598 return -EINVAL;
579599
580
- version = ipc_parse_version(&cmd);
581600 ns = current->nsproxy->ipc_ns;
582601
583602 switch (cmd) {
....@@ -614,8 +633,22 @@
614633
615634 SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
616635 {
617
- return ksys_msgctl(msqid, cmd, buf);
636
+ return ksys_msgctl(msqid, cmd, buf, IPC_64);
618637 }
638
+
639
+#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
640
+long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
641
+{
642
+ int version = ipc_parse_version(&cmd);
643
+
644
+ return ksys_msgctl(msqid, cmd, buf, version);
645
+}
646
+
647
+SYSCALL_DEFINE3(old_msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
648
+{
649
+ return ksys_old_msgctl(msqid, cmd, buf);
650
+}
651
+#endif
619652
620653 #ifdef CONFIG_COMPAT
621654
....@@ -623,9 +656,9 @@
623656 struct compat_ipc_perm msg_perm;
624657 compat_uptr_t msg_first;
625658 compat_uptr_t msg_last;
626
- compat_time_t msg_stime;
627
- compat_time_t msg_rtime;
628
- compat_time_t msg_ctime;
659
+ old_time32_t msg_stime;
660
+ old_time32_t msg_rtime;
661
+ old_time32_t msg_ctime;
629662 compat_ulong_t msg_lcbytes;
630663 compat_ulong_t msg_lqbytes;
631664 unsigned short msg_cbytes;
....@@ -690,12 +723,11 @@
690723 }
691724 }
692725
693
-long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr)
726
+static long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr, int version)
694727 {
695728 struct ipc_namespace *ns;
696729 int err;
697730 struct msqid64_ds msqid64;
698
- int version = compat_ipc_parse_version(&cmd);
699731
700732 ns = current->nsproxy->ipc_ns;
701733
....@@ -735,8 +767,22 @@
735767
736768 COMPAT_SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, void __user *, uptr)
737769 {
738
- return compat_ksys_msgctl(msqid, cmd, uptr);
770
+ return compat_ksys_msgctl(msqid, cmd, uptr, IPC_64);
739771 }
772
+
773
+#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
774
+long compat_ksys_old_msgctl(int msqid, int cmd, void __user *uptr)
775
+{
776
+ int version = compat_ipc_parse_version(&cmd);
777
+
778
+ return compat_ksys_msgctl(msqid, cmd, uptr, version);
779
+}
780
+
781
+COMPAT_SYSCALL_DEFINE3(old_msgctl, int, msqid, int, cmd, void __user *, uptr)
782
+{
783
+ return compat_ksys_old_msgctl(msqid, cmd, uptr);
784
+}
785
+#endif
740786 #endif
741787
742788 static int testmsg(struct msg_msg *msg, long type, int mode)
....@@ -774,13 +820,17 @@
774820 list_del(&msr->r_list);
775821 if (msr->r_maxsize < msg->m_ts) {
776822 wake_q_add(wake_q, msr->r_tsk);
777
- WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
823
+
824
+ /* See expunge_all regarding memory barrier */
825
+ smp_store_release(&msr->r_msg, ERR_PTR(-E2BIG));
778826 } else {
779827 ipc_update_pid(&msq->q_lrpid, task_pid(msr->r_tsk));
780828 msq->q_rtime = ktime_get_real_seconds();
781829
782830 wake_q_add(wake_q, msr->r_tsk);
783
- WRITE_ONCE(msr->r_msg, msg);
831
+
832
+ /* See expunge_all regarding memory barrier */
833
+ smp_store_release(&msr->r_msg, msg);
784834 return 1;
785835 }
786836 }
....@@ -1130,7 +1180,11 @@
11301180 msr_d.r_maxsize = INT_MAX;
11311181 else
11321182 msr_d.r_maxsize = bufsz;
1133
- msr_d.r_msg = ERR_PTR(-EAGAIN);
1183
+
1184
+ /* memory barrier not require due to ipc_lock_object() */
1185
+ WRITE_ONCE(msr_d.r_msg, ERR_PTR(-EAGAIN));
1186
+
1187
+ /* memory barrier not required, we own ipc_lock_object() */
11341188 __set_current_state(TASK_INTERRUPTIBLE);
11351189
11361190 ipc_unlock_object(&msq->q_perm);
....@@ -1159,8 +1213,12 @@
11591213 * signal) it will either see the message and continue ...
11601214 */
11611215 msg = READ_ONCE(msr_d.r_msg);
1162
- if (msg != ERR_PTR(-EAGAIN))
1216
+ if (msg != ERR_PTR(-EAGAIN)) {
1217
+ /* see MSG_BARRIER for purpose/pairing */
1218
+ smp_acquire__after_ctrl_dep();
1219
+
11631220 goto out_unlock1;
1221
+ }
11641222
11651223 /*
11661224 * ... or see -EAGAIN, acquire the lock to check the message
....@@ -1168,7 +1226,7 @@
11681226 */
11691227 ipc_lock_object(&msq->q_perm);
11701228
1171
- msg = msr_d.r_msg;
1229
+ msg = READ_ONCE(msr_d.r_msg);
11721230 if (msg != ERR_PTR(-EAGAIN))
11731231 goto out_unlock0;
11741232