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