diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-06-27 21:32:36 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-04 13:13:49 -0400 |
commit | 0d0606060baefdb13d3d80dba1b4c816b0676e16 (patch) | |
tree | 1a2546ad468325ea3f6391b62e1c942cba37ef41 | |
parent | cc1a7c4bae28215d042fb9f00dcb77dd65abafdf (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/Makefile | 3 | ||||
-rw-r--r-- | ipc/compat_mq.c | 138 | ||||
-rw-r--r-- | ipc/mqueue.c | 349 |
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 @@ | |||
5 | obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o | 5 | obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o |
6 | obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.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 | 7 | obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o |
8 | obj_mq-$(CONFIG_COMPAT) += compat_mq.o | 8 | obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o |
9 | obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) | ||
10 | obj-$(CONFIG_IPC_NS) += namespace.o | 9 | obj-$(CONFIG_IPC_NS) += namespace.o |
11 | obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o | 10 | obj-$(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 | |||
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 | } | ||
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 | ||
670 | static int prepare_timeout(const struct timespec __user *u_abs_timeout, | 670 | static 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 | ||
773 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | 771 | static 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 | ||
847 | SYSCALL_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 | |||
854 | SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) | 857 | SYSCALL_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 | ||
960 | SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, | 963 | static 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 | ||
1081 | SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, | 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, | 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 | ||
1183 | SYSCALL_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 | |||
1197 | SYSCALL_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 | */ |
1191 | SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, | 1216 | static 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(¬ification, u_notification, | ||
1204 | sizeof(struct sigevent))) | ||
1205 | return -EFAULT; | ||
1206 | } | ||
1207 | |||
1208 | audit_mq_notify(mqdes, u_notification ? ¬ification : 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 */ |
1240 | retry: | 1257 | retry: |
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 | ||
1323 | SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, | 1340 | SYSCALL_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 | |||
1352 | static 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; | 1396 | SYSCALL_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 | ||
1376 | out_fput: | 1404 | if (u_mqstat) { |
1377 | fdput(f); | 1405 | new = &mqstat; |
1378 | out: | 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 | |||
1423 | struct 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 | |||
1431 | static 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 | |||
1447 | static 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 | |||
1462 | COMPAT_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 | |||
1475 | static 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 | |||
1485 | COMPAT_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 | |||
1500 | COMPAT_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 | |||
1515 | COMPAT_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 | |||
1529 | COMPAT_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 | ||
1382 | static const struct inode_operations mqueue_dir_inode_operations = { | 1555 | static const struct inode_operations mqueue_dir_inode_operations = { |
1383 | .lookup = simple_lookup, | 1556 | .lookup = simple_lookup, |