Commit 95b58422 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse: ipc compat annotations and cleanups

	ipc compat code switched to compat_alloc_user_space() and annotated.
parent de54add3
......@@ -235,24 +235,13 @@ static inline int put_compat_semid_ds(struct semid64_ds *s,
return err;
}
static inline int do_semctl(int semid, int semnum, int cmd, union semun arg)
{
mm_segment_t old_fs;
int err;
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_semctl(semid, semnum, cmd, arg);
set_fs(old_fs);
return err;
}
long compat_sys_semctl(int first, int second, int third, void __user *uptr)
{
union semun fourth;
u32 pad;
int err, err2;
struct semid64_ds s64;
struct semid64_ds __user *up64;
int version = compat_ipc_parse_version(&third);
if (!uptr)
......@@ -279,16 +268,17 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr)
case IPC_STAT:
case SEM_STAT:
fourth.__pad = &s64;
err = do_semctl(first, second, third, fourth);
up64 = compat_alloc_user_space(sizeof(s64));
fourth.__pad = up64;
err = sys_semctl(first, second, third, fourth);
if (err < 0)
break;
if (version == IPC_64) {
if (copy_from_user(&s64, up64, sizeof(s64)))
err2 = -EFAULT;
else if (version == IPC_64)
err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
} else {
else
err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
}
if (err2)
err = -EFAULT;
break;
......@@ -299,11 +289,14 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr)
} else {
err = get_compat_semid_ds(&s64, compat_ptr(pad));
}
up64 = compat_alloc_user_space(sizeof(s64));
if (copy_to_user(up64, &s64, sizeof(s64)))
err = -EFAULT;
if (err)
break;
fourth.__pad = &s64;
err = do_semctl(first, second, third, fourth);
fourth.__pad = up64;
err = sys_semctl(first, second, third, fourth);
break;
default:
......@@ -315,39 +308,30 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr)
long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
{
struct msgbuf *p;
struct compat_msgbuf __user *up;
mm_segment_t old_fs;
int err;
struct msgbuf __user *p;
struct compat_msgbuf __user *up = uptr;
long type;
if (first < 0)
return -EINVAL;
if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf)))
return -EINVAL;
p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
if (!p)
return -ENOMEM;
err = -EFAULT;
up = uptr;
if (get_user(p->mtype, &up->mtype) ||
copy_from_user(p->mtext, &up->mtext, second))
goto out;
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_msgsnd(first, p, second, third);
set_fs(old_fs);
out:
kfree(p);
return err;
p = compat_alloc_user_space(second + sizeof(struct msgbuf));
if (get_user(type, &up->mtype) ||
put_user(type, &p->mtype) ||
copy_in_user(p->mtext, up->mtext, second))
return -EFAULT;
return sys_msgsnd(first, p, second, third);
}
long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
int version, void __user *uptr)
{
struct msgbuf *p;
struct msgbuf __user *p;
struct compat_msgbuf __user *up;
mm_segment_t old_fs;
long type;
int err;
if (first < 0)
......@@ -356,34 +340,25 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
return -EINVAL;
if (!version) {
struct compat_ipc_kludge __user *uipck = uptr;
struct compat_ipc_kludge ipck;
err = -EINVAL;
if (!uptr)
goto out;
err = -EFAULT;
if (copy_from_user (&ipck, uipck, sizeof(ipck)))
if (copy_from_user (&ipck, uptr, sizeof(ipck)))
goto out;
uptr = compat_ptr(ipck.msgp);
msgtyp = ipck.msgtyp;
}
err = -ENOMEM;
p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
if (!p)
goto out;
old_fs = get_fs();
set_fs(KERNEL_DS);
p = compat_alloc_user_space(second + sizeof(struct msgbuf));
err = sys_msgrcv(first, p, second, msgtyp, third);
set_fs(old_fs);
if (err < 0)
goto free_then_out;
goto out;
up = uptr;
if (put_user(p->mtype, &up->mtype) ||
__copy_to_user(&up->mtext, p->mtext, err))
if (get_user(type, &p->mtype) ||
put_user(type, &up->mtype) ||
copy_in_user(up->mtext, p->mtext, err))
err = -EFAULT;
free_then_out:
kfree(p);
out:
return err;
}
......@@ -450,24 +425,12 @@ static inline int put_compat_msqid_ds(struct msqid64_ds *m,
return err;
}
static inline int do_msgctl(int first, int second, void *buf)
{
mm_segment_t old_fs;
int err;
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_msgctl(first, second, buf);
set_fs(old_fs);
return err;
}
long compat_sys_msgctl(int first, int second, void __user *uptr)
{
int err, err2;
struct msqid64_ds m64;
int version = compat_ipc_parse_version(&second);
void __user *p;
switch (second & (~IPC_64)) {
case IPC_INFO:
......@@ -484,21 +447,25 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
}
if (err)
break;
err = do_msgctl(first, second, &m64);
p = compat_alloc_user_space(sizeof(m64));
if (copy_to_user(p, &m64, sizeof(m64)))
err = -EFAULT;
else
err = sys_msgctl(first, second, p);
break;
case IPC_STAT:
case MSG_STAT:
err = do_msgctl(first, second, &m64);
p = compat_alloc_user_space(sizeof(m64));
err = sys_msgctl(first, second, p);
if (err < 0)
break;
if (version == IPC_64) {
if (copy_from_user(&m64, p, sizeof(m64)))
err2 = -EFAULT;
else if (version == IPC_64)
err2 = put_compat_msqid64_ds(&m64, uptr);
} else {
else
err2 = put_compat_msqid_ds(&m64, uptr);
}
if (err2)
err = -EFAULT;
break;
......@@ -607,40 +574,29 @@ static inline int put_compat_shminfo(struct shminfo64 *smi,
err |= __put_user(smi->shmall, &up->shmall);
}
static inline int put_compat_shm_info(struct shm_info *si,
static inline int put_compat_shm_info(struct shm_info __user *ip,
struct compat_shm_info __user *uip)
{
int err;
struct shm_info si;
if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)))
if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
copy_from_user(&si, ip, sizeof(si)))
return -EFAULT;
err = __put_user(si->used_ids, &uip->used_ids);
err |= __put_user(si->shm_tot, &uip->shm_tot);
err |= __put_user(si->shm_rss, &uip->shm_rss);
err |= __put_user(si->shm_swp, &uip->shm_swp);
err |= __put_user(si->swap_attempts, &uip->swap_attempts);
err |= __put_user(si->swap_successes, &uip->swap_successes);
return err;
}
static inline int do_shmctl(int shmid, int cmd, void *buf)
{
mm_segment_t old_fs;
int err;
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_shmctl(shmid, cmd, buf);
set_fs(old_fs);
err = __put_user(si.used_ids, &uip->used_ids);
err |= __put_user(si.shm_tot, &uip->shm_tot);
err |= __put_user(si.shm_rss, &uip->shm_rss);
err |= __put_user(si.shm_swp, &uip->shm_swp);
err |= __put_user(si.swap_attempts, &uip->swap_attempts);
err |= __put_user(si.swap_successes, &uip->swap_successes);
return err;
}
long compat_sys_shmctl(int first, int second, void __user *uptr)
{
void __user *p;
struct shmid64_ds s64;
struct shminfo64 smi;
struct shm_info si;
int err, err2;
int version = compat_ipc_parse_version(&second);
......@@ -652,15 +608,16 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
break;
case IPC_INFO:
err = do_shmctl(first, second, &smi);
p = compat_alloc_user_space(sizeof(smi));
err = sys_shmctl(first, second, p);
if (err < 0)
break;
if (version == IPC_64) {
if (copy_from_user(&smi, p, sizeof(smi)))
err2 = -EFAULT;
else if (version == IPC_64)
err2 = put_compat_shminfo64(&smi, uptr);
} else {
else
err2 = put_compat_shminfo(&smi, uptr);
}
if (err2)
err = -EFAULT;
break;
......@@ -674,30 +631,35 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
}
if (err)
break;
err = do_shmctl(first, second, &s64);
p = compat_alloc_user_space(sizeof(s64));
if (copy_to_user(p, &s64, sizeof(s64)))
err = -EFAULT;
else
err = sys_shmctl(first, second, p);
break;
case IPC_STAT:
case SHM_STAT:
err = do_shmctl(first, second, &s64);
p = compat_alloc_user_space(sizeof(s64));
err = sys_shmctl(first, second, p);
if (err < 0)
break;
if (version == IPC_64) {
if (copy_from_user(&s64, p, sizeof(s64)))
err2 = -EFAULT;
else if (version == IPC_64)
err2 = put_compat_shmid64_ds(&s64, uptr);
} else {
else
err2 = put_compat_shmid_ds(&s64, uptr);
}
if (err2)
err = -EFAULT;
break;
case SHM_INFO:
err = do_shmctl(first, second, &si);
p = compat_alloc_user_space(sizeof(struct shm_info));
err = sys_shmctl(first, second, p);
if (err < 0)
break;
err2 = put_compat_shm_info(&si, uptr);
err2 = put_compat_shm_info(p, uptr);
if (err2)
err = -EFAULT;
break;
......@@ -712,24 +674,14 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
unsigned nsops, const struct compat_timespec __user *timeout)
{
struct timespec ts;
struct timespec __user *ts64;
/* parameter checking precedence should mirror sys_semtimedop() */
if (nsops < 1 || semid < 0)
return -EINVAL;
if (nsops > sc_semopm)
return -E2BIG;
if (!access_ok(VERIFY_READ, tsems, nsops * sizeof(struct sembuf)))
return -EFAULT;
if (!timeout)
return sys_semtimedop(semid, tsems, nsops, 0);
ts64 = compat_alloc_user_space(sizeof(*ts64));
if (get_compat_timespec(&ts, timeout))
return -EFAULT;
if (copy_to_user(ts64, &ts, sizeof(ts)))
return -EFAULT;
struct timespec __user *ts64 = NULL;
if (timeout) {
struct timespec ts;
ts64 = compat_alloc_user_space(sizeof(*ts64));
if (get_compat_timespec(&ts, timeout))
return -EFAULT;
if (copy_to_user(ts64, &ts, sizeof(ts)))
return -EFAULT;
}
return sys_semtimedop(semid, tsems, nsops, ts64);
}
......@@ -50,45 +50,29 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
int oflag, compat_mode_t mode,
struct compat_mq_attr __user *u_attr)
{
struct mq_attr attr;
mm_segment_t oldfs;
char *name;
long ret;
if ((oflag & O_CREAT) == 0 || !u_attr)
return sys_mq_open(u_name, oflag, mode, 0);
if (get_compat_mq_attr(&attr, u_attr))
return -EFAULT;
name = getname(u_name);
if (IS_ERR(name))
return PTR_ERR(name);
oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_mq_open(name, oflag, mode, &attr);
set_fs(oldfs);
putname(name);
return ret;
void __user *p = NULL;
if (u_attr && oflag & O_CREAT) {
struct mq_attr 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);
}
static struct timespec __user *compat_prepare_timeout(
const struct compat_timespec __user *u_abs_timeout)
static int compat_prepare_timeout(struct timespec __user * *p,
const struct compat_timespec __user *u)
{
struct timespec ts;
struct timespec __user *u_ts;
if (!u_abs_timeout)
if (!u) {
*p = NULL;
return 0;
u_ts = compat_alloc_user_space(sizeof(*u_ts));
if (get_compat_timespec(&ts, u_abs_timeout)
|| copy_to_user(u_ts, &ts, sizeof(*u_ts)))
return ERR_PTR(-EFAULT);
return u_ts;
}
*p = compat_alloc_user_space(sizeof(ts));
if (get_compat_timespec(&ts, u) || copy_to_user(*p, &ts, sizeof(ts)))
return -EFAULT;
return 0;
}
asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
......@@ -98,8 +82,7 @@ asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
{
struct timespec __user *u_ts;
u_ts = compat_prepare_timeout(u_abs_timeout);
if (IS_ERR(u_ts))
if (compat_prepare_timeout(&u_ts, u_abs_timeout))
return -EFAULT;
return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
......@@ -112,9 +95,7 @@ asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
const struct compat_timespec __user *u_abs_timeout)
{
struct timespec __user *u_ts;
u_ts = compat_prepare_timeout(u_abs_timeout);
if (IS_ERR(u_ts))
if (compat_prepare_timeout(&u_ts, u_abs_timeout))
return -EFAULT;
return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
......@@ -138,60 +119,42 @@ static int get_compat_sigevent(struct sigevent *event,
asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
const struct compat_sigevent __user *u_notification)
{
mm_segment_t oldfs;
struct sigevent notification;
char cookie[NOTIFY_COOKIE_LEN];
compat_uptr_t u_cookie;
long ret;
if (!u_notification)
return sys_mq_notify(mqdes, 0);
if (get_compat_sigevent(&notification, u_notification))
return -EFAULT;
if (notification.sigev_notify == SIGEV_THREAD) {
u_cookie = (compat_uptr_t)notification.sigev_value.sival_int;
if (copy_from_user(cookie, compat_ptr(u_cookie),
NOTIFY_COOKIE_LEN)) {
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;
}
notification.sigev_value.sival_ptr = cookie;
}
oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_mq_notify(mqdes, &notification);
set_fs(oldfs);
return ret;
return sys_mq_notify(mqdes, p);
}
asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
const struct compat_mq_attr __user *u_mqstat,
struct compat_mq_attr __user *u_omqstat)
{
struct mq_attr mqstat, omqstat;
struct mq_attr *p_mqstat = 0, *p_omqstat = 0;
mm_segment_t oldfs;
struct mq_attr mqstat;
struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
long ret;
if (u_mqstat) {
p_mqstat = &mqstat;
if (get_compat_mq_attr(p_mqstat, u_mqstat))
if (get_compat_mq_attr(&mqstat, u_mqstat) ||
copy_to_user(p, &mqstat, sizeof(mqstat)))
return -EFAULT;
}
if (u_omqstat)
p_omqstat = &omqstat;
oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_mq_getsetattr(mqdes, p_mqstat, p_omqstat);
set_fs(oldfs);
ret = sys_mq_getsetattr(mqdes,
u_mqstat ? p : NULL,
u_omqstat ? p + 1 : NULL);
if (ret)
return ret;
return (u_omqstat) ? put_compat_mq_attr(&omqstat, u_omqstat) : 0;
if (u_omqstat) {
if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
put_compat_mq_attr(&mqstat, u_omqstat))
return -EFAULT;
}
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment