summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 20:57:13 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 20:57:13 -0700
commitc856863988ebf612d159e55eeddbcd27de63b40d (patch)
tree88ce68d58f66679aabe029a93230280191b58d32
parent771d3feb4b79f8569bf0033b9075a434d0365fa2 (diff)
parent0d0606060baefdb13d3d80dba1b4c816b0676e16 (diff)
downloadlwn-c856863988ebf612d159e55eeddbcd27de63b40d.tar.gz
lwn-c856863988ebf612d159e55eeddbcd27de63b40d.zip
Merge branch 'misc.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc compat stuff updates from Al Viro: "This part is basically untangling various compat stuff. Compat syscalls moved to their native counterparts, getting rid of quite a bit of double-copying and/or set_fs() uses. A lot of field-by-field copyin/copyout killed off. - kernel/compat.c is much closer to containing just the copyin/copyout of compat structs. Not all compat syscalls are gone from it yet, but it's getting there. - ipc/compat_mq.c killed off completely. - block/compat_ioctl.c cleaned up; floppy compat ioctls moved to drivers/block/floppy.c where they belong. Yes, there are several drivers that implement some of the same ioctls. Some are m68k and one is 32bit-only pmac. drivers/block/floppy.c is the only one in that bunch that can be built on biarch" * 'misc.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: mqueue: move compat syscalls to native ones usbdevfs: get rid of field-by-field copyin compat_hdio_ioctl: get rid of set_fs() take floppy compat ioctls to sodding floppy.c ipmi: get rid of field-by-field __get_user() ipmi: get COMPAT_IPMICTL_RECEIVE_MSG in sync with the native one rt_sigtimedwait(): move compat to native select: switch compat_{get,put}_fd_set() to compat_{get,put}_bitmap() put_compat_rusage(): switch to copy_to_user() sigpending(): move compat to native getrlimit()/setrlimit(): move compat to native times(2): move compat to native compat_{get,put}_bitmap(): use unsafe_{get,put}_user() fb_get_fscreeninfo(): don't bother with do_fb_ioctl() do_sigaltstack(): lift copying to/from userland into callers take compat_sys_old_getrlimit() to native syscall trim __ARCH_WANT_SYS_OLD_GETRLIMIT
-rw-r--r--arch/alpha/include/asm/unistd.h1
-rw-r--r--arch/m32r/include/asm/unistd.h1
-rw-r--r--arch/mips/include/asm/unistd.h1
-rw-r--r--arch/parisc/include/asm/unistd.h1
-rw-r--r--arch/powerpc/include/asm/compat.h1
-rw-r--r--arch/s390/include/asm/compat.h1
-rw-r--r--arch/x86/include/asm/compat.h1
-rw-r--r--block/compat_ioctl.c355
-rw-r--r--drivers/block/floppy.c328
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c333
-rw-r--r--drivers/usb/core/devio.c48
-rw-r--r--drivers/video/fbdev/core/fbmem.c19
-rw-r--r--fs/select.c44
-rw-r--r--include/linux/compat.h3
-rw-r--r--include/linux/signal.h2
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/linux/time.h3
-rw-r--r--ipc/Makefile3
-rw-r--r--ipc/compat_mq.c138
-rw-r--r--ipc/mqueue.c349
-rw-r--r--kernel/compat.c267
-rw-r--r--kernel/signal.c155
-rw-r--r--kernel/sys.c100
23 files changed, 1019 insertions, 1137 deletions
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index a56e608db2f9..b37153ecf2ac 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -10,7 +10,6 @@
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_FORK
diff --git a/arch/m32r/include/asm/unistd.h b/arch/m32r/include/asm/unistd.h
index 59db80193454..de602533a3bd 100644
--- a/arch/m32r/include/asm/unistd.h
+++ b/arch/m32r/include/asm/unistd.h
@@ -18,7 +18,6 @@
#define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_FORK
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index e55813029d5a..3c09450908aa 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -35,7 +35,6 @@
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLD_UNAME
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 5f4c68daa261..7dc31c84dd37 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -156,7 +156,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
index 4f2df589ec1d..f256e1d14a14 100644
--- a/arch/powerpc/include/asm/compat.h
+++ b/arch/powerpc/include/asm/compat.h
@@ -109,7 +109,6 @@ struct compat_statfs {
int f_spare[4];
};
-#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t;
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index 0ddd37e6c29d..b9300f8aee10 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -178,7 +178,6 @@ struct compat_statfs64 {
u32 f_spare[4];
};
-#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t; /* at least 32 bits */
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 24118c0b4640..5343c19814b3 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -116,7 +116,6 @@ struct compat_statfs {
int f_spare[4];
};
-#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t; /* at least 32 bits */
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 04325b81c2b4..38554c2ea38a 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -4,7 +4,6 @@
#include <linux/cdrom.h>
#include <linux/compat.h>
#include <linux/elevator.h>
-#include <linux/fd.h>
#include <linux/hdreg.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
@@ -80,19 +79,16 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- mm_segment_t old_fs = get_fs();
- unsigned long kval;
- unsigned int __user *uvp;
+ unsigned long *__user p;
int error;
- set_fs(KERNEL_DS);
+ p = compat_alloc_user_space(sizeof(unsigned long));
error = __blkdev_driver_ioctl(bdev, mode,
- cmd, (unsigned long)(&kval));
- set_fs(old_fs);
-
+ cmd, (unsigned long)p);
if (error == 0) {
- uvp = compat_ptr(arg);
- if (put_user(kval, uvp))
+ unsigned int __user *uvp = compat_ptr(arg);
+ unsigned long v;
+ if (get_user(v, p) || put_user(v, uvp))
error = -EFAULT;
}
return error;
@@ -209,318 +205,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
#define BLKBSZSET_32 _IOW(0x12, 113, int)
#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
-struct compat_floppy_drive_params {
- char cmos;
- compat_ulong_t max_dtr;
- compat_ulong_t hlt;
- compat_ulong_t hut;
- compat_ulong_t srt;
- compat_ulong_t spinup;
- compat_ulong_t spindown;
- unsigned char spindown_offset;
- unsigned char select_delay;
- unsigned char rps;
- unsigned char tracks;
- compat_ulong_t timeout;
- unsigned char interleave_sect;
- struct floppy_max_errors max_errors;
- char flags;
- char read_track;
- short autodetect[8];
- compat_int_t checkfreq;
- compat_int_t native_format;
-};
-
-struct compat_floppy_drive_struct {
- signed char flags;
- compat_ulong_t spinup_date;
- compat_ulong_t select_date;
- compat_ulong_t first_read_date;
- short probed_format;
- short track;
- short maxblock;
- short maxtrack;
- compat_int_t generation;
- compat_int_t keep_data;
- compat_int_t fd_ref;
- compat_int_t fd_device;
- compat_int_t last_checked;
- compat_caddr_t dmabuf;
- compat_int_t bufblocks;
-};
-
-struct compat_floppy_fdc_state {
- compat_int_t spec1;
- compat_int_t spec2;
- compat_int_t dtr;
- unsigned char version;
- unsigned char dor;
- compat_ulong_t address;
- unsigned int rawcmd:2;
- unsigned int reset:1;
- unsigned int need_configure:1;
- unsigned int perp_mode:2;
- unsigned int has_fifo:1;
- unsigned int driver_version;
- unsigned char track[4];
-};
-
-struct compat_floppy_write_errors {
- unsigned int write_errors;
- compat_ulong_t first_error_sector;
- compat_int_t first_error_generation;
- compat_ulong_t last_error_sector;
- compat_int_t last_error_generation;
- compat_uint_t badness;
-};
-
-#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
-#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
-#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
-#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
-#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
-#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
-#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
-#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
-
-static struct {
- unsigned int cmd32;
- unsigned int cmd;
-} fd_ioctl_trans_table[] = {
- { FDSETPRM32, FDSETPRM },
- { FDDEFPRM32, FDDEFPRM },
- { FDGETPRM32, FDGETPRM },
- { FDSETDRVPRM32, FDSETDRVPRM },
- { FDGETDRVPRM32, FDGETDRVPRM },
- { FDGETDRVSTAT32, FDGETDRVSTAT },
- { FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
- { FDGETFDCSTAT32, FDGETFDCSTAT },
- { FDWERRORGET32, FDWERRORGET }
-};
-
-#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
-
-static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- mm_segment_t old_fs = get_fs();
- void *karg = NULL;
- unsigned int kcmd = 0;
- int i, err;
-
- for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
- if (cmd == fd_ioctl_trans_table[i].cmd32) {
- kcmd = fd_ioctl_trans_table[i].cmd;
- break;
- }
- if (!kcmd)
- return -EINVAL;
-
- switch (cmd) {
- case FDSETPRM32:
- case FDDEFPRM32:
- case FDGETPRM32:
- {
- compat_uptr_t name;
- struct compat_floppy_struct __user *uf;
- struct floppy_struct *f;
-
- uf = compat_ptr(arg);
- f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
- if (!karg)
- return -ENOMEM;
- if (cmd == FDGETPRM32)
- break;
- err = __get_user(f->size, &uf->size);
- err |= __get_user(f->sect, &uf->sect);
- err |= __get_user(f->head, &uf->head);
- err |= __get_user(f->track, &uf->track);
- err |= __get_user(f->stretch, &uf->stretch);
- err |= __get_user(f->gap, &uf->gap);
- err |= __get_user(f->rate, &uf->rate);
- err |= __get_user(f->spec1, &uf->spec1);
- err |= __get_user(f->fmt_gap, &uf->fmt_gap);
- err |= __get_user(name, &uf->name);
- f->name = compat_ptr(name);
- if (err) {
- err = -EFAULT;
- goto out;
- }
- break;
- }
- case FDSETDRVPRM32:
- case FDGETDRVPRM32:
- {
- struct compat_floppy_drive_params __user *uf;
- struct floppy_drive_params *f;
-
- uf = compat_ptr(arg);
- f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
- if (!karg)
- return -ENOMEM;
- if (cmd == FDGETDRVPRM32)
- break;
- err = __get_user(f->cmos, &uf->cmos);
- err |= __get_user(f->max_dtr, &uf->max_dtr);
- err |= __get_user(f->hlt, &uf->hlt);
- err |= __get_user(f->hut, &uf->hut);
- err |= __get_user(f->srt, &uf->srt);
- err |= __get_user(f->spinup, &uf->spinup);
- err |= __get_user(f->spindown, &uf->spindown);
- err |= __get_user(f->spindown_offset, &uf->spindown_offset);
- err |= __get_user(f->select_delay, &uf->select_delay);
- err |= __get_user(f->rps, &uf->rps);
- err |= __get_user(f->tracks, &uf->tracks);
- err |= __get_user(f->timeout, &uf->timeout);
- err |= __get_user(f->interleave_sect, &uf->interleave_sect);
- err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
- err |= __get_user(f->flags, &uf->flags);
- err |= __get_user(f->read_track, &uf->read_track);
- err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
- err |= __get_user(f->checkfreq, &uf->checkfreq);
- err |= __get_user(f->native_format, &uf->native_format);
- if (err) {
- err = -EFAULT;
- goto out;
- }
- break;
- }
- case FDGETDRVSTAT32:
- case FDPOLLDRVSTAT32:
- karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
- if (!karg)
- return -ENOMEM;
- break;
- case FDGETFDCSTAT32:
- karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
- if (!karg)
- return -ENOMEM;
- break;
- case FDWERRORGET32:
- karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
- if (!karg)
- return -ENOMEM;
- break;
- default:
- return -EINVAL;
- }
- set_fs(KERNEL_DS);
- err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
- set_fs(old_fs);
- if (err)
- goto out;
- switch (cmd) {
- case FDGETPRM32:
- {
- struct floppy_struct *f = karg;
- struct compat_floppy_struct __user *uf = compat_ptr(arg);
-
- err = __put_user(f->size, &uf->size);
- err |= __put_user(f->sect, &uf->sect);
- err |= __put_user(f->head, &uf->head);
- err |= __put_user(f->track, &uf->track);
- err |= __put_user(f->stretch, &uf->stretch);
- err |= __put_user(f->gap, &uf->gap);
- err |= __put_user(f->rate, &uf->rate);
- err |= __put_user(f->spec1, &uf->spec1);
- err |= __put_user(f->fmt_gap, &uf->fmt_gap);
- err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
- break;
- }
- case FDGETDRVPRM32:
- {
- struct compat_floppy_drive_params __user *uf;
- struct floppy_drive_params *f = karg;
-
- uf = compat_ptr(arg);
- err = __put_user(f->cmos, &uf->cmos);
- err |= __put_user(f->max_dtr, &uf->max_dtr);
- err |= __put_user(f->hlt, &uf->hlt);
- err |= __put_user(f->hut, &uf->hut);
- err |= __put_user(f->srt, &uf->srt);
- err |= __put_user(f->spinup, &uf->spinup);
- err |= __put_user(f->spindown, &uf->spindown);
- err |= __put_user(f->spindown_offset, &uf->spindown_offset);
- err |= __put_user(f->select_delay, &uf->select_delay);
- err |= __put_user(f->rps, &uf->rps);
- err |= __put_user(f->tracks, &uf->tracks);
- err |= __put_user(f->timeout, &uf->timeout);
- err |= __put_user(f->interleave_sect, &uf->interleave_sect);
- err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
- err |= __put_user(f->flags, &uf->flags);
- err |= __put_user(f->read_track, &uf->read_track);
- err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
- err |= __put_user(f->checkfreq, &uf->checkfreq);
- err |= __put_user(f->native_format, &uf->native_format);
- break;
- }
- case FDGETDRVSTAT32:
- case FDPOLLDRVSTAT32:
- {
- struct compat_floppy_drive_struct __user *uf;
- struct floppy_drive_struct *f = karg;
-
- uf = compat_ptr(arg);
- err = __put_user(f->flags, &uf->flags);
- err |= __put_user(f->spinup_date, &uf->spinup_date);
- err |= __put_user(f->select_date, &uf->select_date);
- err |= __put_user(f->first_read_date, &uf->first_read_date);
- err |= __put_user(f->probed_format, &uf->probed_format);
- err |= __put_user(f->track, &uf->track);
- err |= __put_user(f->maxblock, &uf->maxblock);
- err |= __put_user(f->maxtrack, &uf->maxtrack);
- err |= __put_user(f->generation, &uf->generation);
- err |= __put_user(f->keep_data, &uf->keep_data);
- err |= __put_user(f->fd_ref, &uf->fd_ref);
- err |= __put_user(f->fd_device, &uf->fd_device);
- err |= __put_user(f->last_checked, &uf->last_checked);
- err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
- err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
- break;
- }
- case FDGETFDCSTAT32:
- {
- struct compat_floppy_fdc_state __user *uf;
- struct floppy_fdc_state *f = karg;
-
- uf = compat_ptr(arg);
- err = __put_user(f->spec1, &uf->spec1);
- err |= __put_user(f->spec2, &uf->spec2);
- err |= __put_user(f->dtr, &uf->dtr);
- err |= __put_user(f->version, &uf->version);
- err |= __put_user(f->dor, &uf->dor);
- err |= __put_user(f->address, &uf->address);
- err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
- (char *)&f->address + sizeof(f->address), sizeof(int));
- err |= __put_user(f->driver_version, &uf->driver_version);
- err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
- break;
- }
- case FDWERRORGET32:
- {
- struct compat_floppy_write_errors __user *uf;
- struct floppy_write_errors *f = karg;
-
- uf = compat_ptr(arg);
- err = __put_user(f->write_errors, &uf->write_errors);
- err |= __put_user(f->first_error_sector, &uf->first_error_sector);
- err |= __put_user(f->first_error_generation, &uf->first_error_generation);
- err |= __put_user(f->last_error_sector, &uf->last_error_sector);
- err |= __put_user(f->last_error_generation, &uf->last_error_generation);
- err |= __put_user(f->badness, &uf->badness);
- break;
- }
- default:
- break;
- }
- if (err)
- err = -EFAULT;
-
-out:
- kfree(karg);
- return err;
-}
-
static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg)
{
@@ -537,16 +221,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
case HDIO_GET_ADDRESS:
case HDIO_GET_BUSSTATE:
return compat_hdio_ioctl(bdev, mode, cmd, arg);
- case FDSETPRM32:
- case FDDEFPRM32:
- case FDGETPRM32:
- case FDSETDRVPRM32:
- case FDGETDRVPRM32:
- case FDGETDRVSTAT32:
- case FDPOLLDRVSTAT32:
- case FDGETFDCSTAT32:
- case FDWERRORGET32:
- return compat_fd_ioctl(bdev, mode, cmd, arg);
case CDROMREADAUDIO:
return compat_cdrom_read_audio(bdev, mode, cmd, arg);
case CDROM_SEND_PACKET:
@@ -566,23 +240,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
case HDIO_DRIVE_CMD:
/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
case 0x330:
- /* 0x02 -- Floppy ioctls */
- case FDMSGON:
- case FDMSGOFF:
- case FDSETEMSGTRESH:
- case FDFLUSH:
- case FDWERRORCLR:
- case FDSETMAXERRS:
- case FDGETMAXERRS:
- case FDGETDRVTYP:
- case FDEJECT:
- case FDCLRPRM:
- case FDFMTBEG:
- case FDFMTEND:
- case FDRESET:
- case FDTWADDLE:
- case FDFMTTRK:
- case FDRAWCMD:
/* CDROM stuff */
case CDROMPAUSE:
case CDROMRESUME:
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index ce823647a9c4..9c00f29e40c1 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -192,6 +192,7 @@ static int print_unex = 1;
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/async.h>
+#include <linux/compat.h>
/*
* PS/2 floppies have much slower step rates than regular floppies.
@@ -3568,6 +3569,330 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
return ret;
}
+#ifdef CONFIG_COMPAT
+
+struct compat_floppy_drive_params {
+ char cmos;
+ compat_ulong_t max_dtr;
+ compat_ulong_t hlt;
+ compat_ulong_t hut;
+ compat_ulong_t srt;
+ compat_ulong_t spinup;
+ compat_ulong_t spindown;
+ unsigned char spindown_offset;
+ unsigned char select_delay;
+ unsigned char rps;
+ unsigned char tracks;
+ compat_ulong_t timeout;
+ unsigned char interleave_sect;
+ struct floppy_max_errors max_errors;
+ char flags;
+ char read_track;
+ short autodetect[8];
+ compat_int_t checkfreq;
+ compat_int_t native_format;
+};
+
+struct compat_floppy_drive_struct {
+ signed char flags;
+ compat_ulong_t spinup_date;
+ compat_ulong_t select_date;
+ compat_ulong_t first_read_date;
+ short probed_format;
+ short track;
+ short maxblock;
+ short maxtrack;
+ compat_int_t generation;
+ compat_int_t keep_data;
+ compat_int_t fd_ref;
+ compat_int_t fd_device;
+ compat_int_t last_checked;
+ compat_caddr_t dmabuf;
+ compat_int_t bufblocks;
+};
+
+struct compat_floppy_fdc_state {
+ compat_int_t spec1;
+ compat_int_t spec2;
+ compat_int_t dtr;
+ unsigned char version;
+ unsigned char dor;
+ compat_ulong_t address;
+ unsigned int rawcmd:2;
+ unsigned int reset:1;
+ unsigned int need_configure:1;
+ unsigned int perp_mode:2;
+ unsigned int has_fifo:1;
+ unsigned int driver_version;
+ unsigned char track[4];
+};
+
+struct compat_floppy_write_errors {
+ unsigned int write_errors;
+ compat_ulong_t first_error_sector;
+ compat_int_t first_error_generation;
+ compat_ulong_t last_error_sector;
+ compat_int_t last_error_generation;
+ compat_uint_t badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
+#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
+#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
+
+static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
+ struct compat_floppy_struct __user *arg)
+{
+ struct floppy_struct v;
+ int drive, type;
+ int err;
+
+ BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
+ offsetof(struct compat_floppy_struct, name));
+
+ if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
+ return -EPERM;
+
+ memset(&v, 0, sizeof(struct floppy_struct));
+ if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
+ return -EFAULT;
+
+ mutex_lock(&floppy_mutex);
+ drive = (long)bdev->bd_disk->private_data;
+ type = ITYPE(UDRS->fd_device);
+ err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
+ &v, drive, type, bdev);
+ mutex_unlock(&floppy_mutex);
+ return err;
+}
+
+static int compat_get_prm(int drive,
+ struct compat_floppy_struct __user *arg)
+{
+ struct compat_floppy_struct v;
+ struct floppy_struct *p;
+ int err;
+
+ memset(&v, 0, sizeof(v));
+ mutex_lock(&floppy_mutex);
+ err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
+ if (err) {
+ mutex_unlock(&floppy_mutex);
+ return err;
+ }
+ memcpy(&v, p, offsetof(struct floppy_struct, name));
+ mutex_unlock(&floppy_mutex);
+ if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
+ return -EFAULT;
+ return 0;
+}
+
+static int compat_setdrvprm(int drive,
+ struct compat_floppy_drive_params __user *arg)
+{
+ struct compat_floppy_drive_params v;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
+ mutex_lock(&floppy_mutex);
+ UDP->cmos = v.cmos;
+ UDP->max_dtr = v.max_dtr;
+ UDP->hlt = v.hlt;
+ UDP->hut = v.hut;
+ UDP->srt = v.srt;
+ UDP->spinup = v.spinup;
+ UDP->spindown = v.spindown;
+ UDP->spindown_offset = v.spindown_offset;
+ UDP->select_delay = v.select_delay;
+ UDP->rps = v.rps;
+ UDP->tracks = v.tracks;
+ UDP->timeout = v.timeout;
+ UDP->interleave_sect = v.interleave_sect;
+ UDP->max_errors = v.max_errors;
+ UDP->flags = v.flags;
+ UDP->read_track = v.read_track;
+ memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
+ UDP->checkfreq = v.checkfreq;
+ UDP->native_format = v.native_format;
+ mutex_unlock(&floppy_mutex);
+ return 0;
+}
+
+static int compat_getdrvprm(int drive,
+ struct compat_floppy_drive_params __user *arg)
+{
+ struct compat_floppy_drive_params v;
+
+ memset(&v, 0, sizeof(struct compat_floppy_drive_params));
+ mutex_lock(&floppy_mutex);
+ v.cmos = UDP->cmos;
+ v.max_dtr = UDP->max_dtr;
+ v.hlt = UDP->hlt;
+ v.hut = UDP->hut;
+ v.srt = UDP->srt;
+ v.spinup = UDP->spinup;
+ v.spindown = UDP->spindown;
+ v.spindown_offset = UDP->spindown_offset;
+ v.select_delay = UDP->select_delay;
+ v.rps = UDP->rps;
+ v.tracks = UDP->tracks;
+ v.timeout = UDP->timeout;
+ v.interleave_sect = UDP->interleave_sect;
+ v.max_errors = UDP->max_errors;
+ v.flags = UDP->flags;
+ v.read_track = UDP->read_track;
+ memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
+ v.checkfreq = UDP->checkfreq;
+ v.native_format = UDP->native_format;
+ mutex_unlock(&floppy_mutex);
+
+ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
+ return 0;
+}
+
+static int compat_getdrvstat(int drive, bool poll,
+ struct compat_floppy_drive_struct __user *arg)
+{
+ struct compat_floppy_drive_struct v;
+
+ memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
+ mutex_lock(&floppy_mutex);
+
+ if (poll) {
+ if (lock_fdc(drive))
+ goto Eintr;
+ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
+ goto Eintr;
+ process_fd_request();
+ }
+ v.spinup_date = UDRS->spinup_date;
+ v.select_date = UDRS->select_date;
+ v.first_read_date = UDRS->first_read_date;
+ v.probed_format = UDRS->probed_format;
+ v.track = UDRS->track;
+ v.maxblock = UDRS->maxblock;
+ v.maxtrack = UDRS->maxtrack;
+ v.generation = UDRS->generation;
+ v.keep_data = UDRS->keep_data;
+ v.fd_ref = UDRS->fd_ref;
+ v.fd_device = UDRS->fd_device;
+ v.last_checked = UDRS->last_checked;
+ v.dmabuf = (uintptr_t)UDRS->dmabuf;
+ v.bufblocks = UDRS->bufblocks;
+ mutex_unlock(&floppy_mutex);
+
+ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
+ return -EFAULT;
+ return 0;
+Eintr:
+ mutex_unlock(&floppy_mutex);
+ return -EINTR;
+}
+
+static int compat_getfdcstat(int drive,
+ struct compat_floppy_fdc_state __user *arg)
+{
+ struct compat_floppy_fdc_state v32;
+ struct floppy_fdc_state v;
+
+ mutex_lock(&floppy_mutex);
+ v = *UFDCS;
+ mutex_unlock(&floppy_mutex);
+
+ memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
+ v32.spec1 = v.spec1;
+ v32.spec2 = v.spec2;
+ v32.dtr = v.dtr;
+ v32.version = v.version;
+ v32.dor = v.dor;
+ v32.address = v.address;
+ v32.rawcmd = v.rawcmd;
+ v32.reset = v.reset;
+ v32.need_configure = v.need_configure;
+ v32.perp_mode = v.perp_mode;
+ v32.has_fifo = v.has_fifo;
+ v32.driver_version = v.driver_version;
+ memcpy(v32.track, v.track, 4);
+ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
+ return -EFAULT;
+ return 0;
+}
+
+static int compat_werrorget(int drive,
+ struct compat_floppy_write_errors __user *arg)
+{
+ struct compat_floppy_write_errors v32;
+ struct floppy_write_errors v;
+
+ memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
+ mutex_lock(&floppy_mutex);
+ v = *UDRWE;
+ mutex_unlock(&floppy_mutex);
+ v32.write_errors = v.write_errors;
+ v32.first_error_sector = v.first_error_sector;
+ v32.first_error_generation = v.first_error_generation;
+ v32.last_error_sector = v.last_error_sector;
+ v32.last_error_generation = v.last_error_generation;
+ v32.badness = v.badness;
+ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
+ return -EFAULT;
+ return 0;
+}
+
+static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
+ unsigned long param)
+{
+ int drive = (long)bdev->bd_disk->private_data;
+ switch (cmd) {
+ case FDMSGON:
+ case FDMSGOFF:
+ case FDSETEMSGTRESH:
+ case FDFLUSH:
+ case FDWERRORCLR:
+ case FDEJECT:
+ case FDCLRPRM:
+ case FDFMTBEG:
+ case FDRESET:
+ case FDTWADDLE:
+ return fd_ioctl(bdev, mode, cmd, param);
+ case FDSETMAXERRS:
+ case FDGETMAXERRS:
+ case FDGETDRVTYP:
+ case FDFMTEND:
+ case FDFMTTRK:
+ case FDRAWCMD:
+ return fd_ioctl(bdev, mode, cmd,
+ (unsigned long)compat_ptr(param));
+ case FDSETPRM32:
+ case FDDEFPRM32:
+ return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
+ case FDGETPRM32:
+ return compat_get_prm(drive, compat_ptr(param));
+ case FDSETDRVPRM32:
+ return compat_setdrvprm(drive, compat_ptr(param));
+ case FDGETDRVPRM32:
+ return compat_getdrvprm(drive, compat_ptr(param));
+ case FDPOLLDRVSTAT32:
+ return compat_getdrvstat(drive, true, compat_ptr(param));
+ case FDGETDRVSTAT32:
+ return compat_getdrvstat(drive, false, compat_ptr(param));
+ case FDGETFDCSTAT32:
+ return compat_getfdcstat(drive, compat_ptr(param));
+ case FDWERRORGET32:
+ return compat_werrorget(drive, compat_ptr(param));
+ }
+ return -EINVAL;
+}
+#endif
+
static void __init config_types(void)
{
bool has_drive = false;
@@ -3885,6 +4210,9 @@ static const struct block_device_operations floppy_fops = {
.getgeo = fd_getgeo,
.check_events = floppy_check_events,
.revalidate_disk = floppy_revalidate,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fd_compat_ioctl,
+#endif
};
/*
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index f45119c5337d..2ffca4232686 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -231,6 +231,102 @@ static int handle_send_req(ipmi_user_t user,
return rv;
}
+static int handle_recv(struct ipmi_file_private *priv,
+ bool trunc, struct ipmi_recv *rsp,
+ int (*copyout)(struct ipmi_recv *, void __user *),
+ void __user *to)
+{
+ int addr_len;
+ struct list_head *entry;
+ struct ipmi_recv_msg *msg;
+ unsigned long flags;
+ int rv = 0;
+
+ /* We claim a mutex because we don't want two
+ users getting something from the queue at a time.
+ Since we have to release the spinlock before we can
+ copy the data to the user, it's possible another
+ user will grab something from the queue, too. Then
+ the messages might get out of order if something
+ fails and the message gets put back onto the
+ queue. This mutex prevents that problem. */
+ mutex_lock(&priv->recv_mutex);
+
+ /* Grab the message off the list. */
+ spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+ if (list_empty(&(priv->recv_msgs))) {
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+ rv = -EAGAIN;
+ goto recv_err;
+ }
+ entry = priv->recv_msgs.next;
+ msg = list_entry(entry, struct ipmi_recv_msg, link);
+ list_del(entry);
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+
+ addr_len = ipmi_addr_length(msg->addr.addr_type);
+ if (rsp->addr_len < addr_len)
+ {
+ rv = -EINVAL;
+ goto recv_putback_on_err;
+ }
+
+ if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
+ rv = -EFAULT;
+ goto recv_putback_on_err;
+ }
+ rsp->addr_len = addr_len;
+
+ rsp->recv_type = msg->recv_type;
+ rsp->msgid = msg->msgid;
+ rsp->msg.netfn = msg->msg.netfn;
+ rsp->msg.cmd = msg->msg.cmd;
+
+ if (msg->msg.data_len > 0) {
+ if (rsp->msg.data_len < msg->msg.data_len) {
+ rv = -EMSGSIZE;
+ if (trunc)
+ msg->msg.data_len = rsp->msg.data_len;
+ else
+ goto recv_putback_on_err;
+ }
+
+ if (copy_to_user(rsp->msg.data,
+ msg->msg.data,
+ msg->msg.data_len))
+ {
+ rv = -EFAULT;
+ goto recv_putback_on_err;
+ }
+ rsp->msg.data_len = msg->msg.data_len;
+ } else {
+ rsp->msg.data_len = 0;
+ }
+
+ rv = copyout(rsp, to);
+ if (rv)
+ goto recv_putback_on_err;
+
+ mutex_unlock(&priv->recv_mutex);
+ ipmi_free_recv_msg(msg);
+ return 0;
+
+recv_putback_on_err:
+ /* If we got an error, put the message back onto
+ the head of the queue. */
+ spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+ list_add(entry, &(priv->recv_msgs));
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+recv_err:
+ mutex_unlock(&priv->recv_mutex);
+ return rv;
+}
+
+static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
+{
+ return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
+}
+
static int ipmi_ioctl(struct file *file,
unsigned int cmd,
unsigned long data)
@@ -277,100 +373,12 @@ static int ipmi_ioctl(struct file *file,
case IPMICTL_RECEIVE_MSG_TRUNC:
{
struct ipmi_recv rsp;
- int addr_len;
- struct list_head *entry;
- struct ipmi_recv_msg *msg;
- unsigned long flags;
-
-
- rv = 0;
- if (copy_from_user(&rsp, arg, sizeof(rsp))) {
- rv = -EFAULT;
- break;
- }
-
- /* We claim a mutex because we don't want two
- users getting something from the queue at a time.
- Since we have to release the spinlock before we can
- copy the data to the user, it's possible another
- user will grab something from the queue, too. Then
- the messages might get out of order if something
- fails and the message gets put back onto the
- queue. This mutex prevents that problem. */
- mutex_lock(&priv->recv_mutex);
-
- /* Grab the message off the list. */
- spin_lock_irqsave(&(priv->recv_msg_lock), flags);
- if (list_empty(&(priv->recv_msgs))) {
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
- rv = -EAGAIN;
- goto recv_err;
- }
- entry = priv->recv_msgs.next;
- msg = list_entry(entry, struct ipmi_recv_msg, link);
- list_del(entry);
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
-
- addr_len = ipmi_addr_length(msg->addr.addr_type);
- if (rsp.addr_len < addr_len)
- {
- rv = -EINVAL;
- goto recv_putback_on_err;
- }
- if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
+ if (copy_from_user(&rsp, arg, sizeof(rsp)))
rv = -EFAULT;
- goto recv_putback_on_err;
- }
- rsp.addr_len = addr_len;
-
- rsp.recv_type = msg->recv_type;
- rsp.msgid = msg->msgid;
- rsp.msg.netfn = msg->msg.netfn;
- rsp.msg.cmd = msg->msg.cmd;
-
- if (msg->msg.data_len > 0) {
- if (rsp.msg.data_len < msg->msg.data_len) {
- rv = -EMSGSIZE;
- if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
- msg->msg.data_len = rsp.msg.data_len;
- } else {
- goto recv_putback_on_err;
- }
- }
-
- if (copy_to_user(rsp.msg.data,
- msg->msg.data,
- msg->msg.data_len))
- {
- rv = -EFAULT;
- goto recv_putback_on_err;
- }
- rsp.msg.data_len = msg->msg.data_len;
- } else {
- rsp.msg.data_len = 0;
- }
-
- if (copy_to_user(arg, &rsp, sizeof(rsp))) {
- rv = -EFAULT;
- goto recv_putback_on_err;
- }
-
- mutex_unlock(&priv->recv_mutex);
- ipmi_free_recv_msg(msg);
- break;
-
- recv_putback_on_err:
- /* If we got an error, put the message back onto
- the head of the queue. */
- spin_lock_irqsave(&(priv->recv_msg_lock), flags);
- list_add(entry, &(priv->recv_msgs));
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
- mutex_unlock(&priv->recv_mutex);
- break;
-
- recv_err:
- mutex_unlock(&priv->recv_mutex);
+ else
+ rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
+ &rsp, copyout_recv, arg);
break;
}
@@ -696,85 +704,56 @@ struct compat_ipmi_req_settime {
/*
* Define some helper functions for copying IPMI data
*/
-static long get_compat_ipmi_msg(struct ipmi_msg *p64,
- struct compat_ipmi_msg __user *p32)
-{
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(p64->netfn, &p32->netfn) ||
- __get_user(p64->cmd, &p32->cmd) ||
- __get_user(p64->data_len, &p32->data_len) ||
- __get_user(tmp, &p32->data))
- return -EFAULT;
- p64->data = compat_ptr(tmp);
- return 0;
-}
-
-static long put_compat_ipmi_msg(struct ipmi_msg *p64,
- struct compat_ipmi_msg __user *p32)
+static void get_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg *p32)
{
- if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
- __put_user(p64->netfn, &p32->netfn) ||
- __put_user(p64->cmd, &p32->cmd) ||
- __put_user(p64->data_len, &p32->data_len))
- return -EFAULT;
- return 0;
+ p64->netfn = p32->netfn;
+ p64->cmd = p32->cmd;
+ p64->data_len = p32->data_len;
+ p64->data = compat_ptr(p32->data);
}
-static long get_compat_ipmi_req(struct ipmi_req *p64,
- struct compat_ipmi_req __user *p32)
+static void get_compat_ipmi_req(struct ipmi_req *p64,
+ struct compat_ipmi_req *p32)
{
-
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(tmp, &p32->addr) ||
- __get_user(p64->addr_len, &p32->addr_len) ||
- __get_user(p64->msgid, &p32->msgid) ||
- get_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- p64->addr = compat_ptr(tmp);
- return 0;
+ p64->addr = compat_ptr(p32->addr);
+ p64->addr_len = p32->addr_len;
+ p64->msgid = p32->msgid;
+ get_compat_ipmi_msg(&p64->msg, &p32->msg);
}
-static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
- struct compat_ipmi_req_settime __user *p32)
+static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
+ struct compat_ipmi_req_settime *p32)
{
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- get_compat_ipmi_req(&p64->req, &p32->req) ||
- __get_user(p64->retries, &p32->retries) ||
- __get_user(p64->retry_time_ms, &p32->retry_time_ms))
- return -EFAULT;
- return 0;
+ get_compat_ipmi_req(&p64->req, &p32->req);
+ p64->retries = p32->retries;
+ p64->retry_time_ms = p32->retry_time_ms;
}
-static long get_compat_ipmi_recv(struct ipmi_recv *p64,
- struct compat_ipmi_recv __user *p32)
+static void get_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv *p32)
{
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(p64->recv_type, &p32->recv_type) ||
- __get_user(tmp, &p32->addr) ||
- __get_user(p64->addr_len, &p32->addr_len) ||
- __get_user(p64->msgid, &p32->msgid) ||
- get_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- p64->addr = compat_ptr(tmp);
- return 0;
+ memset(p64, 0, sizeof(struct ipmi_recv));
+ p64->recv_type = p32->recv_type;
+ p64->addr = compat_ptr(p32->addr);
+ p64->addr_len = p32->addr_len;
+ p64->msgid = p32->msgid;
+ get_compat_ipmi_msg(&p64->msg, &p32->msg);
}
-static long put_compat_ipmi_recv(struct ipmi_recv *p64,
- struct compat_ipmi_recv __user *p32)
+static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
{
- if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
- __put_user(p64->recv_type, &p32->recv_type) ||
- __put_user(p64->addr_len, &p32->addr_len) ||
- __put_user(p64->msgid, &p32->msgid) ||
- put_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- return 0;
+ struct compat_ipmi_recv v32;
+ memset(&v32, 0, sizeof(struct compat_ipmi_recv));
+ v32.recv_type = p64->recv_type;
+ v32.addr = ptr_to_compat(p64->addr);
+ v32.addr_len = p64->addr_len;
+ v32.msgid = p64->msgid;
+ v32.msg.netfn = p64->msg.netfn;
+ v32.msg.cmd = p64->msg.cmd;
+ v32.msg.data_len = p64->msg.data_len;
+ v32.msg.data = ptr_to_compat(p64->msg.data);
+ return copy_to_user(to, &v32, sizeof(v32)) ? -EFAULT : 0;
}
/*
@@ -783,17 +762,19 @@ static long put_compat_ipmi_recv(struct ipmi_recv *p64,
static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
- int rc;
struct ipmi_file_private *priv = filep->private_data;
switch(cmd) {
case COMPAT_IPMICTL_SEND_COMMAND:
{
struct ipmi_req rp;
+ struct compat_ipmi_req r32;
- if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
+ if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
return -EFAULT;
+ get_compat_ipmi_req(&rp, &r32);
+
return handle_send_req(priv->user, &rp,
priv->default_retries,
priv->default_retry_time_ms);
@@ -801,42 +782,30 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
{
struct ipmi_req_settime sp;
+ struct compat_ipmi_req_settime sp32;
- if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
+ if (copy_from_user(&sp32, compat_ptr(arg), sizeof(sp32)))
return -EFAULT;
+ get_compat_ipmi_req_settime(&sp, &sp32);
+
return handle_send_req(priv->user, &sp.req,
sp.retries, sp.retry_time_ms);
}
case COMPAT_IPMICTL_RECEIVE_MSG:
case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
{
- struct ipmi_recv __user *precv64;
struct ipmi_recv recv64;
+ struct compat_ipmi_recv recv32;
- memset(&recv64, 0, sizeof(recv64));
- if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ if (copy_from_user(&recv32, compat_ptr(arg), sizeof(recv32)))
return -EFAULT;
- precv64 = compat_alloc_user_space(sizeof(recv64));
- if (copy_to_user(precv64, &recv64, sizeof(recv64)))
- return -EFAULT;
-
- rc = ipmi_ioctl(filep,
- ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
- ? IPMICTL_RECEIVE_MSG
- : IPMICTL_RECEIVE_MSG_TRUNC),
- (unsigned long) precv64);
- if (rc != 0)
- return rc;
-
- if (copy_from_user(&recv64, precv64, sizeof(recv64)))
- return -EFAULT;
-
- if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
- return -EFAULT;
+ get_compat_ipmi_recv(&recv64, &recv32);
- return rc;
+ return handle_recv(priv,
+ cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
+ &recv64, copyout_recv32, compat_ptr(arg));
}
default:
return ipmi_ioctl(filep, cmd, arg);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0e7d0e81a7cb..ebe27595c4af 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1966,27 +1966,21 @@ static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *a
static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
{
- __u32 uptr;
- if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) ||
- __get_user(kurb->type, &uurb->type) ||
- __get_user(kurb->endpoint, &uurb->endpoint) ||
- __get_user(kurb->status, &uurb->status) ||
- __get_user(kurb->flags, &uurb->flags) ||
- __get_user(kurb->buffer_length, &uurb->buffer_length) ||
- __get_user(kurb->actual_length, &uurb->actual_length) ||
- __get_user(kurb->start_frame, &uurb->start_frame) ||
- __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
- __get_user(kurb->error_count, &uurb->error_count) ||
- __get_user(kurb->signr, &uurb->signr))
+ struct usbdevfs_urb32 urb32;
+ if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
return -EFAULT;
-
- if (__get_user(uptr, &uurb->buffer))
- return -EFAULT;
- kurb->buffer = compat_ptr(uptr);
- if (__get_user(uptr, &uurb->usercontext))
- return -EFAULT;
- kurb->usercontext = compat_ptr(uptr);
-
+ kurb->type = urb32.type;
+ kurb->endpoint = urb32.endpoint;
+ kurb->status = urb32.status;
+ kurb->flags = urb32.flags;
+ kurb->buffer = compat_ptr(urb32.buffer);
+ kurb->buffer_length = urb32.buffer_length;
+ kurb->actual_length = urb32.actual_length;
+ kurb->start_frame = urb32.start_frame;
+ kurb->number_of_packets = urb32.number_of_packets;
+ kurb->error_count = urb32.error_count;
+ kurb->signr = urb32.signr;
+ kurb->usercontext = compat_ptr(urb32.usercontext);
return 0;
}
@@ -2198,18 +2192,14 @@ static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
#ifdef CONFIG_COMPAT
static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
{
- struct usbdevfs_ioctl32 __user *uioc;
+ struct usbdevfs_ioctl32 ioc32;
struct usbdevfs_ioctl ctrl;
- u32 udata;
- uioc = compat_ptr((long)arg);
- if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) ||
- __get_user(ctrl.ifno, &uioc->ifno) ||
- __get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
- __get_user(udata, &uioc->data))
+ if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
return -EFAULT;
- ctrl.data = compat_ptr(udata);
-
+ ctrl.ifno = ioc32.ifno;
+ ctrl.ioctl_code = ioc32.ioctl_code;
+ ctrl.data = compat_ptr(ioc32.data);
return proc_ioctl(ps, &ctrl);
}
#endif
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 069fe7960df1..5324358f110f 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1331,22 +1331,13 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
- mm_segment_t old_fs;
struct fb_fix_screeninfo fix;
- struct fb_fix_screeninfo32 __user *fix32;
- int err;
-
- fix32 = compat_ptr(arg);
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
- set_fs(old_fs);
- if (!err)
- err = do_fscreeninfo_to_user(&fix, fix32);
-
- return err;
+ if (!lock_fb_info(info))
+ return -ENODEV;
+ fix = info->fix;
+ unlock_fb_info(info);
+ return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
}
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
diff --git a/fs/select.c b/fs/select.c
index 5b524a977d91..9d5f15ed87fe 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -1161,59 +1161,25 @@ static
int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset)
{
- nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
if (ufdset) {
- unsigned long odd;
-
- if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
- return -EFAULT;
-
- odd = nr & 1UL;
- nr &= ~1UL;
- while (nr) {
- unsigned long h, l;
- if (__get_user(l, ufdset) || __get_user(h, ufdset+1))
- return -EFAULT;
- ufdset += 2;
- *fdset++ = h << 32 | l;
- nr -= 2;
- }
- if (odd && __get_user(*fdset, ufdset))
- return -EFAULT;
+ return compat_get_bitmap(fdset, ufdset, nr);
} else {
/* Tricky, must clear full unsigned long in the
- * kernel fdset at the end, this makes sure that
+ * kernel fdset at the end, ALIGN makes sure that
* actually happens.
*/
- memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
+ memset(fdset, 0, ALIGN(nr, BITS_PER_LONG));
+ return 0;
}
- return 0;
}
static
int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset)
{
- unsigned long odd;
- nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
-
if (!ufdset)
return 0;
-
- odd = nr & 1UL;
- nr &= ~1UL;
- while (nr) {
- unsigned long h, l;
- l = *fdset++;
- h = l >> 32;
- if (__put_user(l, ufdset) || __put_user(h, ufdset+1))
- return -EFAULT;
- ufdset += 2;
- nr -= 2;
- }
- if (odd && __put_user(*fdset, ufdset))
- return -EFAULT;
- return 0;
+ return compat_put_bitmap(ufdset, fdset, nr);
}
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 2ed54020ace0..5a6a109b4a50 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -402,8 +402,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid,
#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
-#define BITS_TO_COMPAT_LONGS(bits) \
- (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
+#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size);
diff --git a/include/linux/signal.h b/include/linux/signal.h
index a39feddd71ba..e2678b5dbb21 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -243,8 +243,6 @@ extern int do_send_sig_info(int sig, struct siginfo *info,
struct task_struct *p, bool group);
extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
-extern int do_sigtimedwait(const sigset_t *, siginfo_t *,
- const struct timespec *);
extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9b06f8..3cb15ea48aee 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -650,7 +650,7 @@ asmlinkage long sys_olduname(struct oldold_utsname __user *);
asmlinkage long sys_getrlimit(unsigned int resource,
struct rlimit __user *rlim);
-#if defined(COMPAT_RLIM_OLD_INFINITY) || !(defined(CONFIG_IA64))
+#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
#endif
asmlinkage long sys_setrlimit(unsigned int resource,
diff --git a/include/linux/time.h b/include/linux/time.h
index f9858d7e6361..4abb32d4c6b8 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -180,9 +180,6 @@ extern int do_getitimer(int which, struct itimerval *value);
extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
-struct tms;
-extern void do_sys_times(struct tms *);
-
/*
* Similar to the struct tm in userspace <time.h>, but it needs to be here so
* that the kernel source is self contained.
diff --git a/ipc/Makefile b/ipc/Makefile
index 86c7300ecdf5..9c200e544434 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -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
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
deleted file mode 100644
index ef6f91cc4490..000000000000
--- a/ipc/compat_mq.c
+++ /dev/null
@@ -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;
-}
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index e8d41ff57241..c9ff943f19ab 100644
--- a/ipc/mqueue.c
+++ b/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(&notification, u_notification,
- sizeof(struct sigevent)))
- return -EFAULT;
- }
-
- audit_mq_notify(mqdes, u_notification ? &notification : 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;
- inode = file_inode(f.file);
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
- ret = -EBADF;
- goto out_fput;
+ fdput(f);
+ return -EBADF;
}
+
+ inode = file_inode(f.file);
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,17 +1389,168 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
}
spin_unlock(&info->lock);
+ fdput(f);
+ return 0;
+}
- ret = 0;
- if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
- sizeof(struct mq_attr)))
- ret = -EFAULT;
+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;
-out_fput:
- fdput(f);
-out:
- return ret;
+ 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,
diff --git a/kernel/compat.c b/kernel/compat.c
index 0621c8e1ab72..6f0a0e723a06 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -247,53 +247,6 @@ int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerv
return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
}
-static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
-{
- return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
-}
-
-COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
-{
- if (tbuf) {
- struct tms tms;
- struct compat_tms tmp;
-
- do_sys_times(&tms);
- /* Convert our struct tms to the compat version. */
- tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
- tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
- tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
- tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
- if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- force_successful_syscall_return();
- return compat_jiffies_to_clock_t(jiffies);
-}
-
-#ifdef __ARCH_WANT_SYS_SIGPENDING
-
-/*
- * Assumption: old_sigset_t and compat_old_sigset_t are both
- * types that can be passed to put_user()/get_user().
- */
-
-COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set)
-{
- old_sigset_t s;
- long ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_sigpending((old_sigset_t __user *) &s);
- set_fs(old_fs);
- if (ret == 0)
- ret = put_user(s, set);
- return ret;
-}
-
-#endif
-
#ifdef __ARCH_WANT_SYS_SIGPROCMASK
/*
@@ -348,94 +301,29 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
#endif
-COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
- struct compat_rlimit __user *, rlim)
-{
- struct rlimit r;
-
- if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
- __get_user(r.rlim_cur, &rlim->rlim_cur) ||
- __get_user(r.rlim_max, &rlim->rlim_max))
- return -EFAULT;
-
- if (r.rlim_cur == COMPAT_RLIM_INFINITY)
- r.rlim_cur = RLIM_INFINITY;
- if (r.rlim_max == COMPAT_RLIM_INFINITY)
- r.rlim_max = RLIM_INFINITY;
- return do_prlimit(current, resource, &r, NULL);
-}
-
-#ifdef COMPAT_RLIM_OLD_INFINITY
-
-COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
- struct compat_rlimit __user *, rlim)
-{
- struct rlimit r;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_old_getrlimit(resource, (struct rlimit __user *)&r);
- set_fs(old_fs);
-
- if (!ret) {
- if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
- r.rlim_cur = COMPAT_RLIM_INFINITY;
- if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
- r.rlim_max = COMPAT_RLIM_INFINITY;
-
- if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
- __put_user(r.rlim_cur, &rlim->rlim_cur) ||
- __put_user(r.rlim_max, &rlim->rlim_max))
- return -EFAULT;
- }
- return ret;
-}
-
-#endif
-
-COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
- struct compat_rlimit __user *, rlim)
-{
- struct rlimit r;
- int ret;
-
- ret = do_prlimit(current, resource, NULL, &r);
- if (!ret) {
- if (r.rlim_cur > COMPAT_RLIM_INFINITY)
- r.rlim_cur = COMPAT_RLIM_INFINITY;
- if (r.rlim_max > COMPAT_RLIM_INFINITY)
- r.rlim_max = COMPAT_RLIM_INFINITY;
-
- if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
- __put_user(r.rlim_cur, &rlim->rlim_cur) ||
- __put_user(r.rlim_max, &rlim->rlim_max))
- return -EFAULT;
- }
- return ret;
-}
-
int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
{
- if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
- __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
- __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
- __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
- __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
- __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
- __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
- __put_user(r->ru_idrss, &ru->ru_idrss) ||
- __put_user(r->ru_isrss, &ru->ru_isrss) ||
- __put_user(r->ru_minflt, &ru->ru_minflt) ||
- __put_user(r->ru_majflt, &ru->ru_majflt) ||
- __put_user(r->ru_nswap, &ru->ru_nswap) ||
- __put_user(r->ru_inblock, &ru->ru_inblock) ||
- __put_user(r->ru_oublock, &ru->ru_oublock) ||
- __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
- __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
- __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
- __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
- __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
+ struct compat_rusage r32;
+ memset(&r32, 0, sizeof(r32));
+ r32.ru_utime.tv_sec = r->ru_utime.tv_sec;
+ r32.ru_utime.tv_usec = r->ru_utime.tv_usec;
+ r32.ru_stime.tv_sec = r->ru_stime.tv_sec;
+ r32.ru_stime.tv_usec = r->ru_stime.tv_usec;
+ r32.ru_maxrss = r->ru_maxrss;
+ r32.ru_ixrss = r->ru_ixrss;
+ r32.ru_idrss = r->ru_idrss;
+ r32.ru_isrss = r->ru_isrss;
+ r32.ru_minflt = r->ru_minflt;
+ r32.ru_majflt = r->ru_majflt;
+ r32.ru_nswap = r->ru_nswap;
+ r32.ru_inblock = r->ru_inblock;
+ r32.ru_oublock = r->ru_oublock;
+ r32.ru_msgsnd = r->ru_msgsnd;
+ r32.ru_msgrcv = r->ru_msgrcv;
+ r32.ru_nsignals = r->ru_nsignals;
+ r32.ru_nvcsw = r->ru_nvcsw;
+ r32.ru_nivcsw = r->ru_nivcsw;
+ if (copy_to_user(ru, &r32, sizeof(r32)))
return -EFAULT;
return 0;
}
@@ -565,84 +453,59 @@ int get_compat_sigevent(struct sigevent *event,
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size)
{
- int i, j;
- unsigned long m;
- compat_ulong_t um;
unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
+ nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
return -EFAULT;
- nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
-
- for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
- m = 0;
-
- for (j = 0; j < sizeof(m)/sizeof(um); j++) {
- /*
- * We dont want to read past the end of the userspace
- * bitmap. We must however ensure the end of the
- * kernel bitmap is zeroed.
- */
- if (nr_compat_longs) {
- nr_compat_longs--;
- if (__get_user(um, umask))
- return -EFAULT;
- } else {
- um = 0;
- }
-
- umask++;
- m |= (long)um << (j * BITS_PER_COMPAT_LONG);
- }
- *mask++ = m;
+ user_access_begin();
+ while (nr_compat_longs > 1) {
+ compat_ulong_t l1, l2;
+ unsafe_get_user(l1, umask++, Efault);
+ unsafe_get_user(l2, umask++, Efault);
+ *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
+ nr_compat_longs -= 2;
}
-
+ if (nr_compat_longs)
+ unsafe_get_user(*mask, umask++, Efault);
+ user_access_end();
return 0;
+
+Efault:
+ user_access_end();
+ return -EFAULT;
}
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size)
{
- int i, j;
- unsigned long m;
- compat_ulong_t um;
unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
+ nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
return -EFAULT;
- nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
-
- for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
- m = *mask++;
-
- for (j = 0; j < sizeof(m)/sizeof(um); j++) {
- um = m;
-
- /*
- * We dont want to write past the end of the userspace
- * bitmap.
- */
- if (nr_compat_longs) {
- nr_compat_longs--;
- if (__put_user(um, umask))
- return -EFAULT;
- }
-
- umask++;
- m >>= 4*sizeof(um);
- m >>= 4*sizeof(um);
- }
+ user_access_begin();
+ while (nr_compat_longs > 1) {
+ unsigned long m = *mask++;
+ unsafe_put_user((compat_ulong_t)m, umask++, Efault);
+ unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
+ nr_compat_longs -= 2;
}
-
+ if (nr_compat_longs)
+ unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
+ user_access_end();
return 0;
+Efault:
+ user_access_end();
+ return -EFAULT;
}
void
@@ -668,38 +531,6 @@ sigset_to_compat(compat_sigset_t *compat, const sigset_t *set)
}
}
-COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
- struct compat_siginfo __user *, uinfo,
- struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
-{
- compat_sigset_t s32;
- sigset_t s;
- struct timespec t;
- siginfo_t info;
- long ret;
-
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
- return -EFAULT;
- sigset_from_compat(&s, &s32);
-
- if (uts) {
- if (compat_get_timespec(&t, uts))
- return -EFAULT;
- }
-
- ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
-
- if (ret > 0 && uinfo) {
- if (copy_siginfo_to_user32(uinfo, &info))
- ret = -EFAULT;
- }
-
- return ret;
-}
-
#ifdef CONFIG_NUMA
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
compat_uptr_t __user *, pages32,
diff --git a/kernel/signal.c b/kernel/signal.c
index 35a570f71f07..48a59eefd8ad 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2776,7 +2776,7 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
* @info: if non-null, the signal's siginfo is returned here
* @ts: upper bound on process time suspension
*/
-int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
+static int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
const struct timespec *ts)
{
ktime_t *to = NULL, timeout = KTIME_MAX;
@@ -2865,6 +2865,40 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
return ret;
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
+ struct compat_siginfo __user *, uinfo,
+ struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
+{
+ compat_sigset_t s32;
+ sigset_t s;
+ struct timespec t;
+ siginfo_t info;
+ long ret;
+
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
+ return -EFAULT;
+ sigset_from_compat(&s, &s32);
+
+ if (uts) {
+ if (compat_get_timespec(&t, uts))
+ return -EFAULT;
+ }
+
+ ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
+
+ if (ret > 0 && uinfo) {
+ if (copy_siginfo_to_user32(uinfo, &info))
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+#endif
+
/**
* sys_kill - send a signal to a process
* @pid: the PID of the process
@@ -3121,78 +3155,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
}
static int
-do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
+do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
{
- stack_t oss;
- int error;
+ struct task_struct *t = current;
- oss.ss_sp = (void __user *) current->sas_ss_sp;
- oss.ss_size = current->sas_ss_size;
- oss.ss_flags = sas_ss_flags(sp) |
- (current->sas_ss_flags & SS_FLAG_BITS);
+ if (oss) {
+ memset(oss, 0, sizeof(stack_t));
+ oss->ss_sp = (void __user *) t->sas_ss_sp;
+ oss->ss_size = t->sas_ss_size;
+ oss->ss_flags = sas_ss_flags(sp) |
+ (current->sas_ss_flags & SS_FLAG_BITS);
+ }
- if (uss) {
- void __user *ss_sp;
- size_t ss_size;
- unsigned ss_flags;
+ if (ss) {
+ void __user *ss_sp = ss->ss_sp;
+ size_t ss_size = ss->ss_size;
+ unsigned ss_flags = ss->ss_flags;
int ss_mode;
- error = -EFAULT;
- if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
- goto out;
- error = __get_user(ss_sp, &uss->ss_sp) |
- __get_user(ss_flags, &uss->ss_flags) |
- __get_user(ss_size, &uss->ss_size);
- if (error)
- goto out;
-
- error = -EPERM;
- if (on_sig_stack(sp))
- goto out;
+ if (unlikely(on_sig_stack(sp)))
+ return -EPERM;
ss_mode = ss_flags & ~SS_FLAG_BITS;
- error = -EINVAL;
- if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
- ss_mode != 0)
- goto out;
+ if (unlikely(ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
+ ss_mode != 0))
+ return -EINVAL;
if (ss_mode == SS_DISABLE) {
ss_size = 0;
ss_sp = NULL;
} else {
- error = -ENOMEM;
- if (ss_size < MINSIGSTKSZ)
- goto out;
+ if (unlikely(ss_size < MINSIGSTKSZ))
+ return -ENOMEM;
}
- current->sas_ss_sp = (unsigned long) ss_sp;
- current->sas_ss_size = ss_size;
- current->sas_ss_flags = ss_flags;
+ t->sas_ss_sp = (unsigned long) ss_sp;
+ t->sas_ss_size = ss_size;
+ t->sas_ss_flags = ss_flags;
}
-
- error = 0;
- if (uoss) {
- error = -EFAULT;
- if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
- goto out;
- error = __put_user(oss.ss_sp, &uoss->ss_sp) |
- __put_user(oss.ss_size, &uoss->ss_size) |
- __put_user(oss.ss_flags, &uoss->ss_flags);
- }
-
-out:
- return error;
+ return 0;
}
+
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
{
- return do_sigaltstack(uss, uoss, current_user_stack_pointer());
+ stack_t new, old;
+ int err;
+ if (uss && copy_from_user(&new, uss, sizeof(stack_t)))
+ return -EFAULT;
+ err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL,
+ current_user_stack_pointer());
+ if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t)))
+ err = -EFAULT;
+ return err;
}
int restore_altstack(const stack_t __user *uss)
{
- int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
+ stack_t new;
+ if (copy_from_user(&new, uss, sizeof(stack_t)))
+ return -EFAULT;
+ (void)do_sigaltstack(&new, NULL, current_user_stack_pointer());
/* squash all but EFAULT for now */
- return err == -EFAULT ? err : 0;
+ return 0;
}
int __save_altstack(stack_t __user *uss, unsigned long sp)
@@ -3215,29 +3239,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
{
stack_t uss, uoss;
int ret;
- mm_segment_t seg;
if (uss_ptr) {
compat_stack_t uss32;
-
- memset(&uss, 0, sizeof(stack_t));
if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
return -EFAULT;
uss.ss_sp = compat_ptr(uss32.ss_sp);
uss.ss_flags = uss32.ss_flags;
uss.ss_size = uss32.ss_size;
}
- seg = get_fs();
- set_fs(KERNEL_DS);
- ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
- (stack_t __force __user *) &uoss,
+ ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
compat_user_stack_pointer());
- set_fs(seg);
if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
- __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
- __put_user(uoss.ss_size, &uoss_ptr->ss_size))
+ compat_stack_t old;
+ memset(&old, 0, sizeof(old));
+ old.ss_sp = ptr_to_compat(uoss.ss_sp);
+ old.ss_flags = uoss.ss_flags;
+ old.ss_size = uoss.ss_size;
+ if (copy_to_user(uoss_ptr, &old, sizeof(compat_stack_t)))
ret = -EFAULT;
}
return ret;
@@ -3277,6 +3296,18 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
return sys_rt_sigpending((sigset_t __user *)set, sizeof(old_sigset_t));
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32)
+{
+ sigset_t set;
+ int err = do_sigpending(&set, sizeof(old_sigset_t));
+ if (err == 0)
+ if (copy_to_user(set32, &set, sizeof(old_sigset_t)))
+ err = -EFAULT;
+ return err;
+}
+#endif
+
#endif
#ifdef __ARCH_WANT_SYS_SIGPROCMASK
diff --git a/kernel/sys.c b/kernel/sys.c
index dab1a0658a92..47d901586b4e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -886,7 +886,7 @@ SYSCALL_DEFINE0(getegid)
return from_kgid_munged(current_user_ns(), current_egid());
}
-void do_sys_times(struct tms *tms)
+static void do_sys_times(struct tms *tms)
{
u64 tgutime, tgstime, cutime, cstime;
@@ -912,6 +912,32 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
return (long) jiffies_64_to_clock_t(get_jiffies_64());
}
+#ifdef CONFIG_COMPAT
+static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
+{
+ return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
+}
+
+COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
+{
+ if (tbuf) {
+ struct tms tms;
+ struct compat_tms tmp;
+
+ do_sys_times(&tms);
+ /* Convert our struct tms to the compat version. */
+ tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
+ tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
+ tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
+ tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
+ if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
+ return -EFAULT;
+ }
+ force_successful_syscall_return();
+ return compat_jiffies_to_clock_t(jiffies);
+}
+#endif
+
/*
* This needs some heavy checking ...
* I just haven't the stomach for it. I also don't fully
@@ -1306,6 +1332,54 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
return ret;
}
+#ifdef CONFIG_COMPAT
+
+COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
+{
+ struct rlimit r;
+ struct compat_rlimit r32;
+
+ if (copy_from_user(&r32, rlim, sizeof(struct compat_rlimit)))
+ return -EFAULT;
+
+ if (r32.rlim_cur == COMPAT_RLIM_INFINITY)
+ r.rlim_cur = RLIM_INFINITY;
+ else
+ r.rlim_cur = r32.rlim_cur;
+ if (r32.rlim_max == COMPAT_RLIM_INFINITY)
+ r.rlim_max = RLIM_INFINITY;
+ else
+ r.rlim_max = r32.rlim_max;
+ return do_prlimit(current, resource, &r, NULL);
+}
+
+COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
+{
+ struct rlimit r;
+ int ret;
+
+ ret = do_prlimit(current, resource, NULL, &r);
+ if (!ret) {
+ struct rlimit r32;
+ if (r.rlim_cur > COMPAT_RLIM_INFINITY)
+ r32.rlim_cur = COMPAT_RLIM_INFINITY;
+ else
+ r32.rlim_cur = r.rlim_cur;
+ if (r.rlim_max > COMPAT_RLIM_INFINITY)
+ r32.rlim_max = COMPAT_RLIM_INFINITY;
+ else
+ r32.rlim_max = r.rlim_max;
+
+ if (copy_to_user(rlim, &r32, sizeof(struct compat_rlimit)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+#endif
+
#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
/*
@@ -1328,6 +1402,30 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
+ struct compat_rlimit __user *, rlim)
+{
+ struct rlimit r;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+
+ task_lock(current->group_leader);
+ r = current->signal->rlim[resource];
+ task_unlock(current->group_leader);
+ if (r.rlim_cur > 0x7FFFFFFF)
+ r.rlim_cur = 0x7FFFFFFF;
+ if (r.rlim_max > 0x7FFFFFFF)
+ r.rlim_max = 0x7FFFFFFF;
+
+ if (put_user(r.rlim_cur, &rlim->rlim_cur) ||
+ put_user(r.rlim_max, &rlim->rlim_max))
+ return -EFAULT;
+ return 0;
+}
+#endif
+
#endif
static inline bool rlim64_is_infinity(__u64 rlim64)