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>

Al Viro 0d060606 cc1a7c4b

+263 -229
+1 -2
ipc/Makefile
··· 5 obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o 6 obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o 7 obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o 8 - obj_mq-$(CONFIG_COMPAT) += compat_mq.o 9 - obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) 10 obj-$(CONFIG_IPC_NS) += namespace.o 11 obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o 12
··· 5 obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o 6 obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o 7 obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o 8 + obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o 9 obj-$(CONFIG_IPC_NS) += namespace.o 10 obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o 11
-138
ipc/compat_mq.c
··· 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 - 17 - struct 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 - 25 - static 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 - 37 - static 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 - 49 - COMPAT_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 - 67 - COMPAT_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 - 81 - COMPAT_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 - 95 - COMPAT_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 - 112 - COMPAT_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 - }
···
+262 -89
ipc/mqueue.c
··· 668 } 669 670 static int prepare_timeout(const struct timespec __user *u_abs_timeout, 671 - ktime_t *expires, struct timespec *ts) 672 { 673 if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec))) 674 return -EFAULT; 675 if (!timespec_valid(ts)) 676 return -EINVAL; 677 - 678 - *expires = timespec_to_ktime(*ts); 679 return 0; 680 } 681 ··· 768 return dentry_open(path, oflag, current_cred()); 769 } 770 771 - SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, 772 - struct mq_attr __user *, u_attr) 773 { 774 struct path path; 775 struct file *filp; 776 struct filename *name; 777 - struct mq_attr attr; 778 int fd, error; 779 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 780 struct vfsmount *mnt = ipc_ns->mq_mnt; 781 struct dentry *root = mnt->mnt_root; 782 int ro; 783 784 - if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 785 - return -EFAULT; 786 - 787 - audit_mq_open(oflag, mode, u_attr ? &attr : NULL); 788 789 if (IS_ERR(name = getname(u_name))) 790 return PTR_ERR(name); ··· 813 goto out; 814 } 815 audit_inode_parent_hidden(name, root); 816 - filp = do_create(ipc_ns, d_inode(root), 817 - &path, oflag, mode, 818 - u_attr ? &attr : NULL); 819 } 820 } else { 821 if (d_really_is_negative(path.dentry)) { ··· 842 out_putname: 843 putname(name); 844 return fd; 845 } 846 847 SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) ··· 960 sender->state = STATE_READY; 961 } 962 963 - SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, 964 - size_t, msg_len, unsigned int, msg_prio, 965 - const struct timespec __user *, u_abs_timeout) 966 { 967 struct fd f; 968 struct inode *inode; ··· 971 struct msg_msg *msg_ptr; 972 struct mqueue_inode_info *info; 973 ktime_t expires, *timeout = NULL; 974 - struct timespec ts; 975 struct posix_msg_tree_node *new_leaf = NULL; 976 int ret = 0; 977 DEFINE_WAKE_Q(wake_q); 978 979 - if (u_abs_timeout) { 980 - int res = prepare_timeout(u_abs_timeout, &expires, &ts); 981 - if (res) 982 - return res; 983 - timeout = &expires; 984 - } 985 - 986 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) 987 return -EINVAL; 988 989 - audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL); 990 991 f = fdget(mqdes); 992 if (unlikely(!f.file)) { ··· 1078 return ret; 1079 } 1080 1081 - SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, 1082 - size_t, msg_len, unsigned int __user *, u_msg_prio, 1083 - const struct timespec __user *, u_abs_timeout) 1084 { 1085 ssize_t ret; 1086 struct msg_msg *msg_ptr; ··· 1089 struct mqueue_inode_info *info; 1090 struct ext_wait_queue wait; 1091 ktime_t expires, *timeout = NULL; 1092 - struct timespec ts; 1093 struct posix_msg_tree_node *new_leaf = NULL; 1094 1095 - if (u_abs_timeout) { 1096 - int res = prepare_timeout(u_abs_timeout, &expires, &ts); 1097 - if (res) 1098 - return res; 1099 timeout = &expires; 1100 } 1101 1102 - audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL); 1103 1104 f = fdget(mqdes); 1105 if (unlikely(!f.file)) { ··· 1180 return ret; 1181 } 1182 1183 /* 1184 * Notes: the case when user wants us to deregister (with NULL as pointer) 1185 * and he isn't currently owner of notification, will be silently discarded. 1186 * It isn't explicitly defined in the POSIX. 1187 */ 1188 - SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, 1189 - const struct sigevent __user *, u_notification) 1190 { 1191 int ret; 1192 struct fd f; 1193 struct sock *sock; 1194 struct inode *inode; 1195 - struct sigevent notification; 1196 struct mqueue_inode_info *info; 1197 struct sk_buff *nc; 1198 1199 - if (u_notification) { 1200 - if (copy_from_user(&notification, u_notification, 1201 - sizeof(struct sigevent))) 1202 - return -EFAULT; 1203 - } 1204 - 1205 - audit_mq_notify(mqdes, u_notification ? &notification : NULL); 1206 1207 nc = NULL; 1208 sock = NULL; 1209 - if (u_notification != NULL) { 1210 - if (unlikely(notification.sigev_notify != SIGEV_NONE && 1211 - notification.sigev_notify != SIGEV_SIGNAL && 1212 - notification.sigev_notify != SIGEV_THREAD)) 1213 return -EINVAL; 1214 - if (notification.sigev_notify == SIGEV_SIGNAL && 1215 - !valid_signal(notification.sigev_signo)) { 1216 return -EINVAL; 1217 } 1218 - if (notification.sigev_notify == SIGEV_THREAD) { 1219 long timeo; 1220 1221 /* create the notify skb */ ··· 1245 goto out; 1246 } 1247 if (copy_from_user(nc->data, 1248 - notification.sigev_value.sival_ptr, 1249 NOTIFY_COOKIE_LEN)) { 1250 ret = -EFAULT; 1251 goto out; ··· 1255 skb_put(nc, NOTIFY_COOKIE_LEN); 1256 /* and attach it to the socket */ 1257 retry: 1258 - f = fdget(notification.sigev_signo); 1259 if (!f.file) { 1260 ret = -EBADF; 1261 goto out; ··· 1295 1296 ret = 0; 1297 spin_lock(&info->lock); 1298 - if (u_notification == NULL) { 1299 if (info->notify_owner == task_tgid(current)) { 1300 remove_notification(info); 1301 inode->i_atime = inode->i_ctime = current_time(inode); ··· 1303 } else if (info->notify_owner != NULL) { 1304 ret = -EBUSY; 1305 } else { 1306 - switch (notification.sigev_notify) { 1307 case SIGEV_NONE: 1308 info->notify.sigev_notify = SIGEV_NONE; 1309 break; ··· 1315 info->notify.sigev_notify = SIGEV_THREAD; 1316 break; 1317 case SIGEV_SIGNAL: 1318 - info->notify.sigev_signo = notification.sigev_signo; 1319 - info->notify.sigev_value = notification.sigev_value; 1320 info->notify.sigev_notify = SIGEV_SIGNAL; 1321 break; 1322 } ··· 1337 return ret; 1338 } 1339 1340 - SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, 1341 - const struct mq_attr __user *, u_mqstat, 1342 - struct mq_attr __user *, u_omqstat) 1343 { 1344 - int ret; 1345 - struct mq_attr mqstat, omqstat; 1346 struct fd f; 1347 struct inode *inode; 1348 struct mqueue_inode_info *info; 1349 1350 - if (u_mqstat != NULL) { 1351 - if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr))) 1352 - return -EFAULT; 1353 - if (mqstat.mq_flags & (~O_NONBLOCK)) 1354 - return -EINVAL; 1355 - } 1356 1357 f = fdget(mqdes); 1358 - if (!f.file) { 1359 - ret = -EBADF; 1360 - goto out; 1361 } 1362 1363 inode = file_inode(f.file); 1364 - if (unlikely(f.file->f_op != &mqueue_file_operations)) { 1365 - ret = -EBADF; 1366 - goto out_fput; 1367 - } 1368 info = MQUEUE_I(inode); 1369 1370 spin_lock(&info->lock); 1371 1372 - omqstat = info->attr; 1373 - omqstat.mq_flags = f.file->f_flags & O_NONBLOCK; 1374 - if (u_mqstat) { 1375 - audit_mq_getsetattr(mqdes, &mqstat); 1376 spin_lock(&f.file->f_lock); 1377 - if (mqstat.mq_flags & O_NONBLOCK) 1378 f.file->f_flags |= O_NONBLOCK; 1379 else 1380 f.file->f_flags &= ~O_NONBLOCK; ··· 1389 } 1390 1391 spin_unlock(&info->lock); 1392 - 1393 - ret = 0; 1394 - if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat, 1395 - sizeof(struct mq_attr))) 1396 - ret = -EFAULT; 1397 - 1398 - out_fput: 1399 fdput(f); 1400 - out: 1401 - return ret; 1402 } 1403 1404 static const struct inode_operations mqueue_dir_inode_operations = { 1405 .lookup = simple_lookup,
··· 668 } 669 670 static int prepare_timeout(const struct timespec __user *u_abs_timeout, 671 + struct timespec *ts) 672 { 673 if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec))) 674 return -EFAULT; 675 if (!timespec_valid(ts)) 676 return -EINVAL; 677 return 0; 678 } 679 ··· 770 return dentry_open(path, oflag, current_cred()); 771 } 772 773 + static int do_mq_open(const char __user *u_name, int oflag, umode_t mode, 774 + struct mq_attr *attr) 775 { 776 struct path path; 777 struct file *filp; 778 struct filename *name; 779 int fd, error; 780 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 781 struct vfsmount *mnt = ipc_ns->mq_mnt; 782 struct dentry *root = mnt->mnt_root; 783 int ro; 784 785 + audit_mq_open(oflag, mode, attr); 786 787 if (IS_ERR(name = getname(u_name))) 788 return PTR_ERR(name); ··· 819 goto out; 820 } 821 audit_inode_parent_hidden(name, root); 822 + filp = do_create(ipc_ns, d_inode(root), &path, 823 + oflag, mode, attr); 824 } 825 } else { 826 if (d_really_is_negative(path.dentry)) { ··· 849 out_putname: 850 putname(name); 851 return fd; 852 + } 853 + 854 + SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, 855 + struct mq_attr __user *, u_attr) 856 + { 857 + struct mq_attr attr; 858 + if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 859 + return -EFAULT; 860 + 861 + return do_mq_open(u_name, oflag, mode, u_attr ? &attr : NULL); 862 } 863 864 SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) ··· 957 sender->state = STATE_READY; 958 } 959 960 + static int do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, 961 + size_t msg_len, unsigned int msg_prio, 962 + struct timespec *ts) 963 { 964 struct fd f; 965 struct inode *inode; ··· 968 struct msg_msg *msg_ptr; 969 struct mqueue_inode_info *info; 970 ktime_t expires, *timeout = NULL; 971 struct posix_msg_tree_node *new_leaf = NULL; 972 int ret = 0; 973 DEFINE_WAKE_Q(wake_q); 974 975 if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) 976 return -EINVAL; 977 978 + if (ts) { 979 + expires = timespec_to_ktime(*ts); 980 + timeout = &expires; 981 + } 982 + 983 + audit_mq_sendrecv(mqdes, msg_len, msg_prio, ts); 984 985 f = fdget(mqdes); 986 if (unlikely(!f.file)) { ··· 1078 return ret; 1079 } 1080 1081 + static int do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, 1082 + size_t msg_len, unsigned int __user *u_msg_prio, 1083 + struct timespec *ts) 1084 { 1085 ssize_t ret; 1086 struct msg_msg *msg_ptr; ··· 1089 struct mqueue_inode_info *info; 1090 struct ext_wait_queue wait; 1091 ktime_t expires, *timeout = NULL; 1092 struct posix_msg_tree_node *new_leaf = NULL; 1093 1094 + if (ts) { 1095 + expires = timespec_to_ktime(*ts); 1096 timeout = &expires; 1097 } 1098 1099 + audit_mq_sendrecv(mqdes, msg_len, 0, ts); 1100 1101 f = fdget(mqdes); 1102 if (unlikely(!f.file)) { ··· 1183 return ret; 1184 } 1185 1186 + SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, 1187 + size_t, msg_len, unsigned int, msg_prio, 1188 + const struct timespec __user *, u_abs_timeout) 1189 + { 1190 + struct timespec ts, *p = NULL; 1191 + if (u_abs_timeout) { 1192 + int res = prepare_timeout(u_abs_timeout, &ts); 1193 + if (res) 1194 + return res; 1195 + p = &ts; 1196 + } 1197 + return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p); 1198 + } 1199 + 1200 + SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, 1201 + size_t, msg_len, unsigned int __user *, u_msg_prio, 1202 + const struct timespec __user *, u_abs_timeout) 1203 + { 1204 + struct timespec ts, *p = NULL; 1205 + if (u_abs_timeout) { 1206 + int res = prepare_timeout(u_abs_timeout, &ts); 1207 + if (res) 1208 + return res; 1209 + p = &ts; 1210 + } 1211 + return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p); 1212 + } 1213 + 1214 /* 1215 * Notes: the case when user wants us to deregister (with NULL as pointer) 1216 * and he isn't currently owner of notification, will be silently discarded. 1217 * It isn't explicitly defined in the POSIX. 1218 */ 1219 + static int do_mq_notify(mqd_t mqdes, const struct sigevent *notification) 1220 { 1221 int ret; 1222 struct fd f; 1223 struct sock *sock; 1224 struct inode *inode; 1225 struct mqueue_inode_info *info; 1226 struct sk_buff *nc; 1227 1228 + audit_mq_notify(mqdes, notification); 1229 1230 nc = NULL; 1231 sock = NULL; 1232 + if (notification != NULL) { 1233 + if (unlikely(notification->sigev_notify != SIGEV_NONE && 1234 + notification->sigev_notify != SIGEV_SIGNAL && 1235 + notification->sigev_notify != SIGEV_THREAD)) 1236 return -EINVAL; 1237 + if (notification->sigev_notify == SIGEV_SIGNAL && 1238 + !valid_signal(notification->sigev_signo)) { 1239 return -EINVAL; 1240 } 1241 + if (notification->sigev_notify == SIGEV_THREAD) { 1242 long timeo; 1243 1244 /* create the notify skb */ ··· 1228 goto out; 1229 } 1230 if (copy_from_user(nc->data, 1231 + notification->sigev_value.sival_ptr, 1232 NOTIFY_COOKIE_LEN)) { 1233 ret = -EFAULT; 1234 goto out; ··· 1238 skb_put(nc, NOTIFY_COOKIE_LEN); 1239 /* and attach it to the socket */ 1240 retry: 1241 + f = fdget(notification->sigev_signo); 1242 if (!f.file) { 1243 ret = -EBADF; 1244 goto out; ··· 1278 1279 ret = 0; 1280 spin_lock(&info->lock); 1281 + if (notification == NULL) { 1282 if (info->notify_owner == task_tgid(current)) { 1283 remove_notification(info); 1284 inode->i_atime = inode->i_ctime = current_time(inode); ··· 1286 } else if (info->notify_owner != NULL) { 1287 ret = -EBUSY; 1288 } else { 1289 + switch (notification->sigev_notify) { 1290 case SIGEV_NONE: 1291 info->notify.sigev_notify = SIGEV_NONE; 1292 break; ··· 1298 info->notify.sigev_notify = SIGEV_THREAD; 1299 break; 1300 case SIGEV_SIGNAL: 1301 + info->notify.sigev_signo = notification->sigev_signo; 1302 + info->notify.sigev_value = notification->sigev_value; 1303 info->notify.sigev_notify = SIGEV_SIGNAL; 1304 break; 1305 } ··· 1320 return ret; 1321 } 1322 1323 + SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, 1324 + const struct sigevent __user *, u_notification) 1325 { 1326 + struct sigevent n, *p = NULL; 1327 + if (u_notification) { 1328 + if (copy_from_user(&n, u_notification, sizeof(struct sigevent))) 1329 + return -EFAULT; 1330 + p = &n; 1331 + } 1332 + return do_mq_notify(mqdes, p); 1333 + } 1334 + 1335 + static int do_mq_getsetattr(int mqdes, struct mq_attr *new, struct mq_attr *old) 1336 + { 1337 struct fd f; 1338 struct inode *inode; 1339 struct mqueue_inode_info *info; 1340 1341 + if (new && (new->mq_flags & (~O_NONBLOCK))) 1342 + return -EINVAL; 1343 1344 f = fdget(mqdes); 1345 + if (!f.file) 1346 + return -EBADF; 1347 + 1348 + if (unlikely(f.file->f_op != &mqueue_file_operations)) { 1349 + fdput(f); 1350 + return -EBADF; 1351 } 1352 1353 inode = file_inode(f.file); 1354 info = MQUEUE_I(inode); 1355 1356 spin_lock(&info->lock); 1357 1358 + if (old) { 1359 + *old = info->attr; 1360 + old->mq_flags = f.file->f_flags & O_NONBLOCK; 1361 + } 1362 + if (new) { 1363 + audit_mq_getsetattr(mqdes, new); 1364 spin_lock(&f.file->f_lock); 1365 + if (new->mq_flags & O_NONBLOCK) 1366 f.file->f_flags |= O_NONBLOCK; 1367 else 1368 f.file->f_flags &= ~O_NONBLOCK; ··· 1367 } 1368 1369 spin_unlock(&info->lock); 1370 fdput(f); 1371 + return 0; 1372 } 1373 + 1374 + SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, 1375 + const struct mq_attr __user *, u_mqstat, 1376 + struct mq_attr __user *, u_omqstat) 1377 + { 1378 + int ret; 1379 + struct mq_attr mqstat, omqstat; 1380 + struct mq_attr *new = NULL, *old = NULL; 1381 + 1382 + if (u_mqstat) { 1383 + new = &mqstat; 1384 + if (copy_from_user(new, u_mqstat, sizeof(struct mq_attr))) 1385 + return -EFAULT; 1386 + } 1387 + if (u_omqstat) 1388 + old = &omqstat; 1389 + 1390 + ret = do_mq_getsetattr(mqdes, new, old); 1391 + if (ret || !old) 1392 + return ret; 1393 + 1394 + if (copy_to_user(u_omqstat, old, sizeof(struct mq_attr))) 1395 + return -EFAULT; 1396 + return 0; 1397 + } 1398 + 1399 + #ifdef CONFIG_COMPAT 1400 + 1401 + struct compat_mq_attr { 1402 + compat_long_t mq_flags; /* message queue flags */ 1403 + compat_long_t mq_maxmsg; /* maximum number of messages */ 1404 + compat_long_t mq_msgsize; /* maximum message size */ 1405 + compat_long_t mq_curmsgs; /* number of messages currently queued */ 1406 + compat_long_t __reserved[4]; /* ignored for input, zeroed for output */ 1407 + }; 1408 + 1409 + static inline int get_compat_mq_attr(struct mq_attr *attr, 1410 + const struct compat_mq_attr __user *uattr) 1411 + { 1412 + struct compat_mq_attr v; 1413 + 1414 + if (copy_from_user(&v, uattr, sizeof(*uattr))) 1415 + return -EFAULT; 1416 + 1417 + memset(attr, 0, sizeof(*attr)); 1418 + attr->mq_flags = v.mq_flags; 1419 + attr->mq_maxmsg = v.mq_maxmsg; 1420 + attr->mq_msgsize = v.mq_msgsize; 1421 + attr->mq_curmsgs = v.mq_curmsgs; 1422 + return 0; 1423 + } 1424 + 1425 + static inline int put_compat_mq_attr(const struct mq_attr *attr, 1426 + struct compat_mq_attr __user *uattr) 1427 + { 1428 + struct compat_mq_attr v; 1429 + 1430 + memset(&v, 0, sizeof(v)); 1431 + v.mq_flags = attr->mq_flags; 1432 + v.mq_maxmsg = attr->mq_maxmsg; 1433 + v.mq_msgsize = attr->mq_msgsize; 1434 + v.mq_curmsgs = attr->mq_curmsgs; 1435 + if (copy_to_user(uattr, &v, sizeof(*uattr))) 1436 + return -EFAULT; 1437 + return 0; 1438 + } 1439 + 1440 + COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name, 1441 + int, oflag, compat_mode_t, mode, 1442 + struct compat_mq_attr __user *, u_attr) 1443 + { 1444 + struct mq_attr attr, *p = NULL; 1445 + if (u_attr && oflag & O_CREAT) { 1446 + p = &attr; 1447 + if (get_compat_mq_attr(&attr, u_attr)) 1448 + return -EFAULT; 1449 + } 1450 + return do_mq_open(u_name, oflag, mode, p); 1451 + } 1452 + 1453 + static int compat_prepare_timeout(const struct compat_timespec __user *p, 1454 + struct timespec *ts) 1455 + { 1456 + if (compat_get_timespec(ts, p)) 1457 + return -EFAULT; 1458 + if (!timespec_valid(ts)) 1459 + return -EINVAL; 1460 + return 0; 1461 + } 1462 + 1463 + COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, 1464 + const char __user *, u_msg_ptr, 1465 + compat_size_t, msg_len, unsigned int, msg_prio, 1466 + const struct compat_timespec __user *, u_abs_timeout) 1467 + { 1468 + struct timespec ts, *p = NULL; 1469 + if (u_abs_timeout) { 1470 + int res = compat_prepare_timeout(u_abs_timeout, &ts); 1471 + if (res) 1472 + return res; 1473 + p = &ts; 1474 + } 1475 + return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p); 1476 + } 1477 + 1478 + COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, 1479 + char __user *, u_msg_ptr, 1480 + compat_size_t, msg_len, unsigned int __user *, u_msg_prio, 1481 + const struct compat_timespec __user *, u_abs_timeout) 1482 + { 1483 + struct timespec ts, *p = NULL; 1484 + if (u_abs_timeout) { 1485 + int res = compat_prepare_timeout(u_abs_timeout, &ts); 1486 + if (res) 1487 + return res; 1488 + p = &ts; 1489 + } 1490 + return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p); 1491 + } 1492 + 1493 + COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, 1494 + const struct compat_sigevent __user *, u_notification) 1495 + { 1496 + struct sigevent n, *p = NULL; 1497 + if (u_notification) { 1498 + if (get_compat_sigevent(&n, u_notification)) 1499 + return -EFAULT; 1500 + if (n.sigev_notify == SIGEV_THREAD) 1501 + n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int); 1502 + p = &n; 1503 + } 1504 + return do_mq_notify(mqdes, p); 1505 + } 1506 + 1507 + COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, 1508 + const struct compat_mq_attr __user *, u_mqstat, 1509 + struct compat_mq_attr __user *, u_omqstat) 1510 + { 1511 + int ret; 1512 + struct mq_attr mqstat, omqstat; 1513 + struct mq_attr *new = NULL, *old = NULL; 1514 + 1515 + if (u_mqstat) { 1516 + new = &mqstat; 1517 + if (get_compat_mq_attr(new, u_mqstat)) 1518 + return -EFAULT; 1519 + } 1520 + if (u_omqstat) 1521 + old = &omqstat; 1522 + 1523 + ret = do_mq_getsetattr(mqdes, new, old); 1524 + if (ret || !old) 1525 + return ret; 1526 + 1527 + if (put_compat_mq_attr(old, u_omqstat)) 1528 + return -EFAULT; 1529 + return 0; 1530 + } 1531 + #endif 1532 1533 static const struct inode_operations mqueue_dir_inode_operations = { 1534 .lookup = simple_lookup,