mqueue: move compat syscalls to native ones
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 28 Jun 2017 01:32:36 +0000 (21:32 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 4 Jul 2017 17:13:49 +0000 (13:13 -0400)
... 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>
ipc/Makefile
ipc/compat_mq.c [deleted file]
ipc/mqueue.c

index 86c7300ecdf5d566111459fe07e7d171e08a192d..9c200e544434761aac1e0d2d9effbcb1c616bd91 100644 (file)
@@ -5,8 +5,7 @@
 obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
 obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o
 obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
-obj_mq-$(CONFIG_COMPAT) += compat_mq.o
-obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
+obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
 obj-$(CONFIG_IPC_NS) += namespace.o
 obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
 
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
deleted file mode 100644 (file)
index ef6f91c..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  ipc/compat_mq.c
- *    32 bit emulation for POSIX message queue system calls
- *
- *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author: Arnd Bergmann <arnd@arndb.de>
- */
-
-#include <linux/compat.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/mqueue.h>
-#include <linux/syscalls.h>
-
-#include <linux/uaccess.h>
-
-struct compat_mq_attr {
-       compat_long_t mq_flags;      /* message queue flags                  */
-       compat_long_t mq_maxmsg;     /* maximum number of messages           */
-       compat_long_t mq_msgsize;    /* maximum message size                 */
-       compat_long_t mq_curmsgs;    /* number of messages currently queued  */
-       compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
-};
-
-static inline int get_compat_mq_attr(struct mq_attr *attr,
-                       const struct compat_mq_attr __user *uattr)
-{
-       if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
-               return -EFAULT;
-
-       return __get_user(attr->mq_flags, &uattr->mq_flags)
-               | __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
-               | __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
-               | __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
-}
-
-static inline int put_compat_mq_attr(const struct mq_attr *attr,
-                       struct compat_mq_attr __user *uattr)
-{
-       if (clear_user(uattr, sizeof *uattr))
-               return -EFAULT;
-
-       return __put_user(attr->mq_flags, &uattr->mq_flags)
-               | __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
-               | __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
-               | __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
-}
-
-COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
-                      int, oflag, compat_mode_t, mode,
-                      struct compat_mq_attr __user *, u_attr)
-{
-       void __user *p = NULL;
-       if (u_attr && oflag & O_CREAT) {
-               struct mq_attr attr;
-
-               memset(&attr, 0, sizeof(attr));
-
-               p = compat_alloc_user_space(sizeof(attr));
-               if (get_compat_mq_attr(&attr, u_attr) ||
-                   copy_to_user(p, &attr, sizeof(attr)))
-                       return -EFAULT;
-       }
-       return sys_mq_open(u_name, oflag, mode, p);
-}
-
-COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
-                      const char __user *, u_msg_ptr,
-                      compat_size_t, msg_len, unsigned int, msg_prio,
-                      const struct compat_timespec __user *, u_abs_timeout)
-{
-       struct timespec __user *u_ts;
-
-       if (compat_convert_timespec(&u_ts, u_abs_timeout))
-               return -EFAULT;
-
-       return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
-                       msg_prio, u_ts);
-}
-
-COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
-                      char __user *, u_msg_ptr,
-                      compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
-                      const struct compat_timespec __user *, u_abs_timeout)
-{
-       struct timespec __user *u_ts;
-
-       if (compat_convert_timespec(&u_ts, u_abs_timeout))
-               return -EFAULT;
-
-       return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
-                       u_msg_prio, u_ts);
-}
-
-COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
-                      const struct compat_sigevent __user *, u_notification)
-{
-       struct sigevent __user *p = NULL;
-       if (u_notification) {
-               struct sigevent n;
-               p = compat_alloc_user_space(sizeof(*p));
-               if (get_compat_sigevent(&n, u_notification))
-                       return -EFAULT;
-               if (n.sigev_notify == SIGEV_THREAD)
-                       n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
-               if (copy_to_user(p, &n, sizeof(*p)))
-                       return -EFAULT;
-       }
-       return sys_mq_notify(mqdes, p);
-}
-
-COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
-                      const struct compat_mq_attr __user *, u_mqstat,
-                      struct compat_mq_attr __user *, u_omqstat)
-{
-       struct mq_attr mqstat;
-       struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
-       long ret;
-
-       memset(&mqstat, 0, sizeof(mqstat));
-
-       if (u_mqstat) {
-               if (get_compat_mq_attr(&mqstat, u_mqstat) ||
-                   copy_to_user(p, &mqstat, sizeof(mqstat)))
-                       return -EFAULT;
-       }
-       ret = sys_mq_getsetattr(mqdes,
-                               u_mqstat ? p : NULL,
-                               u_omqstat ? p + 1 : NULL);
-       if (ret)
-               return ret;
-       if (u_omqstat) {
-               if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
-                   put_compat_mq_attr(&mqstat, u_omqstat))
-                       return -EFAULT;
-       }
-       return 0;
-}
index e8d41ff57241d86e6c2aa0c46e6408897491256e..c9ff943f19abc68158278a0221c6e8a6e432fec5 100644 (file)
@@ -668,14 +668,12 @@ static void __do_notify(struct mqueue_inode_info *info)
 }
 
 static int prepare_timeout(const struct timespec __user *u_abs_timeout,
-                          ktime_t *expires, struct timespec *ts)
+                          struct timespec *ts)
 {
        if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
                return -EFAULT;
        if (!timespec_valid(ts))
                return -EINVAL;
-
-       *expires = timespec_to_ktime(*ts);
        return 0;
 }
 
@@ -770,23 +768,19 @@ static struct file *do_open(struct path *path, int oflag)
        return dentry_open(path, oflag, current_cred());
 }
 
-SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
-               struct mq_attr __user *, u_attr)
+static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
+                     struct mq_attr *attr)
 {
        struct path path;
        struct file *filp;
        struct filename *name;
-       struct mq_attr attr;
        int fd, error;
        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
        struct vfsmount *mnt = ipc_ns->mq_mnt;
        struct dentry *root = mnt->mnt_root;
        int ro;
 
-       if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
-               return -EFAULT;
-
-       audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
+       audit_mq_open(oflag, mode, attr);
 
        if (IS_ERR(name = getname(u_name)))
                return PTR_ERR(name);
@@ -819,9 +813,8 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
                                goto out;
                        }
                        audit_inode_parent_hidden(name, root);
-                       filp = do_create(ipc_ns, d_inode(root),
-                                               &path, oflag, mode,
-                                               u_attr ? &attr : NULL);
+                       filp = do_create(ipc_ns, d_inode(root), &path,
+                                        oflag, mode, attr);
                }
        } else {
                if (d_really_is_negative(path.dentry)) {
@@ -851,6 +844,16 @@ out_putname:
        return fd;
 }
 
+SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
+               struct mq_attr __user *, u_attr)
+{
+       struct mq_attr attr;
+       if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
+               return -EFAULT;
+
+       return do_mq_open(u_name, oflag, mode, u_attr ? &attr : NULL);
+}
+
 SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
 {
        int err;
@@ -957,9 +960,9 @@ static inline void pipelined_receive(struct wake_q_head *wake_q,
        sender->state = STATE_READY;
 }
 
-SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
-               size_t, msg_len, unsigned int, msg_prio,
-               const struct timespec __user *, u_abs_timeout)
+static int do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
+               size_t msg_len, unsigned int msg_prio,
+               struct timespec *ts)
 {
        struct fd f;
        struct inode *inode;
@@ -968,22 +971,19 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
        struct msg_msg *msg_ptr;
        struct mqueue_inode_info *info;
        ktime_t expires, *timeout = NULL;
-       struct timespec ts;
        struct posix_msg_tree_node *new_leaf = NULL;
        int ret = 0;
        DEFINE_WAKE_Q(wake_q);
 
-       if (u_abs_timeout) {
-               int res = prepare_timeout(u_abs_timeout, &expires, &ts);
-               if (res)
-                       return res;
-               timeout = &expires;
-       }
-
        if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
                return -EINVAL;
 
-       audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL);
+       if (ts) {
+               expires = timespec_to_ktime(*ts);
+               timeout = &expires;
+       }
+
+       audit_mq_sendrecv(mqdes, msg_len, msg_prio, ts);
 
        f = fdget(mqdes);
        if (unlikely(!f.file)) {
@@ -1078,9 +1078,9 @@ out:
        return ret;
 }
 
-SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
-               size_t, msg_len, unsigned int __user *, u_msg_prio,
-               const struct timespec __user *, u_abs_timeout)
+static int do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
+               size_t msg_len, unsigned int __user *u_msg_prio,
+               struct timespec *ts)
 {
        ssize_t ret;
        struct msg_msg *msg_ptr;
@@ -1089,17 +1089,14 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
        struct mqueue_inode_info *info;
        struct ext_wait_queue wait;
        ktime_t expires, *timeout = NULL;
-       struct timespec ts;
        struct posix_msg_tree_node *new_leaf = NULL;
 
-       if (u_abs_timeout) {
-               int res = prepare_timeout(u_abs_timeout, &expires, &ts);
-               if (res)
-                       return res;
+       if (ts) {
+               expires = timespec_to_ktime(*ts);
                timeout = &expires;
        }
 
-       audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL);
+       audit_mq_sendrecv(mqdes, msg_len, 0, ts);
 
        f = fdget(mqdes);
        if (unlikely(!f.file)) {
@@ -1183,42 +1180,62 @@ out:
        return ret;
 }
 
+SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
+               size_t, msg_len, unsigned int, msg_prio,
+               const struct timespec __user *, u_abs_timeout)
+{
+       struct timespec ts, *p = NULL;
+       if (u_abs_timeout) {
+               int res = prepare_timeout(u_abs_timeout, &ts);
+               if (res)
+                       return res;
+               p = &ts;
+       }
+       return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
+}
+
+SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
+               size_t, msg_len, unsigned int __user *, u_msg_prio,
+               const struct timespec __user *, u_abs_timeout)
+{
+       struct timespec ts, *p = NULL;
+       if (u_abs_timeout) {
+               int res = prepare_timeout(u_abs_timeout, &ts);
+               if (res)
+                       return res;
+               p = &ts;
+       }
+       return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
+}
+
 /*
  * Notes: the case when user wants us to deregister (with NULL as pointer)
  * and he isn't currently owner of notification, will be silently discarded.
  * It isn't explicitly defined in the POSIX.
  */
-SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
-               const struct sigevent __user *, u_notification)
+static int do_mq_notify(mqd_t mqdes, const struct sigevent *notification)
 {
        int ret;
        struct fd f;
        struct sock *sock;
        struct inode *inode;
-       struct sigevent notification;
        struct mqueue_inode_info *info;
        struct sk_buff *nc;
 
-       if (u_notification) {
-               if (copy_from_user(&notification, u_notification,
-                                       sizeof(struct sigevent)))
-                       return -EFAULT;
-       }
-
-       audit_mq_notify(mqdes, u_notification ? &notification : NULL);
+       audit_mq_notify(mqdes, notification);
 
        nc = NULL;
        sock = NULL;
-       if (u_notification != NULL) {
-               if (unlikely(notification.sigev_notify != SIGEV_NONE &&
-                            notification.sigev_notify != SIGEV_SIGNAL &&
-                            notification.sigev_notify != SIGEV_THREAD))
+       if (notification != NULL) {
+               if (unlikely(notification->sigev_notify != SIGEV_NONE &&
+                            notification->sigev_notify != SIGEV_SIGNAL &&
+                            notification->sigev_notify != SIGEV_THREAD))
                        return -EINVAL;
-               if (notification.sigev_notify == SIGEV_SIGNAL &&
-                       !valid_signal(notification.sigev_signo)) {
+               if (notification->sigev_notify == SIGEV_SIGNAL &&
+                       !valid_signal(notification->sigev_signo)) {
                        return -EINVAL;
                }
-               if (notification.sigev_notify == SIGEV_THREAD) {
+               if (notification->sigev_notify == SIGEV_THREAD) {
                        long timeo;
 
                        /* create the notify skb */
@@ -1228,7 +1245,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
                                goto out;
                        }
                        if (copy_from_user(nc->data,
-                                       notification.sigev_value.sival_ptr,
+                                       notification->sigev_value.sival_ptr,
                                        NOTIFY_COOKIE_LEN)) {
                                ret = -EFAULT;
                                goto out;
@@ -1238,7 +1255,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
                        skb_put(nc, NOTIFY_COOKIE_LEN);
                        /* and attach it to the socket */
 retry:
-                       f = fdget(notification.sigev_signo);
+                       f = fdget(notification->sigev_signo);
                        if (!f.file) {
                                ret = -EBADF;
                                goto out;
@@ -1278,7 +1295,7 @@ retry:
 
        ret = 0;
        spin_lock(&info->lock);
-       if (u_notification == NULL) {
+       if (notification == NULL) {
                if (info->notify_owner == task_tgid(current)) {
                        remove_notification(info);
                        inode->i_atime = inode->i_ctime = current_time(inode);
@@ -1286,7 +1303,7 @@ retry:
        } else if (info->notify_owner != NULL) {
                ret = -EBUSY;
        } else {
-               switch (notification.sigev_notify) {
+               switch (notification->sigev_notify) {
                case SIGEV_NONE:
                        info->notify.sigev_notify = SIGEV_NONE;
                        break;
@@ -1298,8 +1315,8 @@ retry:
                        info->notify.sigev_notify = SIGEV_THREAD;
                        break;
                case SIGEV_SIGNAL:
-                       info->notify.sigev_signo = notification.sigev_signo;
-                       info->notify.sigev_value = notification.sigev_value;
+                       info->notify.sigev_signo = notification->sigev_signo;
+                       info->notify.sigev_value = notification->sigev_value;
                        info->notify.sigev_notify = SIGEV_SIGNAL;
                        break;
                }
@@ -1320,44 +1337,49 @@ out:
        return ret;
 }
 
-SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
-               const struct mq_attr __user *, u_mqstat,
-               struct mq_attr __user *, u_omqstat)
+SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
+               const struct sigevent __user *, u_notification)
+{
+       struct sigevent n, *p = NULL;
+       if (u_notification) {
+               if (copy_from_user(&n, u_notification, sizeof(struct sigevent)))
+                       return -EFAULT;
+               p = &n;
+       }
+       return do_mq_notify(mqdes, p);
+}
+
+static int do_mq_getsetattr(int mqdes, struct mq_attr *new, struct mq_attr *old)
 {
-       int ret;
-       struct mq_attr mqstat, omqstat;
        struct fd f;
        struct inode *inode;
        struct mqueue_inode_info *info;
 
-       if (u_mqstat != NULL) {
-               if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr)))
-                       return -EFAULT;
-               if (mqstat.mq_flags & (~O_NONBLOCK))
-                       return -EINVAL;
-       }
+       if (new && (new->mq_flags & (~O_NONBLOCK)))
+               return -EINVAL;
 
        f = fdget(mqdes);
-       if (!f.file) {
-               ret = -EBADF;
-               goto out;
-       }
+       if (!f.file)
+               return -EBADF;
 
-       inode = file_inode(f.file);
        if (unlikely(f.file->f_op != &mqueue_file_operations)) {
-               ret = -EBADF;
-               goto out_fput;
+               fdput(f);
+               return -EBADF;
        }
+
+       inode = file_inode(f.file);
        info = MQUEUE_I(inode);
 
        spin_lock(&info->lock);
 
-       omqstat = info->attr;
-       omqstat.mq_flags = f.file->f_flags & O_NONBLOCK;
-       if (u_mqstat) {
-               audit_mq_getsetattr(mqdes, &mqstat);
+       if (old) {
+               *old = info->attr;
+               old->mq_flags = f.file->f_flags & O_NONBLOCK;
+       }
+       if (new) {
+               audit_mq_getsetattr(mqdes, new);
                spin_lock(&f.file->f_lock);
-               if (mqstat.mq_flags & O_NONBLOCK)
+               if (new->mq_flags & O_NONBLOCK)
                        f.file->f_flags |= O_NONBLOCK;
                else
                        f.file->f_flags &= ~O_NONBLOCK;
@@ -1367,17 +1389,168 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
        }
 
        spin_unlock(&info->lock);
+       fdput(f);
+       return 0;
+}
 
-       ret = 0;
-       if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
-                                               sizeof(struct mq_attr)))
-               ret = -EFAULT;
+SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
+               const struct mq_attr __user *, u_mqstat,
+               struct mq_attr __user *, u_omqstat)
+{
+       int ret;
+       struct mq_attr mqstat, omqstat;
+       struct mq_attr *new = NULL, *old = NULL;
 
-out_fput:
-       fdput(f);
-out:
-       return ret;
+       if (u_mqstat) {
+               new = &mqstat;
+               if (copy_from_user(new, u_mqstat, sizeof(struct mq_attr)))
+                       return -EFAULT;
+       }
+       if (u_omqstat)
+               old = &omqstat;
+
+       ret = do_mq_getsetattr(mqdes, new, old);
+       if (ret || !old)
+               return ret;
+
+       if (copy_to_user(u_omqstat, old, sizeof(struct mq_attr)))
+               return -EFAULT;
+       return 0;
+}
+
+#ifdef CONFIG_COMPAT
+
+struct compat_mq_attr {
+       compat_long_t mq_flags;      /* message queue flags                  */
+       compat_long_t mq_maxmsg;     /* maximum number of messages           */
+       compat_long_t mq_msgsize;    /* maximum message size                 */
+       compat_long_t mq_curmsgs;    /* number of messages currently queued  */
+       compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
+};
+
+static inline int get_compat_mq_attr(struct mq_attr *attr,
+                       const struct compat_mq_attr __user *uattr)
+{
+       struct compat_mq_attr v;
+
+       if (copy_from_user(&v, uattr, sizeof(*uattr)))
+               return -EFAULT;
+
+       memset(attr, 0, sizeof(*attr));
+       attr->mq_flags = v.mq_flags;
+       attr->mq_maxmsg = v.mq_maxmsg;
+       attr->mq_msgsize = v.mq_msgsize;
+       attr->mq_curmsgs = v.mq_curmsgs;
+       return 0;
+}
+
+static inline int put_compat_mq_attr(const struct mq_attr *attr,
+                       struct compat_mq_attr __user *uattr)
+{
+       struct compat_mq_attr v;
+
+       memset(&v, 0, sizeof(v));
+       v.mq_flags = attr->mq_flags;
+       v.mq_maxmsg = attr->mq_maxmsg;
+       v.mq_msgsize = attr->mq_msgsize;
+       v.mq_curmsgs = attr->mq_curmsgs;
+       if (copy_to_user(uattr, &v, sizeof(*uattr)))
+               return -EFAULT;
+       return 0;
+}
+
+COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
+                      int, oflag, compat_mode_t, mode,
+                      struct compat_mq_attr __user *, u_attr)
+{
+       struct mq_attr attr, *p = NULL;
+       if (u_attr && oflag & O_CREAT) {
+               p = &attr;
+               if (get_compat_mq_attr(&attr, u_attr))
+                       return -EFAULT;
+       }
+       return do_mq_open(u_name, oflag, mode, p);
+}
+
+static int compat_prepare_timeout(const struct compat_timespec __user *p,
+                                  struct timespec *ts)
+{
+       if (compat_get_timespec(ts, p))
+               return -EFAULT;
+       if (!timespec_valid(ts))
+               return -EINVAL;
+       return 0;
+}
+
+COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
+                      const char __user *, u_msg_ptr,
+                      compat_size_t, msg_len, unsigned int, msg_prio,
+                      const struct compat_timespec __user *, u_abs_timeout)
+{
+       struct timespec ts, *p = NULL;
+       if (u_abs_timeout) {
+               int res = compat_prepare_timeout(u_abs_timeout, &ts);
+               if (res)
+                       return res;
+               p = &ts;
+       }
+       return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
+}
+
+COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
+                      char __user *, u_msg_ptr,
+                      compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
+                      const struct compat_timespec __user *, u_abs_timeout)
+{
+       struct timespec ts, *p = NULL;
+       if (u_abs_timeout) {
+               int res = compat_prepare_timeout(u_abs_timeout, &ts);
+               if (res)
+                       return res;
+               p = &ts;
+       }
+       return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
+}
+
+COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
+                      const struct compat_sigevent __user *, u_notification)
+{
+       struct sigevent n, *p = NULL;
+       if (u_notification) {
+               if (get_compat_sigevent(&n, u_notification))
+                       return -EFAULT;
+               if (n.sigev_notify == SIGEV_THREAD)
+                       n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
+               p = &n;
+       }
+       return do_mq_notify(mqdes, p);
+}
+
+COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
+                      const struct compat_mq_attr __user *, u_mqstat,
+                      struct compat_mq_attr __user *, u_omqstat)
+{
+       int ret;
+       struct mq_attr mqstat, omqstat;
+       struct mq_attr *new = NULL, *old = NULL;
+
+       if (u_mqstat) {
+               new = &mqstat;
+               if (get_compat_mq_attr(new, u_mqstat))
+                       return -EFAULT;
+       }
+       if (u_omqstat)
+               old = &omqstat;
+
+       ret = do_mq_getsetattr(mqdes, new, old);
+       if (ret || !old)
+               return ret;
+
+       if (put_compat_mq_attr(old, u_omqstat))
+               return -EFAULT;
+       return 0;
 }
+#endif
 
 static const struct inode_operations mqueue_dir_inode_operations = {
        .lookup = simple_lookup,