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 */
......
This diff is collapsed.
...@@ -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
}; };
/* /*
......
This diff is collapsed.
...@@ -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;
}
This diff is collapsed.
...@@ -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