Commit c8568639 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 771d3feb 0d060606
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP #define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_FORK
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#define __ARCH_WANT_SYS_FADVISE64 #define __ARCH_WANT_SYS_FADVISE64
#define __ARCH_WANT_SYS_GETPGRP #define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
#define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_FORK
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#define __ARCH_WANT_SYS_GETPGRP #define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLD_UNAME #define __ARCH_WANT_SYS_OLD_UNAME
#define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPENDING
......
...@@ -156,7 +156,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ ...@@ -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_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_SIGPROCMASK
......
...@@ -109,7 +109,6 @@ struct compat_statfs { ...@@ -109,7 +109,6 @@ struct compat_statfs {
int f_spare[4]; int f_spare[4];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff #define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t; typedef u32 compat_old_sigset_t;
......
...@@ -178,7 +178,6 @@ struct compat_statfs64 { ...@@ -178,7 +178,6 @@ struct compat_statfs64 {
u32 f_spare[4]; u32 f_spare[4];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff #define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_old_sigset_t; /* at least 32 bits */
......
...@@ -116,7 +116,6 @@ struct compat_statfs { ...@@ -116,7 +116,6 @@ struct compat_statfs {
int f_spare[4]; int f_spare[4];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
#define COMPAT_RLIM_INFINITY 0xffffffff #define COMPAT_RLIM_INFINITY 0xffffffff
typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_old_sigset_t; /* at least 32 bits */
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/elevator.h> #include <linux/elevator.h>
#include <linux/fd.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
...@@ -80,19 +79,16 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev, ...@@ -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, static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
mm_segment_t old_fs = get_fs(); unsigned long *__user p;
unsigned long kval;
unsigned int __user *uvp;
int error; int error;
set_fs(KERNEL_DS); p = compat_alloc_user_space(sizeof(unsigned long));
error = __blkdev_driver_ioctl(bdev, mode, error = __blkdev_driver_ioctl(bdev, mode,
cmd, (unsigned long)(&kval)); cmd, (unsigned long)p);
set_fs(old_fs);
if (error == 0) { if (error == 0) {
uvp = compat_ptr(arg); unsigned int __user *uvp = compat_ptr(arg);
if (put_user(kval, uvp)) unsigned long v;
if (get_user(v, p) || put_user(v, uvp))
error = -EFAULT; error = -EFAULT;
} }
return error; return error;
...@@ -209,318 +205,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -209,318 +205,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
#define BLKBSZSET_32 _IOW(0x12, 113, int) #define BLKBSZSET_32 _IOW(0x12, 113, int)
#define BLKGETSIZE64_32 _IOR(0x12, 114, 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, static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long arg) unsigned cmd, unsigned long arg)
{ {
...@@ -537,16 +221,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -537,16 +221,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
case HDIO_GET_ADDRESS: case HDIO_GET_ADDRESS:
case HDIO_GET_BUSSTATE: case HDIO_GET_BUSSTATE:
return compat_hdio_ioctl(bdev, mode, cmd, arg); 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: case CDROMREADAUDIO:
return compat_cdrom_read_audio(bdev, mode, cmd, arg); return compat_cdrom_read_audio(bdev, mode, cmd, arg);
case CDROM_SEND_PACKET: case CDROM_SEND_PACKET:
...@@ -566,23 +240,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -566,23 +240,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
case HDIO_DRIVE_CMD: case HDIO_DRIVE_CMD:
/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
case 0x330: 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 */ /* CDROM stuff */
case CDROMPAUSE: case CDROMPAUSE:
case CDROMRESUME: case CDROMRESUME:
......
...@@ -192,6 +192,7 @@ static int print_unex = 1; ...@@ -192,6 +192,7 @@ static int print_unex = 1;
#include <linux/io.h> #include <linux/io.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/async.h> #include <linux/async.h>
#include <linux/compat.h>
/* /*
* PS/2 floppies have much slower step rates than regular floppies. * 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, ...@@ -3568,6 +3569,330 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
return ret; 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) static void __init config_types(void)
{ {
bool has_drive = false; bool has_drive = false;
...@@ -3885,6 +4210,9 @@ static const struct block_device_operations floppy_fops = { ...@@ -3885,6 +4210,9 @@ static const struct block_device_operations floppy_fops = {
.getgeo = fd_getgeo, .getgeo = fd_getgeo,
.check_events = floppy_check_events, .check_events = floppy_check_events,
.revalidate_disk = floppy_revalidate, .revalidate_disk = floppy_revalidate,
#ifdef CONFIG_COMPAT
.compat_ioctl = fd_compat_ioctl,
#endif
}; };
/* /*
......
...@@ -231,63 +231,16 @@ static int handle_send_req(ipmi_user_t user, ...@@ -231,63 +231,16 @@ static int handle_send_req(ipmi_user_t user,
return rv; return rv;
} }
static int ipmi_ioctl(struct file *file, static int handle_recv(struct ipmi_file_private *priv,
unsigned int cmd, bool trunc, struct ipmi_recv *rsp,
unsigned long data) int (*copyout)(struct ipmi_recv *, void __user *),
void __user *to)
{ {
int rv = -EINVAL;
struct ipmi_file_private *priv = file->private_data;
void __user *arg = (void __user *)data;
switch (cmd)
{
case IPMICTL_SEND_COMMAND:
{
struct ipmi_req req;
if (copy_from_user(&req, arg, sizeof(req))) {
rv = -EFAULT;
break;
}
rv = handle_send_req(priv->user,
&req,
priv->default_retries,
priv->default_retry_time_ms);
break;
}
case IPMICTL_SEND_COMMAND_SETTIME:
{
struct ipmi_req_settime req;
if (copy_from_user(&req, arg, sizeof(req))) {
rv = -EFAULT;
break;
}
rv = handle_send_req(priv->user,
&req.req,
req.retries,
req.retry_time_ms);
break;
}
case IPMICTL_RECEIVE_MSG:
case IPMICTL_RECEIVE_MSG_TRUNC:
{
struct ipmi_recv rsp;
int addr_len; int addr_len;
struct list_head *entry; struct list_head *entry;
struct ipmi_recv_msg *msg; struct ipmi_recv_msg *msg;
unsigned long flags; unsigned long flags;
int rv = 0;
rv = 0;
if (copy_from_user(&rsp, arg, sizeof(rsp))) {
rv = -EFAULT;
break;
}
/* We claim a mutex because we don't want two /* We claim a mutex because we don't want two
users getting something from the queue at a time. users getting something from the queue at a time.
...@@ -312,65 +265,120 @@ static int ipmi_ioctl(struct file *file, ...@@ -312,65 +265,120 @@ static int ipmi_ioctl(struct file *file,
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
addr_len = ipmi_addr_length(msg->addr.addr_type); addr_len = ipmi_addr_length(msg->addr.addr_type);
if (rsp.addr_len < addr_len) if (rsp->addr_len < addr_len)
{ {
rv = -EINVAL; rv = -EINVAL;
goto recv_putback_on_err; goto recv_putback_on_err;
} }
if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) { if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
rv = -EFAULT; rv = -EFAULT;
goto recv_putback_on_err; goto recv_putback_on_err;
} }
rsp.addr_len = addr_len; rsp->addr_len = addr_len;
rsp.recv_type = msg->recv_type; rsp->recv_type = msg->recv_type;
rsp.msgid = msg->msgid; rsp->msgid = msg->msgid;
rsp.msg.netfn = msg->msg.netfn; rsp->msg.netfn = msg->msg.netfn;
rsp.msg.cmd = msg->msg.cmd; rsp->msg.cmd = msg->msg.cmd;
if (msg->msg.data_len > 0) { if (msg->msg.data_len > 0) {
if (rsp.msg.data_len < msg->msg.data_len) { if (rsp->msg.data_len < msg->msg.data_len) {
rv = -EMSGSIZE; rv = -EMSGSIZE;
if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) { if (trunc)
msg->msg.data_len = rsp.msg.data_len; msg->msg.data_len = rsp->msg.data_len;
} else { else
goto recv_putback_on_err; goto recv_putback_on_err;
} }
}
if (copy_to_user(rsp.msg.data, if (copy_to_user(rsp->msg.data,
msg->msg.data, msg->msg.data,
msg->msg.data_len)) msg->msg.data_len))
{ {
rv = -EFAULT; rv = -EFAULT;
goto recv_putback_on_err; goto recv_putback_on_err;
} }
rsp.msg.data_len = msg->msg.data_len; rsp->msg.data_len = msg->msg.data_len;
} else { } else {
rsp.msg.data_len = 0; rsp->msg.data_len = 0;
} }
if (copy_to_user(arg, &rsp, sizeof(rsp))) { rv = copyout(rsp, to);
rv = -EFAULT; if (rv)
goto recv_putback_on_err; goto recv_putback_on_err;
}
mutex_unlock(&priv->recv_mutex); mutex_unlock(&priv->recv_mutex);
ipmi_free_recv_msg(msg); ipmi_free_recv_msg(msg);
break; return 0;
recv_putback_on_err: recv_putback_on_err:
/* If we got an error, put the message back onto /* If we got an error, put the message back onto
the head of the queue. */ the head of the queue. */
spin_lock_irqsave(&(priv->recv_msg_lock), flags); spin_lock_irqsave(&(priv->recv_msg_lock), flags);
list_add(entry, &(priv->recv_msgs)); list_add(entry, &(priv->recv_msgs));
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
recv_err:
mutex_unlock(&priv->recv_mutex); 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)
{
int rv = -EINVAL;
struct ipmi_file_private *priv = file->private_data;
void __user *arg = (void __user *)data;
switch (cmd)
{
case IPMICTL_SEND_COMMAND:
{
struct ipmi_req req;
if (copy_from_user(&req, arg, sizeof(req))) {
rv = -EFAULT;
break; break;
}
recv_err: rv = handle_send_req(priv->user,
mutex_unlock(&priv->recv_mutex); &req,
priv->default_retries,
priv->default_retry_time_ms);
break;
}
case IPMICTL_SEND_COMMAND_SETTIME:
{
struct ipmi_req_settime req;
if (copy_from_user(&req, arg, sizeof(req))) {
rv = -EFAULT;
break;
}
rv = handle_send_req(priv->user,
&req.req,
req.retries,
req.retry_time_ms);
break;
}
case IPMICTL_RECEIVE_MSG:
case IPMICTL_RECEIVE_MSG_TRUNC:
{
struct ipmi_recv rsp;
if (copy_from_user(&rsp, arg, sizeof(rsp)))
rv = -EFAULT;
else
rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
&rsp, copyout_recv, arg);
break; break;
} }
...@@ -696,85 +704,56 @@ struct compat_ipmi_req_settime { ...@@ -696,85 +704,56 @@ struct compat_ipmi_req_settime {
/* /*
* Define some helper functions for copying IPMI data * Define some helper functions for copying IPMI data
*/ */
static long get_compat_ipmi_msg(struct ipmi_msg *p64, static void get_compat_ipmi_msg(struct ipmi_msg *p64,
struct compat_ipmi_msg __user *p32) struct compat_ipmi_msg *p32)
{ {
compat_uptr_t tmp; p64->netfn = p32->netfn;
p64->cmd = p32->cmd;
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || p64->data_len = p32->data_len;
__get_user(p64->netfn, &p32->netfn) || p64->data = compat_ptr(p32->data);
__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)
{
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;
} }
static long get_compat_ipmi_req(struct ipmi_req *p64, static void get_compat_ipmi_req(struct ipmi_req *p64,
struct compat_ipmi_req __user *p32) struct compat_ipmi_req *p32)
{ {
p64->addr = compat_ptr(p32->addr);
compat_uptr_t tmp; p64->addr_len = p32->addr_len;
p64->msgid = p32->msgid;
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || get_compat_ipmi_msg(&p64->msg, &p32->msg);
__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;
} }
static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
struct compat_ipmi_req_settime __user *p32) struct compat_ipmi_req_settime *p32)
{ {
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || get_compat_ipmi_req(&p64->req, &p32->req);
get_compat_ipmi_req(&p64->req, &p32->req) || p64->retries = p32->retries;
__get_user(p64->retries, &p32->retries) || p64->retry_time_ms = p32->retry_time_ms;
__get_user(p64->retry_time_ms, &p32->retry_time_ms))
return -EFAULT;
return 0;
} }
static long get_compat_ipmi_recv(struct ipmi_recv *p64, static void get_compat_ipmi_recv(struct ipmi_recv *p64,
struct compat_ipmi_recv __user *p32) struct compat_ipmi_recv *p32)
{ {
compat_uptr_t tmp; memset(p64, 0, sizeof(struct ipmi_recv));
p64->recv_type = p32->recv_type;
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || p64->addr = compat_ptr(p32->addr);
__get_user(p64->recv_type, &p32->recv_type) || p64->addr_len = p32->addr_len;
__get_user(tmp, &p32->addr) || p64->msgid = p32->msgid;
__get_user(p64->addr_len, &p32->addr_len) || get_compat_ipmi_msg(&p64->msg, &p32->msg);
__get_user(p64->msgid, &p32->msgid) ||
get_compat_ipmi_msg(&p64->msg, &p32->msg))
return -EFAULT;
p64->addr = compat_ptr(tmp);
return 0;
} }
static long put_compat_ipmi_recv(struct ipmi_recv *p64, static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
struct compat_ipmi_recv __user *p32)
{ {
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || struct compat_ipmi_recv v32;
__put_user(p64->recv_type, &p32->recv_type) || memset(&v32, 0, sizeof(struct compat_ipmi_recv));
__put_user(p64->addr_len, &p32->addr_len) || v32.recv_type = p64->recv_type;
__put_user(p64->msgid, &p32->msgid) || v32.addr = ptr_to_compat(p64->addr);
put_compat_ipmi_msg(&p64->msg, &p32->msg)) v32.addr_len = p64->addr_len;
return -EFAULT; v32.msgid = p64->msgid;
return 0; 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, ...@@ -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, static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int rc;
struct ipmi_file_private *priv = filep->private_data; struct ipmi_file_private *priv = filep->private_data;
switch(cmd) { switch(cmd) {
case COMPAT_IPMICTL_SEND_COMMAND: case COMPAT_IPMICTL_SEND_COMMAND:
{ {
struct ipmi_req rp; 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; return -EFAULT;
get_compat_ipmi_req(&rp, &r32);
return handle_send_req(priv->user, &rp, return handle_send_req(priv->user, &rp,
priv->default_retries, priv->default_retries,
priv->default_retry_time_ms); priv->default_retry_time_ms);
...@@ -801,42 +782,30 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, ...@@ -801,42 +782,30 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
{ {
struct ipmi_req_settime sp; 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; return -EFAULT;
get_compat_ipmi_req_settime(&sp, &sp32);
return handle_send_req(priv->user, &sp.req, return handle_send_req(priv->user, &sp.req,
sp.retries, sp.retry_time_ms); sp.retries, sp.retry_time_ms);
} }
case COMPAT_IPMICTL_RECEIVE_MSG: case COMPAT_IPMICTL_RECEIVE_MSG:
case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
{ {
struct ipmi_recv __user *precv64;
struct ipmi_recv recv64; struct ipmi_recv recv64;
struct compat_ipmi_recv recv32;
memset(&recv64, 0, sizeof(recv64)); if (copy_from_user(&recv32, compat_ptr(arg), sizeof(recv32)))
if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
return -EFAULT;
precv64 = compat_alloc_user_space(sizeof(recv64));
if (copy_to_user(precv64, &recv64, sizeof(recv64)))
return -EFAULT; return -EFAULT;
rc = ipmi_ioctl(filep, get_compat_ipmi_recv(&recv64, &recv32);
((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;
return rc; return handle_recv(priv,
cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
&recv64, copyout_recv32, compat_ptr(arg));
} }
default: default:
return ipmi_ioctl(filep, cmd, arg); return ipmi_ioctl(filep, cmd, arg);
......
...@@ -1966,27 +1966,21 @@ static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *a ...@@ -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, static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb) struct usbdevfs_urb32 __user *uurb)
{ {
__u32 uptr; struct usbdevfs_urb32 urb32;
if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) || if (copy_from_user(&urb32, 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))
return -EFAULT; return -EFAULT;
kurb->type = urb32.type;
if (__get_user(uptr, &uurb->buffer)) kurb->endpoint = urb32.endpoint;
return -EFAULT; kurb->status = urb32.status;
kurb->buffer = compat_ptr(uptr); kurb->flags = urb32.flags;
if (__get_user(uptr, &uurb->usercontext)) kurb->buffer = compat_ptr(urb32.buffer);
return -EFAULT; kurb->buffer_length = urb32.buffer_length;
kurb->usercontext = compat_ptr(uptr); 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; return 0;
} }
...@@ -2198,18 +2192,14 @@ static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg) ...@@ -2198,18 +2192,14 @@ static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg) 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; struct usbdevfs_ioctl ctrl;
u32 udata;
uioc = compat_ptr((long)arg); if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
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))
return -EFAULT; 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); return proc_ioctl(ps, &ctrl);
} }
#endif #endif
......
...@@ -1331,22 +1331,13 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, ...@@ -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, static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
mm_segment_t old_fs;
struct fb_fix_screeninfo fix; 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, static long fb_compat_ioctl(struct file *file, unsigned int cmd,
......
...@@ -1161,59 +1161,25 @@ static ...@@ -1161,59 +1161,25 @@ static
int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset) unsigned long *fdset)
{ {
nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
if (ufdset) { if (ufdset) {
unsigned long odd; return compat_get_bitmap(fdset, ufdset, nr);
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;
} else { } else {
/* Tricky, must clear full unsigned long in the /* 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. * 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 static
int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset) unsigned long *fdset)
{ {
unsigned long odd;
nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
if (!ufdset) if (!ufdset)
return 0; return 0;
return compat_put_bitmap(ufdset, fdset, nr);
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;
} }
......
...@@ -402,8 +402,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid, ...@@ -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_PER_COMPAT_LONG (8*sizeof(compat_long_t))
#define BITS_TO_COMPAT_LONGS(bits) \ #define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
(((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size); unsigned long bitmap_size);
......
...@@ -243,8 +243,6 @@ extern int do_send_sig_info(int sig, struct siginfo *info, ...@@ -243,8 +243,6 @@ extern int do_send_sig_info(int sig, struct siginfo *info,
struct task_struct *p, bool group); 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 sig, struct siginfo *info, struct task_struct *p);
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); 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 int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(sigset_t *); extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *); extern void __set_current_blocked(const sigset_t *);
......
...@@ -650,7 +650,7 @@ asmlinkage long sys_olduname(struct oldold_utsname __user *); ...@@ -650,7 +650,7 @@ asmlinkage long sys_olduname(struct oldold_utsname __user *);
asmlinkage long sys_getrlimit(unsigned int resource, asmlinkage long sys_getrlimit(unsigned int resource,
struct rlimit __user *rlim); 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); asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
#endif #endif
asmlinkage long sys_setrlimit(unsigned int resource, asmlinkage long sys_setrlimit(unsigned int resource,
......
...@@ -180,9 +180,6 @@ extern int do_getitimer(int which, struct itimerval *value); ...@@ -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); 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 * Similar to the struct tm in userspace <time.h>, but it needs to be here so
* that the kernel source is self contained. * that the kernel source is self contained.
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o
obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
obj_mq-$(CONFIG_COMPAT) += compat_mq.o obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
obj-$(CONFIG_IPC_NS) += namespace.o obj-$(CONFIG_IPC_NS) += namespace.o
obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
/*
* 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;
}
...@@ -668,14 +668,12 @@ static void __do_notify(struct mqueue_inode_info *info) ...@@ -668,14 +668,12 @@ static void __do_notify(struct mqueue_inode_info *info)
} }
static int prepare_timeout(const struct timespec __user *u_abs_timeout, 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))) if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
return -EFAULT; return -EFAULT;
if (!timespec_valid(ts)) if (!timespec_valid(ts))
return -EINVAL; return -EINVAL;
*expires = timespec_to_ktime(*ts);
return 0; return 0;
} }
...@@ -770,23 +768,19 @@ static struct file *do_open(struct path *path, int oflag) ...@@ -770,23 +768,19 @@ static struct file *do_open(struct path *path, int oflag)
return dentry_open(path, oflag, current_cred()); return dentry_open(path, oflag, current_cred());
} }
SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
struct mq_attr __user *, u_attr) struct mq_attr *attr)
{ {
struct path path; struct path path;
struct file *filp; struct file *filp;
struct filename *name; struct filename *name;
struct mq_attr attr;
int fd, error; int fd, error;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
struct vfsmount *mnt = ipc_ns->mq_mnt; struct vfsmount *mnt = ipc_ns->mq_mnt;
struct dentry *root = mnt->mnt_root; struct dentry *root = mnt->mnt_root;
int ro; int ro;
if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) audit_mq_open(oflag, mode, attr);
return -EFAULT;
audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
if (IS_ERR(name = getname(u_name))) if (IS_ERR(name = getname(u_name)))
return PTR_ERR(name); return PTR_ERR(name);
...@@ -819,9 +813,8 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -819,9 +813,8 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
goto out; goto out;
} }
audit_inode_parent_hidden(name, root); audit_inode_parent_hidden(name, root);
filp = do_create(ipc_ns, d_inode(root), filp = do_create(ipc_ns, d_inode(root), &path,
&path, oflag, mode, oflag, mode, attr);
u_attr ? &attr : NULL);
} }
} else { } else {
if (d_really_is_negative(path.dentry)) { if (d_really_is_negative(path.dentry)) {
...@@ -851,6 +844,16 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, ...@@ -851,6 +844,16 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
return fd; 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) SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{ {
int err; int err;
...@@ -957,9 +960,9 @@ static inline void pipelined_receive(struct wake_q_head *wake_q, ...@@ -957,9 +960,9 @@ static inline void pipelined_receive(struct wake_q_head *wake_q,
sender->state = STATE_READY; sender->state = STATE_READY;
} }
SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, static int do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
size_t, msg_len, unsigned int, msg_prio, size_t msg_len, unsigned int msg_prio,
const struct timespec __user *, u_abs_timeout) struct timespec *ts)
{ {
struct fd f; struct fd f;
struct inode *inode; struct inode *inode;
...@@ -968,22 +971,19 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, ...@@ -968,22 +971,19 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
struct msg_msg *msg_ptr; struct msg_msg *msg_ptr;
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
ktime_t expires, *timeout = NULL; ktime_t expires, *timeout = NULL;
struct timespec ts;
struct posix_msg_tree_node *new_leaf = NULL; struct posix_msg_tree_node *new_leaf = NULL;
int ret = 0; int ret = 0;
DEFINE_WAKE_Q(wake_q); 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)) if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
return -EINVAL; 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); f = fdget(mqdes);
if (unlikely(!f.file)) { if (unlikely(!f.file)) {
...@@ -1078,9 +1078,9 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, ...@@ -1078,9 +1078,9 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
return ret; return ret;
} }
SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, static int do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
size_t, msg_len, unsigned int __user *, u_msg_prio, size_t msg_len, unsigned int __user *u_msg_prio,
const struct timespec __user *, u_abs_timeout) struct timespec *ts)
{ {
ssize_t ret; ssize_t ret;
struct msg_msg *msg_ptr; struct msg_msg *msg_ptr;
...@@ -1089,17 +1089,14 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, ...@@ -1089,17 +1089,14 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct ext_wait_queue wait; struct ext_wait_queue wait;
ktime_t expires, *timeout = NULL; ktime_t expires, *timeout = NULL;
struct timespec ts;
struct posix_msg_tree_node *new_leaf = NULL; struct posix_msg_tree_node *new_leaf = NULL;
if (u_abs_timeout) { if (ts) {
int res = prepare_timeout(u_abs_timeout, &expires, &ts); expires = timespec_to_ktime(*ts);
if (res)
return res;
timeout = &expires; timeout = &expires;
} }
audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL); audit_mq_sendrecv(mqdes, msg_len, 0, ts);
f = fdget(mqdes); f = fdget(mqdes);
if (unlikely(!f.file)) { if (unlikely(!f.file)) {
...@@ -1183,42 +1180,62 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, ...@@ -1183,42 +1180,62 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
return ret; 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) * 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. * and he isn't currently owner of notification, will be silently discarded.
* It isn't explicitly defined in the POSIX. * It isn't explicitly defined in the POSIX.
*/ */
SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, static int do_mq_notify(mqd_t mqdes, const struct sigevent *notification)
const struct sigevent __user *, u_notification)
{ {
int ret; int ret;
struct fd f; struct fd f;
struct sock *sock; struct sock *sock;
struct inode *inode; struct inode *inode;
struct sigevent notification;
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct sk_buff *nc; struct sk_buff *nc;
if (u_notification) { audit_mq_notify(mqdes, notification);
if (copy_from_user(&notification, u_notification,
sizeof(struct sigevent)))
return -EFAULT;
}
audit_mq_notify(mqdes, u_notification ? &notification : NULL);
nc = NULL; nc = NULL;
sock = NULL; sock = NULL;
if (u_notification != NULL) { if (notification != NULL) {
if (unlikely(notification.sigev_notify != SIGEV_NONE && if (unlikely(notification->sigev_notify != SIGEV_NONE &&
notification.sigev_notify != SIGEV_SIGNAL && notification->sigev_notify != SIGEV_SIGNAL &&
notification.sigev_notify != SIGEV_THREAD)) notification->sigev_notify != SIGEV_THREAD))
return -EINVAL; return -EINVAL;
if (notification.sigev_notify == SIGEV_SIGNAL && if (notification->sigev_notify == SIGEV_SIGNAL &&
!valid_signal(notification.sigev_signo)) { !valid_signal(notification->sigev_signo)) {
return -EINVAL; return -EINVAL;
} }
if (notification.sigev_notify == SIGEV_THREAD) { if (notification->sigev_notify == SIGEV_THREAD) {
long timeo; long timeo;
/* create the notify skb */ /* create the notify skb */
...@@ -1228,7 +1245,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1228,7 +1245,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
goto out; goto out;
} }
if (copy_from_user(nc->data, if (copy_from_user(nc->data,
notification.sigev_value.sival_ptr, notification->sigev_value.sival_ptr,
NOTIFY_COOKIE_LEN)) { NOTIFY_COOKIE_LEN)) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
...@@ -1238,7 +1255,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1238,7 +1255,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
skb_put(nc, NOTIFY_COOKIE_LEN); skb_put(nc, NOTIFY_COOKIE_LEN);
/* and attach it to the socket */ /* and attach it to the socket */
retry: retry:
f = fdget(notification.sigev_signo); f = fdget(notification->sigev_signo);
if (!f.file) { if (!f.file) {
ret = -EBADF; ret = -EBADF;
goto out; goto out;
...@@ -1278,7 +1295,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1278,7 +1295,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
ret = 0; ret = 0;
spin_lock(&info->lock); spin_lock(&info->lock);
if (u_notification == NULL) { if (notification == NULL) {
if (info->notify_owner == task_tgid(current)) { if (info->notify_owner == task_tgid(current)) {
remove_notification(info); remove_notification(info);
inode->i_atime = inode->i_ctime = current_time(inode); inode->i_atime = inode->i_ctime = current_time(inode);
...@@ -1286,7 +1303,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1286,7 +1303,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
} else if (info->notify_owner != NULL) { } else if (info->notify_owner != NULL) {
ret = -EBUSY; ret = -EBUSY;
} else { } else {
switch (notification.sigev_notify) { switch (notification->sigev_notify) {
case SIGEV_NONE: case SIGEV_NONE:
info->notify.sigev_notify = SIGEV_NONE; info->notify.sigev_notify = SIGEV_NONE;
break; break;
...@@ -1298,8 +1315,8 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1298,8 +1315,8 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
info->notify.sigev_notify = SIGEV_THREAD; info->notify.sigev_notify = SIGEV_THREAD;
break; break;
case SIGEV_SIGNAL: case SIGEV_SIGNAL:
info->notify.sigev_signo = notification.sigev_signo; info->notify.sigev_signo = notification->sigev_signo;
info->notify.sigev_value = notification.sigev_value; info->notify.sigev_value = notification->sigev_value;
info->notify.sigev_notify = SIGEV_SIGNAL; info->notify.sigev_notify = SIGEV_SIGNAL;
break; break;
} }
...@@ -1320,44 +1337,49 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, ...@@ -1320,44 +1337,49 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
return ret; return ret;
} }
SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
const struct mq_attr __user *, u_mqstat, const struct sigevent __user *, u_notification)
struct mq_attr __user *, u_omqstat) {
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 fd f;
struct inode *inode; struct inode *inode;
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
if (u_mqstat != NULL) { if (new && (new->mq_flags & (~O_NONBLOCK)))
if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr)))
return -EFAULT;
if (mqstat.mq_flags & (~O_NONBLOCK))
return -EINVAL; return -EINVAL;
}
f = fdget(mqdes); f = fdget(mqdes);
if (!f.file) { if (!f.file)
ret = -EBADF; return -EBADF;
goto out;
}
inode = file_inode(f.file);
if (unlikely(f.file->f_op != &mqueue_file_operations)) { if (unlikely(f.file->f_op != &mqueue_file_operations)) {
ret = -EBADF; fdput(f);
goto out_fput; return -EBADF;
} }
inode = file_inode(f.file);
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
spin_lock(&info->lock); spin_lock(&info->lock);
omqstat = info->attr; if (old) {
omqstat.mq_flags = f.file->f_flags & O_NONBLOCK; *old = info->attr;
if (u_mqstat) { old->mq_flags = f.file->f_flags & O_NONBLOCK;
audit_mq_getsetattr(mqdes, &mqstat); }
if (new) {
audit_mq_getsetattr(mqdes, new);
spin_lock(&f.file->f_lock); spin_lock(&f.file->f_lock);
if (mqstat.mq_flags & O_NONBLOCK) if (new->mq_flags & O_NONBLOCK)
f.file->f_flags |= O_NONBLOCK; f.file->f_flags |= O_NONBLOCK;
else else
f.file->f_flags &= ~O_NONBLOCK; f.file->f_flags &= ~O_NONBLOCK;
...@@ -1367,17 +1389,168 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, ...@@ -1367,17 +1389,168 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
} }
spin_unlock(&info->lock); spin_unlock(&info->lock);
fdput(f);
return 0;
}
ret = 0; SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat, const struct mq_attr __user *, u_mqstat,
sizeof(struct mq_attr))) struct mq_attr __user *, u_omqstat)
ret = -EFAULT; {
int ret;
struct mq_attr mqstat, omqstat;
struct mq_attr *new = NULL, *old = NULL;
out_fput: if (u_mqstat) {
fdput(f); new = &mqstat;
out: 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; 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 = { static const struct inode_operations mqueue_dir_inode_operations = {
.lookup = simple_lookup, .lookup = simple_lookup,
......
...@@ -247,53 +247,6 @@ int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerv ...@@ -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; 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 #ifdef __ARCH_WANT_SYS_SIGPROCMASK
/* /*
...@@ -348,94 +301,29 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how, ...@@ -348,94 +301,29 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
#endif #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) int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
{ {
if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) || struct compat_rusage r32;
__put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) || memset(&r32, 0, sizeof(r32));
__put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) || r32.ru_utime.tv_sec = r->ru_utime.tv_sec;
__put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) || r32.ru_utime.tv_usec = r->ru_utime.tv_usec;
__put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) || r32.ru_stime.tv_sec = r->ru_stime.tv_sec;
__put_user(r->ru_maxrss, &ru->ru_maxrss) || r32.ru_stime.tv_usec = r->ru_stime.tv_usec;
__put_user(r->ru_ixrss, &ru->ru_ixrss) || r32.ru_maxrss = r->ru_maxrss;
__put_user(r->ru_idrss, &ru->ru_idrss) || r32.ru_ixrss = r->ru_ixrss;
__put_user(r->ru_isrss, &ru->ru_isrss) || r32.ru_idrss = r->ru_idrss;
__put_user(r->ru_minflt, &ru->ru_minflt) || r32.ru_isrss = r->ru_isrss;
__put_user(r->ru_majflt, &ru->ru_majflt) || r32.ru_minflt = r->ru_minflt;
__put_user(r->ru_nswap, &ru->ru_nswap) || r32.ru_majflt = r->ru_majflt;
__put_user(r->ru_inblock, &ru->ru_inblock) || r32.ru_nswap = r->ru_nswap;
__put_user(r->ru_oublock, &ru->ru_oublock) || r32.ru_inblock = r->ru_inblock;
__put_user(r->ru_msgsnd, &ru->ru_msgsnd) || r32.ru_oublock = r->ru_oublock;
__put_user(r->ru_msgrcv, &ru->ru_msgrcv) || r32.ru_msgsnd = r->ru_msgsnd;
__put_user(r->ru_nsignals, &ru->ru_nsignals) || r32.ru_msgrcv = r->ru_msgrcv;
__put_user(r->ru_nvcsw, &ru->ru_nvcsw) || r32.ru_nsignals = r->ru_nsignals;
__put_user(r->ru_nivcsw, &ru->ru_nivcsw)) r32.ru_nvcsw = r->ru_nvcsw;
r32.ru_nivcsw = r->ru_nivcsw;
if (copy_to_user(ru, &r32, sizeof(r32)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -565,84 +453,59 @@ int get_compat_sigevent(struct sigevent *event, ...@@ -565,84 +453,59 @@ int get_compat_sigevent(struct sigevent *event,
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size) unsigned long bitmap_size)
{ {
int i, j;
unsigned long m;
compat_ulong_t um;
unsigned long nr_compat_longs; unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */ /* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
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; return -EFAULT;
} else {
um = 0;
}
umask++; user_access_begin();
m |= (long)um << (j * BITS_PER_COMPAT_LONG); while (nr_compat_longs > 1) {
} compat_ulong_t l1, l2;
*mask++ = m; 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; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size) unsigned long bitmap_size)
{ {
int i, j;
unsigned long m;
compat_ulong_t um;
unsigned long nr_compat_longs; unsigned long nr_compat_longs;
/* align bitmap up to nearest compat_long_t boundary */ /* align bitmap up to nearest compat_long_t boundary */
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
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; return -EFAULT;
}
umask++; user_access_begin();
m >>= 4*sizeof(um); while (nr_compat_longs > 1) {
m >>= 4*sizeof(um); 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; return 0;
Efault:
user_access_end();
return -EFAULT;
} }
void void
...@@ -668,38 +531,6 @@ sigset_to_compat(compat_sigset_t *compat, const sigset_t *set) ...@@ -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 #ifdef CONFIG_NUMA
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages, COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
compat_uptr_t __user *, pages32, compat_uptr_t __user *, pages32,
......
...@@ -2776,7 +2776,7 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) ...@@ -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 * @info: if non-null, the signal's siginfo is returned here
* @ts: upper bound on process time suspension * @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) const struct timespec *ts)
{ {
ktime_t *to = NULL, timeout = KTIME_MAX; ktime_t *to = NULL, timeout = KTIME_MAX;
...@@ -2865,6 +2865,40 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, ...@@ -2865,6 +2865,40 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
return ret; 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 * sys_kill - send a signal to a process
* @pid: the PID of the process * @pid: the PID of the process
...@@ -3121,78 +3155,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) ...@@ -3121,78 +3155,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
} }
static int 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; struct task_struct *t = current;
int error;
oss.ss_sp = (void __user *) current->sas_ss_sp; if (oss) {
oss.ss_size = current->sas_ss_size; memset(oss, 0, sizeof(stack_t));
oss.ss_flags = sas_ss_flags(sp) | 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); (current->sas_ss_flags & SS_FLAG_BITS);
}
if (uss) { if (ss) {
void __user *ss_sp; void __user *ss_sp = ss->ss_sp;
size_t ss_size; size_t ss_size = ss->ss_size;
unsigned ss_flags; unsigned ss_flags = ss->ss_flags;
int ss_mode; int ss_mode;
error = -EFAULT; if (unlikely(on_sig_stack(sp)))
if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) return -EPERM;
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;
ss_mode = ss_flags & ~SS_FLAG_BITS; ss_mode = ss_flags & ~SS_FLAG_BITS;
error = -EINVAL; if (unlikely(ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK && ss_mode != 0))
ss_mode != 0) return -EINVAL;
goto out;
if (ss_mode == SS_DISABLE) { if (ss_mode == SS_DISABLE) {
ss_size = 0; ss_size = 0;
ss_sp = NULL; ss_sp = NULL;
} else { } else {
error = -ENOMEM; if (unlikely(ss_size < MINSIGSTKSZ))
if (ss_size < MINSIGSTKSZ) return -ENOMEM;
goto out;
} }
current->sas_ss_sp = (unsigned long) ss_sp; t->sas_ss_sp = (unsigned long) ss_sp;
current->sas_ss_size = ss_size; t->sas_ss_size = ss_size;
current->sas_ss_flags = ss_flags; 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);
} }
return 0;
out:
return error;
} }
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss) 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 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 */ /* squash all but EFAULT for now */
return err == -EFAULT ? err : 0; return 0;
} }
int __save_altstack(stack_t __user *uss, unsigned long sp) int __save_altstack(stack_t __user *uss, unsigned long sp)
...@@ -3215,29 +3239,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack, ...@@ -3215,29 +3239,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
{ {
stack_t uss, uoss; stack_t uss, uoss;
int ret; int ret;
mm_segment_t seg;
if (uss_ptr) { if (uss_ptr) {
compat_stack_t uss32; compat_stack_t uss32;
memset(&uss, 0, sizeof(stack_t));
if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t))) if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
return -EFAULT; return -EFAULT;
uss.ss_sp = compat_ptr(uss32.ss_sp); uss.ss_sp = compat_ptr(uss32.ss_sp);
uss.ss_flags = uss32.ss_flags; uss.ss_flags = uss32.ss_flags;
uss.ss_size = uss32.ss_size; uss.ss_size = uss32.ss_size;
} }
seg = get_fs(); ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
set_fs(KERNEL_DS);
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
(stack_t __force __user *) &uoss,
compat_user_stack_pointer()); compat_user_stack_pointer());
set_fs(seg);
if (ret >= 0 && uoss_ptr) { if (ret >= 0 && uoss_ptr) {
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) || compat_stack_t old;
__put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || memset(&old, 0, sizeof(old));
__put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || old.ss_sp = ptr_to_compat(uoss.ss_sp);
__put_user(uoss.ss_size, &uoss_ptr->ss_size)) 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; ret = -EFAULT;
} }
return ret; return ret;
...@@ -3277,6 +3296,18 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) ...@@ -3277,6 +3296,18 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
return sys_rt_sigpending((sigset_t __user *)set, sizeof(old_sigset_t)); 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 #endif
#ifdef __ARCH_WANT_SYS_SIGPROCMASK #ifdef __ARCH_WANT_SYS_SIGPROCMASK
......
...@@ -886,7 +886,7 @@ SYSCALL_DEFINE0(getegid) ...@@ -886,7 +886,7 @@ SYSCALL_DEFINE0(getegid)
return from_kgid_munged(current_user_ns(), current_egid()); 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; u64 tgutime, tgstime, cutime, cstime;
...@@ -912,6 +912,32 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf) ...@@ -912,6 +912,32 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
return (long) jiffies_64_to_clock_t(get_jiffies_64()); 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 ... * This needs some heavy checking ...
* I just haven't the stomach for it. I also don't fully * 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) ...@@ -1306,6 +1332,54 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
return ret; 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 #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
/* /*
...@@ -1328,6 +1402,30 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, ...@@ -1328,6 +1402,30 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0; 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 #endif
static inline bool rlim64_is_infinity(__u64 rlim64) static inline bool rlim64_is_infinity(__u64 rlim64)
......
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