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>
This commit is contained in:
parent
cc1a7c4bae
commit
0d0606060b
3 changed files with 263 additions and 229 deletions
|
@ -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
|
||||
|
||||
|
|
138
ipc/compat_mq.c
138
ipc/compat_mq.c
|
@ -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;
|
||||
}
|
351
ipc/mqueue.c
351
ipc/mqueue.c
|
@ -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(¬ification, u_notification,
|
||||
sizeof(struct sigevent)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
audit_mq_notify(mqdes, u_notification ? ¬ification : 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;
|
||||
|
||||
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
||||
fdput(f);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
inode = file_inode(f.file);
|
||||
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
||||
ret = -EBADF;
|
||||
goto out_fput;
|
||||
}
|
||||
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,18 +1389,169 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
|||
}
|
||||
|
||||
spin_unlock(&info->lock);
|
||||
|
||||
ret = 0;
|
||||
if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
|
||||
sizeof(struct mq_attr)))
|
||||
ret = -EFAULT;
|
||||
|
||||
out_fput:
|
||||
fdput(f);
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
.create = mqueue_create,
|
||||
|
|
Loading…
Reference in a new issue