Back to home page

LXR

 
 

    


0001 /*
0002  *  ipc/compat_mq.c
0003  *    32 bit emulation for POSIX message queue system calls
0004  *
0005  *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
0006  *    Author: Arnd Bergmann <arnd@arndb.de>
0007  */
0008 
0009 #include <linux/compat.h>
0010 #include <linux/fs.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mqueue.h>
0013 #include <linux/syscalls.h>
0014 
0015 #include <linux/uaccess.h>
0016 
0017 struct compat_mq_attr {
0018     compat_long_t mq_flags;      /* message queue flags          */
0019     compat_long_t mq_maxmsg;     /* maximum number of messages       */
0020     compat_long_t mq_msgsize;    /* maximum message size             */
0021     compat_long_t mq_curmsgs;    /* number of messages currently queued  */
0022     compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
0023 };
0024 
0025 static inline int get_compat_mq_attr(struct mq_attr *attr,
0026             const struct compat_mq_attr __user *uattr)
0027 {
0028     if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
0029         return -EFAULT;
0030 
0031     return __get_user(attr->mq_flags, &uattr->mq_flags)
0032         | __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
0033         | __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
0034         | __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
0035 }
0036 
0037 static inline int put_compat_mq_attr(const struct mq_attr *attr,
0038             struct compat_mq_attr __user *uattr)
0039 {
0040     if (clear_user(uattr, sizeof *uattr))
0041         return -EFAULT;
0042 
0043     return __put_user(attr->mq_flags, &uattr->mq_flags)
0044         | __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
0045         | __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
0046         | __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
0047 }
0048 
0049 COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
0050                int, oflag, compat_mode_t, mode,
0051                struct compat_mq_attr __user *, u_attr)
0052 {
0053     void __user *p = NULL;
0054     if (u_attr && oflag & O_CREAT) {
0055         struct mq_attr attr;
0056 
0057         memset(&attr, 0, sizeof(attr));
0058 
0059         p = compat_alloc_user_space(sizeof(attr));
0060         if (get_compat_mq_attr(&attr, u_attr) ||
0061             copy_to_user(p, &attr, sizeof(attr)))
0062             return -EFAULT;
0063     }
0064     return sys_mq_open(u_name, oflag, mode, p);
0065 }
0066 
0067 COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
0068                const char __user *, u_msg_ptr,
0069                compat_size_t, msg_len, unsigned int, msg_prio,
0070                const struct compat_timespec __user *, u_abs_timeout)
0071 {
0072     struct timespec __user *u_ts;
0073 
0074     if (compat_convert_timespec(&u_ts, u_abs_timeout))
0075         return -EFAULT;
0076 
0077     return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
0078             msg_prio, u_ts);
0079 }
0080 
0081 COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
0082                char __user *, u_msg_ptr,
0083                compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
0084                const struct compat_timespec __user *, u_abs_timeout)
0085 {
0086     struct timespec __user *u_ts;
0087 
0088     if (compat_convert_timespec(&u_ts, u_abs_timeout))
0089         return -EFAULT;
0090 
0091     return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
0092             u_msg_prio, u_ts);
0093 }
0094 
0095 COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
0096                const struct compat_sigevent __user *, u_notification)
0097 {
0098     struct sigevent __user *p = NULL;
0099     if (u_notification) {
0100         struct sigevent n;
0101         p = compat_alloc_user_space(sizeof(*p));
0102         if (get_compat_sigevent(&n, u_notification))
0103             return -EFAULT;
0104         if (n.sigev_notify == SIGEV_THREAD)
0105             n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
0106         if (copy_to_user(p, &n, sizeof(*p)))
0107             return -EFAULT;
0108     }
0109     return sys_mq_notify(mqdes, p);
0110 }
0111 
0112 COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
0113                const struct compat_mq_attr __user *, u_mqstat,
0114                struct compat_mq_attr __user *, u_omqstat)
0115 {
0116     struct mq_attr mqstat;
0117     struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
0118     long ret;
0119 
0120     memset(&mqstat, 0, sizeof(mqstat));
0121 
0122     if (u_mqstat) {
0123         if (get_compat_mq_attr(&mqstat, u_mqstat) ||
0124             copy_to_user(p, &mqstat, sizeof(mqstat)))
0125             return -EFAULT;
0126     }
0127     ret = sys_mq_getsetattr(mqdes,
0128                 u_mqstat ? p : NULL,
0129                 u_omqstat ? p + 1 : NULL);
0130     if (ret)
0131         return ret;
0132     if (u_omqstat) {
0133         if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
0134             put_compat_mq_attr(&mqstat, u_omqstat))
0135             return -EFAULT;
0136     }
0137     return 0;
0138 }