mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-07 14:32:23 +00:00
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
This commit is contained in:
commit
c856863988
@ -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 @@
|
|||||||
#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 @@
|
|||||||
#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) \
|
|||||||
#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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
#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,
|
|||||||
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,
|
|||||||
#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,
|
|||||||
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,
|
|||||||
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;
|
|||||||
#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,
|
|||||||
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 = {
|
|||||||
.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,
|
|||||||
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,
|
|||||||
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)))
|
||||||
if (copy_from_user(&rsp, arg, sizeof(rsp))) {
|
|
||||||
rv = -EFAULT;
|
rv = -EFAULT;
|
||||||
break;
|
else
|
||||||
}
|
rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
|
||||||
|
&rsp, copyout_recv, arg);
|
||||||
/* 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 (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 {
|
|||||||
/*
|
/*
|
||||||
* Define some helper functions for copying IPMI data
|
* Define some helper functions for copying IPMI data
|
||||||
*/
|
*/
|
||||||
static long get_compat_ipmi_msg(struct ipmi_msg *p64,
|
static void get_compat_ipmi_msg(struct ipmi_msg *p64,
|
||||||
struct compat_ipmi_msg __user *p32)
|
struct compat_ipmi_msg *p32)
|
||||||
{
|
{
|
||||||
compat_uptr_t tmp;
|
p64->netfn = p32->netfn;
|
||||||
|
p64->cmd = p32->cmd;
|
||||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
p64->data_len = p32->data_len;
|
||||||
__get_user(p64->netfn, &p32->netfn) ||
|
p64->data = compat_ptr(p32->data);
|
||||||
__get_user(p64->cmd, &p32->cmd) ||
|
|
||||||
__get_user(p64->data_len, &p32->data_len) ||
|
|
||||||
__get_user(tmp, &p32->data))
|
|
||||||
return -EFAULT;
|
|
||||||
p64->data = compat_ptr(tmp);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long put_compat_ipmi_msg(struct ipmi_msg *p64,
|
static void get_compat_ipmi_req(struct ipmi_req *p64,
|
||||||
struct compat_ipmi_msg __user *p32)
|
struct compat_ipmi_req *p32)
|
||||||
{
|
{
|
||||||
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
|
p64->addr = compat_ptr(p32->addr);
|
||||||
__put_user(p64->netfn, &p32->netfn) ||
|
p64->addr_len = p32->addr_len;
|
||||||
__put_user(p64->cmd, &p32->cmd) ||
|
p64->msgid = p32->msgid;
|
||||||
__put_user(p64->data_len, &p32->data_len))
|
get_compat_ipmi_msg(&p64->msg, &p32->msg);
|
||||||
return -EFAULT;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long get_compat_ipmi_req(struct ipmi_req *p64,
|
static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
|
||||||
struct compat_ipmi_req __user *p32)
|
struct compat_ipmi_req_settime *p32)
|
||||||
{
|
{
|
||||||
|
get_compat_ipmi_req(&p64->req, &p32->req);
|
||||||
compat_uptr_t tmp;
|
p64->retries = p32->retries;
|
||||||
|
p64->retry_time_ms = p32->retry_time_ms;
|
||||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
|
||||||
__get_user(tmp, &p32->addr) ||
|
|
||||||
__get_user(p64->addr_len, &p32->addr_len) ||
|
|
||||||
__get_user(p64->msgid, &p32->msgid) ||
|
|
||||||
get_compat_ipmi_msg(&p64->msg, &p32->msg))
|
|
||||||
return -EFAULT;
|
|
||||||
p64->addr = compat_ptr(tmp);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
|
static void get_compat_ipmi_recv(struct ipmi_recv *p64,
|
||||||
struct compat_ipmi_req_settime __user *p32)
|
struct compat_ipmi_recv *p32)
|
||||||
{
|
{
|
||||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
memset(p64, 0, sizeof(struct ipmi_recv));
|
||||||
get_compat_ipmi_req(&p64->req, &p32->req) ||
|
p64->recv_type = p32->recv_type;
|
||||||
__get_user(p64->retries, &p32->retries) ||
|
p64->addr = compat_ptr(p32->addr);
|
||||||
__get_user(p64->retry_time_ms, &p32->retry_time_ms))
|
p64->addr_len = p32->addr_len;
|
||||||
return -EFAULT;
|
p64->msgid = p32->msgid;
|
||||||
return 0;
|
get_compat_ipmi_msg(&p64->msg, &p32->msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long get_compat_ipmi_recv(struct ipmi_recv *p64,
|
static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
|
||||||
struct compat_ipmi_recv __user *p32)
|
|
||||||
{
|
{
|
||||||
compat_uptr_t tmp;
|
struct compat_ipmi_recv v32;
|
||||||
|
memset(&v32, 0, sizeof(struct compat_ipmi_recv));
|
||||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
v32.recv_type = p64->recv_type;
|
||||||
__get_user(p64->recv_type, &p32->recv_type) ||
|
v32.addr = ptr_to_compat(p64->addr);
|
||||||
__get_user(tmp, &p32->addr) ||
|
v32.addr_len = p64->addr_len;
|
||||||
__get_user(p64->addr_len, &p32->addr_len) ||
|
v32.msgid = p64->msgid;
|
||||||
__get_user(p64->msgid, &p32->msgid) ||
|
v32.msg.netfn = p64->msg.netfn;
|
||||||
get_compat_ipmi_msg(&p64->msg, &p32->msg))
|
v32.msg.cmd = p64->msg.cmd;
|
||||||
return -EFAULT;
|
v32.msg.data_len = p64->msg.data_len;
|
||||||
p64->addr = compat_ptr(tmp);
|
v32.msg.data = ptr_to_compat(p64->msg.data);
|
||||||
return 0;
|
return copy_to_user(to, &v32, sizeof(v32)) ? -EFAULT : 0;
|
||||||
}
|
|
||||||
|
|
||||||
static long put_compat_ipmi_recv(struct ipmi_recv *p64,
|
|
||||||
struct compat_ipmi_recv __user *p32)
|
|
||||||
{
|
|
||||||
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
|
|
||||||
__put_user(p64->recv_type, &p32->recv_type) ||
|
|
||||||
__put_user(p64->addr_len, &p32->addr_len) ||
|
|
||||||
__put_user(p64->msgid, &p32->msgid) ||
|
|
||||||
put_compat_ipmi_msg(&p64->msg, &p32->msg))
|
|
||||||
return -EFAULT;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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,
|
|||||||
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,
|
return handle_recv(priv,
|
||||||
((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
|
cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
|
||||||
? IPMICTL_RECEIVE_MSG
|
&recv64, copyout_recv32, compat_ptr(arg));
|
||||||
: 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;
|
|
||||||
}
|
}
|
||||||
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
|
|||||||
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)
|
|||||||
#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,
|
|||||||
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);
|
if (!lock_fb_info(info))
|
||||||
|
return -ENODEV;
|
||||||
old_fs = get_fs();
|
fix = info->fix;
|
||||||
set_fs(KERNEL_DS);
|
unlock_fb_info(info);
|
||||||
err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
|
return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
|
||||||
set_fs(old_fs);
|
|
||||||
|
|
||||||
if (!err)
|
|
||||||
err = do_fscreeninfo_to_user(&fix, fix32);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
|
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
44
fs/select.c
44
fs/select.c
@ -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,
|
|||||||
|
|
||||||
#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,
|
|||||||
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 *);
|
|||||||
|
|
||||||
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);
|
|||||||
|
|
||||||
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 @@
|
|||||||
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
|
||||||
|
|
||||||
|
138
ipc/compat_mq.c
138
ipc/compat_mq.c
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* ipc/compat_mq.c
|
|
||||||
* 32 bit emulation for POSIX message queue system calls
|
|
||||||
*
|
|
||||||
* Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
||||||
* Author: Arnd Bergmann <arnd@arndb.de>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/compat.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/mqueue.h>
|
|
||||||
#include <linux/syscalls.h>
|
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
|
|
||||||
struct compat_mq_attr {
|
|
||||||
compat_long_t mq_flags; /* message queue flags */
|
|
||||||
compat_long_t mq_maxmsg; /* maximum number of messages */
|
|
||||||
compat_long_t mq_msgsize; /* maximum message size */
|
|
||||||
compat_long_t mq_curmsgs; /* number of messages currently queued */
|
|
||||||
compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline int get_compat_mq_attr(struct mq_attr *attr,
|
|
||||||
const struct compat_mq_attr __user *uattr)
|
|
||||||
{
|
|
||||||
if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return __get_user(attr->mq_flags, &uattr->mq_flags)
|
|
||||||
| __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
|
|
||||||
| __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
|
|
||||||
| __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int put_compat_mq_attr(const struct mq_attr *attr,
|
|
||||||
struct compat_mq_attr __user *uattr)
|
|
||||||
{
|
|
||||||
if (clear_user(uattr, sizeof *uattr))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return __put_user(attr->mq_flags, &uattr->mq_flags)
|
|
||||||
| __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
|
|
||||||
| __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
|
|
||||||
| __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
|
|
||||||
int, oflag, compat_mode_t, mode,
|
|
||||||
struct compat_mq_attr __user *, u_attr)
|
|
||||||
{
|
|
||||||
void __user *p = NULL;
|
|
||||||
if (u_attr && oflag & O_CREAT) {
|
|
||||||
struct mq_attr attr;
|
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
|
||||||
|
|
||||||
p = compat_alloc_user_space(sizeof(attr));
|
|
||||||
if (get_compat_mq_attr(&attr, u_attr) ||
|
|
||||||
copy_to_user(p, &attr, sizeof(attr)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
return sys_mq_open(u_name, oflag, mode, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
|
|
||||||
const char __user *, u_msg_ptr,
|
|
||||||
compat_size_t, msg_len, unsigned int, msg_prio,
|
|
||||||
const struct compat_timespec __user *, u_abs_timeout)
|
|
||||||
{
|
|
||||||
struct timespec __user *u_ts;
|
|
||||||
|
|
||||||
if (compat_convert_timespec(&u_ts, u_abs_timeout))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
|
|
||||||
msg_prio, u_ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
|
|
||||||
char __user *, u_msg_ptr,
|
|
||||||
compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
|
|
||||||
const struct compat_timespec __user *, u_abs_timeout)
|
|
||||||
{
|
|
||||||
struct timespec __user *u_ts;
|
|
||||||
|
|
||||||
if (compat_convert_timespec(&u_ts, u_abs_timeout))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
|
|
||||||
u_msg_prio, u_ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|
||||||
const struct compat_sigevent __user *, u_notification)
|
|
||||||
{
|
|
||||||
struct sigevent __user *p = NULL;
|
|
||||||
if (u_notification) {
|
|
||||||
struct sigevent n;
|
|
||||||
p = compat_alloc_user_space(sizeof(*p));
|
|
||||||
if (get_compat_sigevent(&n, u_notification))
|
|
||||||
return -EFAULT;
|
|
||||||
if (n.sigev_notify == SIGEV_THREAD)
|
|
||||||
n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
|
|
||||||
if (copy_to_user(p, &n, sizeof(*p)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
return sys_mq_notify(mqdes, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
|
||||||
const struct compat_mq_attr __user *, u_mqstat,
|
|
||||||
struct compat_mq_attr __user *, u_omqstat)
|
|
||||||
{
|
|
||||||
struct mq_attr mqstat;
|
|
||||||
struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
|
|
||||||
long ret;
|
|
||||||
|
|
||||||
memset(&mqstat, 0, sizeof(mqstat));
|
|
||||||
|
|
||||||
if (u_mqstat) {
|
|
||||||
if (get_compat_mq_attr(&mqstat, u_mqstat) ||
|
|
||||||
copy_to_user(p, &mqstat, sizeof(mqstat)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
ret = sys_mq_getsetattr(mqdes,
|
|
||||||
u_mqstat ? p : NULL,
|
|
||||||
u_omqstat ? p + 1 : NULL);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
if (u_omqstat) {
|
|
||||||
if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
|
|
||||||
put_compat_mq_attr(&mqstat, u_omqstat))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
351
ipc/mqueue.c
351
ipc/mqueue.c
@ -668,14 +668,12 @@ static void __do_notify(struct mqueue_inode_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int prepare_timeout(const struct timespec __user *u_abs_timeout,
|
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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(¬ification, u_notification,
|
|
||||||
sizeof(struct sigevent)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
audit_mq_notify(mqdes, u_notification ? ¬ification : 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
} 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,
|
|||||||
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,
|
|||||||
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;
|
|
||||||
|
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
||||||
|
fdput(f);
|
||||||
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
inode = file_inode(f.file);
|
inode = file_inode(f.file);
|
||||||
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
|
||||||
ret = -EBADF;
|
|
||||||
goto out_fput;
|
|
||||||
}
|
|
||||||
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,18 +1389,169 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&info->lock);
|
spin_unlock(&info->lock);
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
|
|
||||||
sizeof(struct mq_attr)))
|
|
||||||
ret = -EFAULT;
|
|
||||||
|
|
||||||
out_fput:
|
|
||||||
fdput(f);
|
fdput(f);
|
||||||
out:
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
||||||
|
const struct mq_attr __user *, u_mqstat,
|
||||||
|
struct mq_attr __user *, u_omqstat)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct mq_attr mqstat, omqstat;
|
||||||
|
struct mq_attr *new = NULL, *old = NULL;
|
||||||
|
|
||||||
|
if (u_mqstat) {
|
||||||
|
new = &mqstat;
|
||||||
|
if (copy_from_user(new, u_mqstat, sizeof(struct mq_attr)))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if (u_omqstat)
|
||||||
|
old = &omqstat;
|
||||||
|
|
||||||
|
ret = do_mq_getsetattr(mqdes, new, old);
|
||||||
|
if (ret || !old)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (copy_to_user(u_omqstat, old, sizeof(struct mq_attr)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
|
||||||
|
struct compat_mq_attr {
|
||||||
|
compat_long_t mq_flags; /* message queue flags */
|
||||||
|
compat_long_t mq_maxmsg; /* maximum number of messages */
|
||||||
|
compat_long_t mq_msgsize; /* maximum message size */
|
||||||
|
compat_long_t mq_curmsgs; /* number of messages currently queued */
|
||||||
|
compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int get_compat_mq_attr(struct mq_attr *attr,
|
||||||
|
const struct compat_mq_attr __user *uattr)
|
||||||
|
{
|
||||||
|
struct compat_mq_attr v;
|
||||||
|
|
||||||
|
if (copy_from_user(&v, uattr, sizeof(*uattr)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
memset(attr, 0, sizeof(*attr));
|
||||||
|
attr->mq_flags = v.mq_flags;
|
||||||
|
attr->mq_maxmsg = v.mq_maxmsg;
|
||||||
|
attr->mq_msgsize = v.mq_msgsize;
|
||||||
|
attr->mq_curmsgs = v.mq_curmsgs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int put_compat_mq_attr(const struct mq_attr *attr,
|
||||||
|
struct compat_mq_attr __user *uattr)
|
||||||
|
{
|
||||||
|
struct compat_mq_attr v;
|
||||||
|
|
||||||
|
memset(&v, 0, sizeof(v));
|
||||||
|
v.mq_flags = attr->mq_flags;
|
||||||
|
v.mq_maxmsg = attr->mq_maxmsg;
|
||||||
|
v.mq_msgsize = attr->mq_msgsize;
|
||||||
|
v.mq_curmsgs = attr->mq_curmsgs;
|
||||||
|
if (copy_to_user(uattr, &v, sizeof(*uattr)))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
|
||||||
|
int, oflag, compat_mode_t, mode,
|
||||||
|
struct compat_mq_attr __user *, u_attr)
|
||||||
|
{
|
||||||
|
struct mq_attr attr, *p = NULL;
|
||||||
|
if (u_attr && oflag & O_CREAT) {
|
||||||
|
p = &attr;
|
||||||
|
if (get_compat_mq_attr(&attr, u_attr))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
return do_mq_open(u_name, oflag, mode, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compat_prepare_timeout(const struct compat_timespec __user *p,
|
||||||
|
struct timespec *ts)
|
||||||
|
{
|
||||||
|
if (compat_get_timespec(ts, p))
|
||||||
|
return -EFAULT;
|
||||||
|
if (!timespec_valid(ts))
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
|
||||||
|
const char __user *, u_msg_ptr,
|
||||||
|
compat_size_t, msg_len, unsigned int, msg_prio,
|
||||||
|
const struct compat_timespec __user *, u_abs_timeout)
|
||||||
|
{
|
||||||
|
struct timespec ts, *p = NULL;
|
||||||
|
if (u_abs_timeout) {
|
||||||
|
int res = compat_prepare_timeout(u_abs_timeout, &ts);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
p = &ts;
|
||||||
|
}
|
||||||
|
return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
|
||||||
|
char __user *, u_msg_ptr,
|
||||||
|
compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
|
||||||
|
const struct compat_timespec __user *, u_abs_timeout)
|
||||||
|
{
|
||||||
|
struct timespec ts, *p = NULL;
|
||||||
|
if (u_abs_timeout) {
|
||||||
|
int res = compat_prepare_timeout(u_abs_timeout, &ts);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
p = &ts;
|
||||||
|
}
|
||||||
|
return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
||||||
|
const struct compat_sigevent __user *, u_notification)
|
||||||
|
{
|
||||||
|
struct sigevent n, *p = NULL;
|
||||||
|
if (u_notification) {
|
||||||
|
if (get_compat_sigevent(&n, u_notification))
|
||||||
|
return -EFAULT;
|
||||||
|
if (n.sigev_notify == SIGEV_THREAD)
|
||||||
|
n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
|
||||||
|
p = &n;
|
||||||
|
}
|
||||||
|
return do_mq_notify(mqdes, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
||||||
|
const struct compat_mq_attr __user *, u_mqstat,
|
||||||
|
struct compat_mq_attr __user *, u_omqstat)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct mq_attr mqstat, omqstat;
|
||||||
|
struct mq_attr *new = NULL, *old = NULL;
|
||||||
|
|
||||||
|
if (u_mqstat) {
|
||||||
|
new = &mqstat;
|
||||||
|
if (get_compat_mq_attr(new, u_mqstat))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if (u_omqstat)
|
||||||
|
old = &omqstat;
|
||||||
|
|
||||||
|
ret = do_mq_getsetattr(mqdes, new, old);
|
||||||
|
if (ret || !old)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (put_compat_mq_attr(old, u_omqstat))
|
||||||
|
return -EFAULT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct inode_operations mqueue_dir_inode_operations = {
|
static const struct inode_operations mqueue_dir_inode_operations = {
|
||||||
.lookup = simple_lookup,
|
.lookup = simple_lookup,
|
||||||
.create = mqueue_create,
|
.create = mqueue_create,
|
||||||
|
267
kernel/compat.c
267
kernel/compat.c
@ -247,53 +247,6 @@ int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerv
|
|||||||
return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
|
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,
|
|||||||
|
|
||||||
#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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
155
kernel/signal.c
155
kernel/signal.c
@ -2776,7 +2776,7 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
|
|||||||
* @info: if non-null, the signal's siginfo is returned here
|
* @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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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
|
||||||
|
100
kernel/sys.c
100
kernel/sys.c
@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user