summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-06-27 21:32:36 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-07-04 13:13:49 -0400
commit0d0606060baefdb13d3d80dba1b4c816b0676e16 (patch)
tree1a2546ad468325ea3f6391b62e1c942cba37ef41
parentcc1a7c4bae28215d042fb9f00dcb77dd65abafdf (diff)
mqueue: move compat syscalls to native ones
... and stop messing with compat_alloc_user_space() and friends [braino fix from Colin King folded in] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--ipc/Makefile3
-rw-r--r--ipc/compat_mq.c138
-rw-r--r--ipc/mqueue.c349
3 files changed, 262 insertions, 228 deletions
diff --git a/ipc/Makefile b/ipc/Makefile
index 86c7300ecdf5..9c200e544434 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -5,8 +5,7 @@
5obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o 5obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
6obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o 6obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o
7obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o 7obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
8obj_mq-$(CONFIG_COMPAT) += compat_mq.o 8obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
9obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
10obj-$(CONFIG_IPC_NS) += namespace.o 9obj-$(CONFIG_IPC_NS) += namespace.o
11obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o 10obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
12 11
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
deleted file mode 100644
index ef6f91cc4490..000000000000
--- a/ipc/compat_mq.c
+++ /dev/null
@@ -1,138 +0,0 @@
1/*
2 * ipc/compat_mq.c
3 * 32 bit emulation for POSIX message queue system calls
4 *
5 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author: Arnd Bergmann <arnd@arndb.de>
7 */
8
9#include <linux/compat.h>
10#include <linux/fs.h>
11#include <linux/kernel.h>
12#include <linux/mqueue.h>
13#include <linux/syscalls.h>
14
15#include <linux/uaccess.h>
16
17struct compat_mq_attr {
18 compat_long_t mq_flags; /* message queue flags */
19 compat_long_t mq_maxmsg; /* maximum number of messages */
20 compat_long_t mq_msgsize; /* maximum message size */
21 compat_long_t mq_curmsgs; /* number of messages currently queued */
22 compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
23};
24
25static inline int get_compat_mq_attr(struct mq_attr *attr,
26 const struct compat_mq_attr __user *uattr)
27{
28 if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
29 return -EFAULT;
30
31 return __get_user(attr->mq_flags, &uattr->mq_flags)
32 | __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
33 | __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
34 | __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
35}
36
37static inline int put_compat_mq_attr(const struct mq_attr *attr,
38 struct compat_mq_attr __user *uattr)
39{
40 if (clear_user(uattr, sizeof *uattr))
41 return -EFAULT;
42
43 return __put_user(attr->mq_flags, &uattr->mq_flags)
44 | __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
45 | __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
46 | __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
47}
48
49COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
50 int, oflag, compat_mode_t, mode,
51 struct compat_mq_attr __user *, u_attr)
52{
53 void __user *p = NULL;
54 if (u_attr && oflag & O_CREAT) {
55 struct mq_attr attr;
56
57 memset(&attr, 0, sizeof(attr));
58
59 p = compat_alloc_user_space(sizeof(attr));
60 if (get_compat_mq_attr(&attr, u_attr) ||
61 copy_to_user(p, &attr, sizeof(attr)))
62 return -EFAULT;
63 }
64 return sys_mq_open(u_name, oflag, mode, p);
65}
66
67COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
68 const char __user *, u_msg_ptr,
69 compat_size_t, msg_len, unsigned int, msg_prio,
70 const struct compat_timespec __user *, u_abs_timeout)
71{
72 struct timespec __user *u_ts;
73
74 if (compat_convert_timespec(&u_ts, u_abs_timeout))
75 return -EFAULT;
76
77 return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
78 msg_prio, u_ts);
79}
80
81COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
82 char __user *, u_msg_ptr,
83 compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
84 const struct compat_timespec __user *, u_abs_timeout)
85{
86 struct timespec __user *u_ts;
87
88 if (compat_convert_timespec(&u_ts, u_abs_timeout))
89 return -EFAULT;
90
91 return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
92 u_msg_prio, u_ts);
93}
94
95COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
96 const struct compat_sigevent __user *, u_notification)
97{
98 struct sigevent __user *p = NULL;
99 if (u_notification) {
100 struct sigevent n;
101 p = compat_alloc_user_space(sizeof(*p));
102 if (get_compat_sigevent(&n, u_notification))
103 return -EFAULT;
104 if (n.sigev_notify == SIGEV_THREAD)
105 n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
106 if (copy_to_user(p, &n, sizeof(*p)))
107 return -EFAULT;
108 }
109 return sys_mq_notify(mqdes, p);
110}
111
112COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
113 const struct compat_mq_attr __user *, u_mqstat,
114 struct compat_mq_attr __user *, u_omqstat)
115{
116 struct mq_attr mqstat;
117 struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
118 long ret;
119
120 memset(&mqstat, 0, sizeof(mqstat));
121
122 if (u_mqstat) {
123 if (get_compat_mq_attr(&mqstat, u_mqstat) ||
124 copy_to_user(p, &mqstat, sizeof(mqstat)))
125 return -EFAULT;
126 }
127 ret = sys_mq_getsetattr(mqdes,
128 u_mqstat ? p : NULL,
129 u_omqstat ? p + 1 : NULL);
130 if (ret)
131 return ret;
132 if (u_omqstat) {
133 if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
134 put_compat_mq_attr(&mqstat, u_omqstat))
135 return -EFAULT;
136 }
137 return 0;
138}
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index e8d41ff57241..c9ff943f19ab 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -668,14 +668,12 @@ static void __do_notify(struct mqueue_inode_info *info)
668} 668}
669 669
670static int prepare_timeout(const struct timespec __user *u_abs_timeout, 670static int prepare_timeout(const struct timespec __user *u_abs_timeout,
671 ktime_t *expires, struct timespec *ts) 671 struct timespec *ts)
672{ 672{
673 if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec))) 673 if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
674 return -EFAULT; 674 return -EFAULT;
675 if (!timespec_valid(ts)) 675 if (!timespec_valid(ts))
676 return -EINVAL; 676 return -EINVAL;
677
678 *expires = timespec_to_ktime(*ts);
679 return 0; 677 return 0;
680} 678}
681 679
@@ -770,23 +768,19 @@ static struct file *do_open(struct path *path, int oflag)
770 return dentry_open(path, oflag, current_cred()); 768 return dentry_open(path, oflag, current_cred());
771} 769}
772 770
773SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, 771static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
774 struct mq_attr __user *, u_attr) 772 struct mq_attr *attr)
775{ 773{
776 struct path path; 774 struct path path;
777 struct file *filp; 775 struct file *filp;
778 struct filename *name; 776 struct filename *name;
779 struct mq_attr attr;
780 int fd, error; 777 int fd, error;
781 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 778 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
782 struct vfsmount *mnt = ipc_ns->mq_mnt; 779 struct vfsmount *mnt = ipc_ns->mq_mnt;
783 struct dentry *root = mnt->mnt_root; 780 struct dentry *root = mnt->mnt_root;
784 int ro; 781 int ro;
785 782
786 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 783 audit_mq_open(oflag, mode, attr);
787 return -EFAULT;
788
789 audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
790 784
791 if (IS_ERR(name = getname(u_name))) 785 if (IS_ERR(name = getname(u_name)))
792 return PTR_ERR(name); 786 return PTR_ERR(name);
@@ -819,9 +813,8 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
819 goto out; 813 goto out;
820 } 814 }
821 audit_inode_parent_hidden(name, root); 815 audit_inode_parent_hidden(name, root);
822 filp = do_create(ipc_ns, d_inode(root), 816 filp = do_create(ipc_ns, d_inode(root), &path,
823 &path, oflag, mode, 817 oflag, mode, attr);
824 u_attr ? &attr : NULL);
825 } 818 }
826 } else { 819 } else {
827 if (d_really_is_negative(path.dentry)) { 820 if (d_really_is_negative(path.dentry)) {
@@ -851,6 +844,16 @@ out_putname:
851 return fd; 844 return fd;
852} 845}
853 846
847SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
848 struct mq_attr __user *, u_attr)
849{
850 struct mq_attr attr;
851 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
852 return -EFAULT;
853
854 return do_mq_open(u_name, oflag, mode, u_attr ? &attr : NULL);
855}
856
854SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) 857SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
855{ 858{
856 int err; 859 int err;
@@ -957,9 +960,9 @@ static inline void pipelined_receive(struct wake_q_head *wake_q,
957 sender->state = STATE_READY; 960 sender->state = STATE_READY;
958} 961}
959 962
960SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, 963static int do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
961 size_t, msg_len, unsigned int, msg_prio, 964 size_t msg_len, unsigned int msg_prio,
962 const struct timespec __user *, u_abs_timeout) 965 struct timespec *ts)
963{ 966{
964 struct fd f; 967 struct fd f;
965 struct inode *inode; 968 struct inode *inode;
@@ -968,22 +971,19 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
968 struct msg_msg *msg_ptr; 971 struct msg_msg *msg_ptr;
969 struct mqueue_inode_info *info; 972 struct mqueue_inode_info *info;
970 ktime_t expires, *timeout = NULL; 973 ktime_t expires, *timeout = NULL;
971 struct timespec ts;
972 struct posix_msg_tree_node *new_leaf = NULL; 974 struct posix_msg_tree_node *new_leaf = NULL;
973 int ret = 0; 975 int ret = 0;
974 DEFINE_WAKE_Q(wake_q); 976 DEFINE_WAKE_Q(wake_q);
975 977
976 if (u_abs_timeout) {
977 int res = prepare_timeout(u_abs_timeout, &expires, &ts);
978 if (res)
979 return res;
980 timeout = &expires;
981 }
982
983 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) 978 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
984 return -EINVAL; 979 return -EINVAL;
985 980
986 audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL); 981 if (ts) {
982 expires = timespec_to_ktime(*ts);
983 timeout = &expires;
984 }
985
986 audit_mq_sendrecv(mqdes, msg_len, msg_prio, ts);
987 987
988 f = fdget(mqdes); 988 f = fdget(mqdes);
989 if (unlikely(!f.file)) { 989 if (unlikely(!f.file)) {
@@ -1078,9 +1078,9 @@ out:
1078 return ret; 1078 return ret;
1079} 1079}
1080 1080
1081SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, 1081static int do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
1082 size_t, msg_len, unsigned int __user *, u_msg_prio, 1082 size_t msg_len, unsigned int __user *u_msg_prio,
1083 const struct timespec __user *, u_abs_timeout) 1083 struct timespec *ts)
1084{ 1084{
1085 ssize_t ret; 1085 ssize_t ret;
1086 struct msg_msg *msg_ptr; 1086 struct msg_msg *msg_ptr;
@@ -1089,17 +1089,14 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
1089 struct mqueue_inode_info *info; 1089 struct mqueue_inode_info *info;
1090 struct ext_wait_queue wait; 1090 struct ext_wait_queue wait;
1091 ktime_t expires, *timeout = NULL; 1091 ktime_t expires, *timeout = NULL;
1092 struct timespec ts;
1093 struct posix_msg_tree_node *new_leaf = NULL; 1092 struct posix_msg_tree_node *new_leaf = NULL;
1094 1093
1095 if (u_abs_timeout) { 1094 if (ts) {
1096 int res = prepare_timeout(u_abs_timeout, &expires, &ts); 1095 expires = timespec_to_ktime(*ts);
1097 if (res)
1098 return res;
1099 timeout = &expires; 1096 timeout = &expires;
1100 } 1097 }
1101 1098
1102 audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL); 1099 audit_mq_sendrecv(mqdes, msg_len, 0, ts);
1103 1100
1104 f = fdget(mqdes); 1101 f = fdget(mqdes);
1105 if (unlikely(!f.file)) { 1102 if (unlikely(!f.file)) {
@@ -1183,42 +1180,62 @@ out:
1183 return ret; 1180 return ret;
1184} 1181}
1185 1182
1183SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
1184 size_t, msg_len, unsigned int, msg_prio,
1185 const struct timespec __user *, u_abs_timeout)
1186{
1187 struct timespec ts, *p = NULL;
1188 if (u_abs_timeout) {
1189 int res = prepare_timeout(u_abs_timeout, &ts);
1190 if (res)
1191 return res;
1192 p = &ts;
1193 }
1194 return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
1195}
1196
1197SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
1198 size_t, msg_len, unsigned int __user *, u_msg_prio,
1199 const struct timespec __user *, u_abs_timeout)
1200{
1201 struct timespec ts, *p = NULL;
1202 if (u_abs_timeout) {
1203 int res = prepare_timeout(u_abs_timeout, &ts);
1204 if (res)
1205 return res;
1206 p = &ts;
1207 }
1208 return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
1209}
1210
1186/* 1211/*
1187 * Notes: the case when user wants us to deregister (with NULL as pointer) 1212 * Notes: the case when user wants us to deregister (with NULL as pointer)
1188 * and he isn't currently owner of notification, will be silently discarded. 1213 * and he isn't currently owner of notification, will be silently discarded.
1189 * It isn't explicitly defined in the POSIX. 1214 * It isn't explicitly defined in the POSIX.
1190 */ 1215 */
1191SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, 1216static int do_mq_notify(mqd_t mqdes, const struct sigevent *notification)
1192 const struct sigevent __user *, u_notification)
1193{ 1217{
1194 int ret; 1218 int ret;
1195 struct fd f; 1219 struct fd f;
1196 struct sock *sock; 1220 struct sock *sock;
1197 struct inode *inode; 1221 struct inode *inode;
1198 struct sigevent notification;
1199 struct mqueue_inode_info *info; 1222 struct mqueue_inode_info *info;
1200 struct sk_buff *nc; 1223 struct sk_buff *nc;
1201 1224
1202 if (u_notification) { 1225 audit_mq_notify(mqdes, notification);
1203 if (copy_from_user(&notification, u_notification,
1204 sizeof(struct sigevent)))
1205 return -EFAULT;
1206 }
1207
1208 audit_mq_notify(mqdes, u_notification ? &notification : NULL);
1209 1226
1210 nc = NULL; 1227 nc = NULL;
1211 sock = NULL; 1228 sock = NULL;
1212 if (u_notification != NULL) { 1229 if (notification != NULL) {
1213 if (unlikely(notification.sigev_notify != SIGEV_NONE && 1230 if (unlikely(notification->sigev_notify != SIGEV_NONE &&
1214 notification.sigev_notify != SIGEV_SIGNAL && 1231 notification->sigev_notify != SIGEV_SIGNAL &&
1215 notification.sigev_notify != SIGEV_THREAD)) 1232 notification->sigev_notify != SIGEV_THREAD))
1216 return -EINVAL; 1233 return -EINVAL;
1217 if (notification.sigev_notify == SIGEV_SIGNAL && 1234 if (notification->sigev_notify == SIGEV_SIGNAL &&
1218 !valid_signal(notification.sigev_signo)) { 1235 !valid_signal(notification->sigev_signo)) {
1219 return -EINVAL; 1236 return -EINVAL;
1220 } 1237 }
1221 if (notification.sigev_notify == SIGEV_THREAD) { 1238 if (notification->sigev_notify == SIGEV_THREAD) {
1222 long timeo; 1239 long timeo;
1223 1240
1224 /* create the notify skb */ 1241 /* create the notify skb */
@@ -1228,7 +1245,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1228 goto out; 1245 goto out;
1229 } 1246 }
1230 if (copy_from_user(nc->data, 1247 if (copy_from_user(nc->data,
1231 notification.sigev_value.sival_ptr, 1248 notification->sigev_value.sival_ptr,
1232 NOTIFY_COOKIE_LEN)) { 1249 NOTIFY_COOKIE_LEN)) {
1233 ret = -EFAULT; 1250 ret = -EFAULT;
1234 goto out; 1251 goto out;
@@ -1238,7 +1255,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1238 skb_put(nc, NOTIFY_COOKIE_LEN); 1255 skb_put(nc, NOTIFY_COOKIE_LEN);
1239 /* and attach it to the socket */ 1256 /* and attach it to the socket */
1240retry: 1257retry:
1241 f = fdget(notification.sigev_signo); 1258 f = fdget(notification->sigev_signo);
1242 if (!f.file) { 1259 if (!f.file) {
1243 ret = -EBADF; 1260 ret = -EBADF;
1244 goto out; 1261 goto out;
@@ -1278,7 +1295,7 @@ retry:
1278 1295
1279 ret = 0; 1296 ret = 0;
1280 spin_lock(&info->lock); 1297 spin_lock(&info->lock);
1281 if (u_notification == NULL) { 1298 if (notification == NULL) {
1282 if (info->notify_owner == task_tgid(current)) { 1299 if (info->notify_owner == task_tgid(current)) {
1283 remove_notification(info); 1300 remove_notification(info);
1284 inode->i_atime = inode->i_ctime = current_time(inode); 1301 inode->i_atime = inode->i_ctime = current_time(inode);
@@ -1286,7 +1303,7 @@ retry:
1286 } else if (info->notify_owner != NULL) { 1303 } else if (info->notify_owner != NULL) {
1287 ret = -EBUSY; 1304 ret = -EBUSY;
1288 } else { 1305 } else {
1289 switch (notification.sigev_notify) { 1306 switch (notification->sigev_notify) {
1290 case SIGEV_NONE: 1307 case SIGEV_NONE:
1291 info->notify.sigev_notify = SIGEV_NONE; 1308 info->notify.sigev_notify = SIGEV_NONE;
1292 break; 1309 break;
@@ -1298,8 +1315,8 @@ retry:
1298 info->notify.sigev_notify = SIGEV_THREAD; 1315 info->notify.sigev_notify = SIGEV_THREAD;
1299 break; 1316 break;
1300 case SIGEV_SIGNAL: 1317 case SIGEV_SIGNAL:
1301 info->notify.sigev_signo = notification.sigev_signo; 1318 info->notify.sigev_signo = notification->sigev_signo;
1302 info->notify.sigev_value = notification.sigev_value; 1319 info->notify.sigev_value = notification->sigev_value;
1303 info->notify.sigev_notify = SIGEV_SIGNAL; 1320 info->notify.sigev_notify = SIGEV_SIGNAL;
1304 break; 1321 break;
1305 } 1322 }
@@ -1320,44 +1337,49 @@ out:
1320 return ret; 1337 return ret;
1321} 1338}
1322 1339
1323SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, 1340SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1324 const struct mq_attr __user *, u_mqstat, 1341 const struct sigevent __user *, u_notification)
1325 struct mq_attr __user *, u_omqstat) 1342{
1343 struct sigevent n, *p = NULL;
1344 if (u_notification) {
1345 if (copy_from_user(&n, u_notification, sizeof(struct sigevent)))
1346 return -EFAULT;
1347 p = &n;
1348 }
1349 return do_mq_notify(mqdes, p);
1350}
1351
1352static int do_mq_getsetattr(int mqdes, struct mq_attr *new, struct mq_attr *old)
1326{ 1353{
1327 int ret;
1328 struct mq_attr mqstat, omqstat;
1329 struct fd f; 1354 struct fd f;
1330 struct inode *inode; 1355 struct inode *inode;
1331 struct mqueue_inode_info *info; 1356 struct mqueue_inode_info *info;
1332 1357
1333 if (u_mqstat != NULL) { 1358 if (new && (new->mq_flags & (~O_NONBLOCK)))
1334 if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr))) 1359 return -EINVAL;
1335 return -EFAULT;
1336 if (mqstat.mq_flags & (~O_NONBLOCK))
1337 return -EINVAL;
1338 }
1339 1360
1340 f = fdget(mqdes); 1361 f = fdget(mqdes);
1341 if (!f.file) { 1362 if (!f.file)
1342 ret = -EBADF; 1363 return -EBADF;
1343 goto out;
1344 }
1345 1364
1346 inode = file_inode(f.file);
1347 if (unlikely(f.file->f_op != &mqueue_file_operations)) { 1365 if (unlikely(f.file->f_op != &mqueue_file_operations)) {
1348 ret = -EBADF; 1366 fdput(f);
1349 goto out_fput; 1367 return -EBADF;
1350 } 1368 }
1369
1370 inode = file_inode(f.file);
1351 info = MQUEUE_I(inode); 1371 info = MQUEUE_I(inode);
1352 1372
1353 spin_lock(&info->lock); 1373 spin_lock(&info->lock);
1354 1374
1355 omqstat = info->attr; 1375 if (old) {
1356 omqstat.mq_flags = f.file->f_flags & O_NONBLOCK; 1376 *old = info->attr;
1357 if (u_mqstat) { 1377 old->mq_flags = f.file->f_flags & O_NONBLOCK;
1358 audit_mq_getsetattr(mqdes, &mqstat); 1378 }
1379 if (new) {
1380 audit_mq_getsetattr(mqdes, new);
1359 spin_lock(&f.file->f_lock); 1381 spin_lock(&f.file->f_lock);
1360 if (mqstat.mq_flags & O_NONBLOCK) 1382 if (new->mq_flags & O_NONBLOCK)
1361 f.file->f_flags |= O_NONBLOCK; 1383 f.file->f_flags |= O_NONBLOCK;
1362 else 1384 else
1363 f.file->f_flags &= ~O_NONBLOCK; 1385 f.file->f_flags &= ~O_NONBLOCK;
@@ -1367,17 +1389,168 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
1367 } 1389 }
1368 1390
1369 spin_unlock(&info->lock); 1391 spin_unlock(&info->lock);
1392 fdput(f);
1393 return 0;
1394}
1370 1395
1371 ret = 0; 1396SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
1372 if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat, 1397 const struct mq_attr __user *, u_mqstat,
1373 sizeof(struct mq_attr))) 1398 struct mq_attr __user *, u_omqstat)
1374 ret = -EFAULT; 1399{
1400 int ret;
1401 struct mq_attr mqstat, omqstat;
1402 struct mq_attr *new = NULL, *old = NULL;
1375 1403
1376out_fput: 1404 if (u_mqstat) {
1377 fdput(f); 1405 new = &mqstat;
1378out: 1406 if (copy_from_user(new, u_mqstat, sizeof(struct mq_attr)))
1379 return ret; 1407 return -EFAULT;
1408 }
1409 if (u_omqstat)
1410 old = &omqstat;
1411
1412 ret = do_mq_getsetattr(mqdes, new, old);
1413 if (ret || !old)
1414 return ret;
1415
1416 if (copy_to_user(u_omqstat, old, sizeof(struct mq_attr)))
1417 return -EFAULT;
1418 return 0;
1419}
1420
1421#ifdef CONFIG_COMPAT
1422
1423struct compat_mq_attr {
1424 compat_long_t mq_flags; /* message queue flags */
1425 compat_long_t mq_maxmsg; /* maximum number of messages */
1426 compat_long_t mq_msgsize; /* maximum message size */
1427 compat_long_t mq_curmsgs; /* number of messages currently queued */
1428 compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
1429};
1430
1431static inline int get_compat_mq_attr(struct mq_attr *attr,
1432 const struct compat_mq_attr __user *uattr)
1433{
1434 struct compat_mq_attr v;
1435
1436 if (copy_from_user(&v, uattr, sizeof(*uattr)))
1437 return -EFAULT;
1438
1439 memset(attr, 0, sizeof(*attr));
1440 attr->mq_flags = v.mq_flags;
1441 attr->mq_maxmsg = v.mq_maxmsg;
1442 attr->mq_msgsize = v.mq_msgsize;
1443 attr->mq_curmsgs = v.mq_curmsgs;
1444 return 0;
1445}
1446
1447static inline int put_compat_mq_attr(const struct mq_attr *attr,
1448 struct compat_mq_attr __user *uattr)
1449{
1450 struct compat_mq_attr v;
1451
1452 memset(&v, 0, sizeof(v));
1453 v.mq_flags = attr->mq_flags;
1454 v.mq_maxmsg = attr->mq_maxmsg;
1455 v.mq_msgsize = attr->mq_msgsize;
1456 v.mq_curmsgs = attr->mq_curmsgs;
1457 if (copy_to_user(uattr, &v, sizeof(*uattr)))
1458 return -EFAULT;
1459 return 0;
1460}
1461
1462COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
1463 int, oflag, compat_mode_t, mode,
1464 struct compat_mq_attr __user *, u_attr)
1465{
1466 struct mq_attr attr, *p = NULL;
1467 if (u_attr && oflag & O_CREAT) {
1468 p = &attr;
1469 if (get_compat_mq_attr(&attr, u_attr))
1470 return -EFAULT;
1471 }
1472 return do_mq_open(u_name, oflag, mode, p);
1473}
1474
1475static int compat_prepare_timeout(const struct compat_timespec __user *p,
1476 struct timespec *ts)
1477{
1478 if (compat_get_timespec(ts, p))
1479 return -EFAULT;
1480 if (!timespec_valid(ts))
1481 return -EINVAL;
1482 return 0;
1483}
1484
1485COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
1486 const char __user *, u_msg_ptr,
1487 compat_size_t, msg_len, unsigned int, msg_prio,
1488 const struct compat_timespec __user *, u_abs_timeout)
1489{
1490 struct timespec ts, *p = NULL;
1491 if (u_abs_timeout) {
1492 int res = compat_prepare_timeout(u_abs_timeout, &ts);
1493 if (res)
1494 return res;
1495 p = &ts;
1496 }
1497 return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
1498}
1499
1500COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
1501 char __user *, u_msg_ptr,
1502 compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
1503 const struct compat_timespec __user *, u_abs_timeout)
1504{
1505 struct timespec ts, *p = NULL;
1506 if (u_abs_timeout) {
1507 int res = compat_prepare_timeout(u_abs_timeout, &ts);
1508 if (res)
1509 return res;
1510 p = &ts;
1511 }
1512 return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
1513}
1514
1515COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1516 const struct compat_sigevent __user *, u_notification)
1517{
1518 struct sigevent n, *p = NULL;
1519 if (u_notification) {
1520 if (get_compat_sigevent(&n, u_notification))
1521 return -EFAULT;
1522 if (n.sigev_notify == SIGEV_THREAD)
1523 n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
1524 p = &n;
1525 }
1526 return do_mq_notify(mqdes, p);
1527}
1528
1529COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
1530 const struct compat_mq_attr __user *, u_mqstat,
1531 struct compat_mq_attr __user *, u_omqstat)
1532{
1533 int ret;
1534 struct mq_attr mqstat, omqstat;
1535 struct mq_attr *new = NULL, *old = NULL;
1536
1537 if (u_mqstat) {
1538 new = &mqstat;
1539 if (get_compat_mq_attr(new, u_mqstat))
1540 return -EFAULT;
1541 }
1542 if (u_omqstat)
1543 old = &omqstat;
1544
1545 ret = do_mq_getsetattr(mqdes, new, old);
1546 if (ret || !old)
1547 return ret;
1548
1549 if (put_compat_mq_attr(old, u_omqstat))
1550 return -EFAULT;
1551 return 0;
1380} 1552}
1553#endif
1381 1554
1382static const struct inode_operations mqueue_dir_inode_operations = { 1555static const struct inode_operations mqueue_dir_inode_operations = {
1383 .lookup = simple_lookup, 1556 .lookup = simple_lookup,