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,6 +231,102 @@ static int handle_send_req(ipmi_user_t user, ...@@ -231,6 +231,102 @@ static int handle_send_req(ipmi_user_t user,
return rv; 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, static int ipmi_ioctl(struct file *file,
unsigned int cmd, unsigned int cmd,
unsigned long data) unsigned long data)
...@@ -277,100 +373,12 @@ static int ipmi_ioctl(struct file *file, ...@@ -277,100 +373,12 @@ static int ipmi_ioctl(struct file *file,
case IPMICTL_RECEIVE_MSG_TRUNC: case IPMICTL_RECEIVE_MSG_TRUNC:
{ {
struct ipmi_recv rsp; 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; rv = -EFAULT;
goto recv_putback_on_err; else
} rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
rsp.addr_len = addr_len; &rsp, copyout_recv, arg);
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);
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;
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)
{ {
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || p64->netfn = p32->netfn;
__put_user(p64->netfn, &p32->netfn) || p64->cmd = p32->cmd;
__put_user(p64->cmd, &p32->cmd) || p64->data_len = p32->data_len;
__put_user(p64->data_len, &p32->data_len)) p64->data = compat_ptr(p32->data);
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; return -EFAULT;
precv64 = compat_alloc_user_space(sizeof(recv64)); get_compat_ipmi_recv(&recv64, &recv32);
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;
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) if (!lock_fb_info(info))
err = do_fscreeninfo_to_user(&fix, fix32); return -ENODEV;
fix = info->fix;
return err; 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 -EINVAL;
return -EFAULT;
if (mqstat.mq_flags & (~O_NONBLOCK))
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 ret; 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 = { 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);
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!access_ok(VERIFY_READ, umask, bitmap_size / 8)) if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); user_access_begin();
while (nr_compat_longs > 1) {
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { compat_ulong_t l1, l2;
m = 0; unsafe_get_user(l1, umask++, Efault);
unsafe_get_user(l2, umask++, Efault);
for (j = 0; j < sizeof(m)/sizeof(um); j++) { *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
/* nr_compat_longs -= 2;
* 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;
} }
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);
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8)) if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); user_access_begin();
while (nr_compat_longs > 1) {
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { unsigned long m = *mask++;
m = *mask++; unsafe_put_user((compat_ulong_t)m, umask++, Efault);
unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
for (j = 0; j < sizeof(m)/sizeof(um); j++) { nr_compat_longs -= 2;
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);
}
} }
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;
(current->sas_ss_flags & SS_FLAG_BITS); oss->ss_size = t->sas_ss_size;
oss->ss_flags = sas_ss_flags(sp) |
(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;
} }
return 0;
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;
} }
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