| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 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 <asm/uaccess.h> |
|---|
| 16 |
|
|---|
| 17 |
struct compat_mq_attr { |
|---|
| 18 |
compat_long_t mq_flags; |
|---|
| 19 |
compat_long_t mq_maxmsg; |
|---|
| 20 |
compat_long_t mq_msgsize; |
|---|
| 21 |
compat_long_t mq_curmsgs; |
|---|
| 22 |
compat_long_t __reserved[4]; |
|---|
| 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 (verify_area(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 |
asmlinkage long compat_sys_mq_open(const char __user *u_name, |
|---|
| 50 |
int oflag, compat_mode_t mode, |
|---|
| 51 |
struct compat_mq_attr __user *u_attr) |
|---|
| 52 |
{ |
|---|
| 53 |
struct mq_attr attr; |
|---|
| 54 |
mm_segment_t oldfs; |
|---|
| 55 |
char *name; |
|---|
| 56 |
long ret; |
|---|
| 57 |
|
|---|
| 58 |
if ((oflag & O_CREAT) == 0 || !u_attr) |
|---|
| 59 |
return sys_mq_open(u_name, oflag, mode, 0); |
|---|
| 60 |
|
|---|
| 61 |
if (get_compat_mq_attr(&attr, u_attr)) |
|---|
| 62 |
return -EFAULT; |
|---|
| 63 |
|
|---|
| 64 |
name = getname(u_name); |
|---|
| 65 |
if (IS_ERR(name)) |
|---|
| 66 |
return PTR_ERR(name); |
|---|
| 67 |
|
|---|
| 68 |
oldfs = get_fs(); |
|---|
| 69 |
set_fs(KERNEL_DS); |
|---|
| 70 |
ret = sys_mq_open(name, oflag, mode, &attr); |
|---|
| 71 |
set_fs(oldfs); |
|---|
| 72 |
|
|---|
| 73 |
putname(name); |
|---|
| 74 |
return ret; |
|---|
| 75 |
} |
|---|
| 76 |
|
|---|
| 77 |
static struct timespec __user *compat_prepare_timeout( |
|---|
| 78 |
const struct compat_timespec __user *u_abs_timeout) |
|---|
| 79 |
{ |
|---|
| 80 |
struct timespec ts; |
|---|
| 81 |
struct timespec __user *u_ts; |
|---|
| 82 |
|
|---|
| 83 |
if (!u_abs_timeout) |
|---|
| 84 |
return 0; |
|---|
| 85 |
|
|---|
| 86 |
u_ts = compat_alloc_user_space(sizeof(*u_ts)); |
|---|
| 87 |
if (get_compat_timespec(&ts, u_abs_timeout) |
|---|
| 88 |
|| copy_to_user(u_ts, &ts, sizeof(*u_ts))) |
|---|
| 89 |
return ERR_PTR(-EFAULT); |
|---|
| 90 |
|
|---|
| 91 |
return u_ts; |
|---|
| 92 |
} |
|---|
| 93 |
|
|---|
| 94 |
asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes, |
|---|
| 95 |
const char __user *u_msg_ptr, |
|---|
| 96 |
size_t msg_len, unsigned int msg_prio, |
|---|
| 97 |
const struct compat_timespec __user *u_abs_timeout) |
|---|
| 98 |
{ |
|---|
| 99 |
struct timespec __user *u_ts; |
|---|
| 100 |
|
|---|
| 101 |
u_ts = compat_prepare_timeout(u_abs_timeout); |
|---|
| 102 |
if (IS_ERR(u_ts)) |
|---|
| 103 |
return -EFAULT; |
|---|
| 104 |
|
|---|
| 105 |
return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len, |
|---|
| 106 |
msg_prio, u_ts); |
|---|
| 107 |
} |
|---|
| 108 |
|
|---|
| 109 |
asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes, |
|---|
| 110 |
char __user *u_msg_ptr, |
|---|
| 111 |
size_t msg_len, unsigned int __user *u_msg_prio, |
|---|
| 112 |
const struct compat_timespec __user *u_abs_timeout) |
|---|
| 113 |
{ |
|---|
| 114 |
struct timespec __user *u_ts; |
|---|
| 115 |
|
|---|
| 116 |
u_ts = compat_prepare_timeout(u_abs_timeout); |
|---|
| 117 |
if (IS_ERR(u_ts)) |
|---|
| 118 |
return -EFAULT; |
|---|
| 119 |
|
|---|
| 120 |
return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len, |
|---|
| 121 |
u_msg_prio, u_ts); |
|---|
| 122 |
} |
|---|
| 123 |
|
|---|
| 124 |
static int get_compat_sigevent(struct sigevent *event, |
|---|
| 125 |
const struct compat_sigevent __user *u_event) |
|---|
| 126 |
{ |
|---|
| 127 |
if (verify_area(VERIFY_READ, u_event, sizeof(*u_event))) |
|---|
| 128 |
return -EFAULT; |
|---|
| 129 |
|
|---|
| 130 |
return __get_user(event->sigev_value.sival_int, |
|---|
| 131 |
&u_event->sigev_value.sival_int) |
|---|
| 132 |
| __get_user(event->sigev_signo, &u_event->sigev_signo) |
|---|
| 133 |
| __get_user(event->sigev_notify, &u_event->sigev_notify) |
|---|
| 134 |
| __get_user(event->sigev_notify_thread_id, |
|---|
| 135 |
&u_event->sigev_notify_thread_id); |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
asmlinkage long compat_sys_mq_notify(mqd_t mqdes, |
|---|
| 139 |
const struct compat_sigevent __user *u_notification) |
|---|
| 140 |
{ |
|---|
| 141 |
mm_segment_t oldfs; |
|---|
| 142 |
struct sigevent notification; |
|---|
| 143 |
char cookie[NOTIFY_COOKIE_LEN]; |
|---|
| 144 |
compat_uptr_t u_cookie; |
|---|
| 145 |
long ret; |
|---|
| 146 |
|
|---|
| 147 |
if (!u_notification) |
|---|
| 148 |
return sys_mq_notify(mqdes, 0); |
|---|
| 149 |
|
|---|
| 150 |
if (get_compat_sigevent(¬ification, u_notification)) |
|---|
| 151 |
return -EFAULT; |
|---|
| 152 |
|
|---|
| 153 |
if (notification.sigev_notify == SIGEV_THREAD) { |
|---|
| 154 |
u_cookie = (compat_uptr_t)notification.sigev_value.sival_int; |
|---|
| 155 |
if (copy_from_user(cookie, compat_ptr(u_cookie), |
|---|
| 156 |
NOTIFY_COOKIE_LEN)) { |
|---|
| 157 |
return -EFAULT; |
|---|
| 158 |
} |
|---|
| 159 |
notification.sigev_value.sival_ptr = cookie; |
|---|
| 160 |
} |
|---|
| 161 |
|
|---|
| 162 |
oldfs = get_fs(); |
|---|
| 163 |
set_fs(KERNEL_DS); |
|---|
| 164 |
ret = sys_mq_notify(mqdes, ¬ification); |
|---|
| 165 |
set_fs(oldfs); |
|---|
| 166 |
|
|---|
| 167 |
return ret; |
|---|
| 168 |
} |
|---|
| 169 |
|
|---|
| 170 |
asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, |
|---|
| 171 |
const struct compat_mq_attr __user *u_mqstat, |
|---|
| 172 |
struct compat_mq_attr __user *u_omqstat) |
|---|
| 173 |
{ |
|---|
| 174 |
struct mq_attr mqstat, omqstat; |
|---|
| 175 |
struct mq_attr *p_mqstat = 0, *p_omqstat = 0; |
|---|
| 176 |
mm_segment_t oldfs; |
|---|
| 177 |
long ret; |
|---|
| 178 |
|
|---|
| 179 |
if (u_mqstat) { |
|---|
| 180 |
p_mqstat = &mqstat; |
|---|
| 181 |
if (get_compat_mq_attr(p_mqstat, u_mqstat)) |
|---|
| 182 |
return -EFAULT; |
|---|
| 183 |
} |
|---|
| 184 |
|
|---|
| 185 |
if (u_omqstat) |
|---|
| 186 |
p_omqstat = &omqstat; |
|---|
| 187 |
|
|---|
| 188 |
oldfs = get_fs(); |
|---|
| 189 |
set_fs(KERNEL_DS); |
|---|
| 190 |
ret = sys_mq_getsetattr(mqdes, p_mqstat, p_omqstat); |
|---|
| 191 |
set_fs(oldfs); |
|---|
| 192 |
|
|---|
| 193 |
if (ret) |
|---|
| 194 |
return ret; |
|---|
| 195 |
|
|---|
| 196 |
return (u_omqstat) ? put_compat_mq_attr(&omqstat, u_omqstat) : 0; |
|---|
| 197 |
} |
|---|