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_FADVISE64
|
||||
#define __ARCH_WANT_SYS_GETPGRP
|
||||
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
#define __ARCH_WANT_SYS_OLDUMOUNT
|
||||
#define __ARCH_WANT_SYS_SIGPENDING
|
||||
#define __ARCH_WANT_SYS_FORK
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#define __ARCH_WANT_SYS_FADVISE64
|
||||
#define __ARCH_WANT_SYS_GETPGRP
|
||||
#define __ARCH_WANT_SYS_LLSEEK
|
||||
#define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
|
||||
#define __ARCH_WANT_SYS_OLDUMOUNT
|
||||
#define __ARCH_WANT_SYS_CLONE
|
||||
#define __ARCH_WANT_SYS_FORK
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#define __ARCH_WANT_SYS_GETPGRP
|
||||
#define __ARCH_WANT_SYS_LLSEEK
|
||||
#define __ARCH_WANT_SYS_NICE
|
||||
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
#define __ARCH_WANT_SYS_OLD_UNAME
|
||||
#define __ARCH_WANT_SYS_OLDUMOUNT
|
||||
#define __ARCH_WANT_SYS_SIGPENDING
|
||||
|
|
|
@ -156,7 +156,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
|
|||
#define __ARCH_WANT_SYS_GETPGRP
|
||||
#define __ARCH_WANT_SYS_LLSEEK
|
||||
#define __ARCH_WANT_SYS_NICE
|
||||
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
#define __ARCH_WANT_SYS_OLDUMOUNT
|
||||
#define __ARCH_WANT_SYS_SIGPENDING
|
||||
#define __ARCH_WANT_SYS_SIGPROCMASK
|
||||
|
|
|
@ -109,7 +109,6 @@ struct compat_statfs {
|
|||
int f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
#define COMPAT_RLIM_INFINITY 0xffffffff
|
||||
|
||||
typedef u32 compat_old_sigset_t;
|
||||
|
|
|
@ -178,7 +178,6 @@ struct compat_statfs64 {
|
|||
u32 f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
#define COMPAT_RLIM_INFINITY 0xffffffff
|
||||
|
||||
typedef u32 compat_old_sigset_t; /* at least 32 bits */
|
||||
|
|
|
@ -116,7 +116,6 @@ struct compat_statfs {
|
|||
int f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
#define COMPAT_RLIM_INFINITY 0xffffffff
|
||||
|
||||
typedef u32 compat_old_sigset_t; /* at least 32 bits */
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <linux/cdrom.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/elevator.h>
|
||||
#include <linux/fd.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
|
@ -80,19 +79,16 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
|
|||
static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
mm_segment_t old_fs = get_fs();
|
||||
unsigned long kval;
|
||||
unsigned int __user *uvp;
|
||||
unsigned long *__user p;
|
||||
int error;
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
p = compat_alloc_user_space(sizeof(unsigned long));
|
||||
error = __blkdev_driver_ioctl(bdev, mode,
|
||||
cmd, (unsigned long)(&kval));
|
||||
set_fs(old_fs);
|
||||
|
||||
cmd, (unsigned long)p);
|
||||
if (error == 0) {
|
||||
uvp = compat_ptr(arg);
|
||||
if (put_user(kval, uvp))
|
||||
unsigned int __user *uvp = compat_ptr(arg);
|
||||
unsigned long v;
|
||||
if (get_user(v, p) || put_user(v, uvp))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
|
@ -209,318 +205,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
#define BLKBSZSET_32 _IOW(0x12, 113, int)
|
||||
#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
|
||||
|
||||
struct compat_floppy_drive_params {
|
||||
char cmos;
|
||||
compat_ulong_t max_dtr;
|
||||
compat_ulong_t hlt;
|
||||
compat_ulong_t hut;
|
||||
compat_ulong_t srt;
|
||||
compat_ulong_t spinup;
|
||||
compat_ulong_t spindown;
|
||||
unsigned char spindown_offset;
|
||||
unsigned char select_delay;
|
||||
unsigned char rps;
|
||||
unsigned char tracks;
|
||||
compat_ulong_t timeout;
|
||||
unsigned char interleave_sect;
|
||||
struct floppy_max_errors max_errors;
|
||||
char flags;
|
||||
char read_track;
|
||||
short autodetect[8];
|
||||
compat_int_t checkfreq;
|
||||
compat_int_t native_format;
|
||||
};
|
||||
|
||||
struct compat_floppy_drive_struct {
|
||||
signed char flags;
|
||||
compat_ulong_t spinup_date;
|
||||
compat_ulong_t select_date;
|
||||
compat_ulong_t first_read_date;
|
||||
short probed_format;
|
||||
short track;
|
||||
short maxblock;
|
||||
short maxtrack;
|
||||
compat_int_t generation;
|
||||
compat_int_t keep_data;
|
||||
compat_int_t fd_ref;
|
||||
compat_int_t fd_device;
|
||||
compat_int_t last_checked;
|
||||
compat_caddr_t dmabuf;
|
||||
compat_int_t bufblocks;
|
||||
};
|
||||
|
||||
struct compat_floppy_fdc_state {
|
||||
compat_int_t spec1;
|
||||
compat_int_t spec2;
|
||||
compat_int_t dtr;
|
||||
unsigned char version;
|
||||
unsigned char dor;
|
||||
compat_ulong_t address;
|
||||
unsigned int rawcmd:2;
|
||||
unsigned int reset:1;
|
||||
unsigned int need_configure:1;
|
||||
unsigned int perp_mode:2;
|
||||
unsigned int has_fifo:1;
|
||||
unsigned int driver_version;
|
||||
unsigned char track[4];
|
||||
};
|
||||
|
||||
struct compat_floppy_write_errors {
|
||||
unsigned int write_errors;
|
||||
compat_ulong_t first_error_sector;
|
||||
compat_int_t first_error_generation;
|
||||
compat_ulong_t last_error_sector;
|
||||
compat_int_t last_error_generation;
|
||||
compat_uint_t badness;
|
||||
};
|
||||
|
||||
#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
|
||||
#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
|
||||
#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
|
||||
#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
|
||||
#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
|
||||
#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
|
||||
#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
|
||||
#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
|
||||
|
||||
static struct {
|
||||
unsigned int cmd32;
|
||||
unsigned int cmd;
|
||||
} fd_ioctl_trans_table[] = {
|
||||
{ FDSETPRM32, FDSETPRM },
|
||||
{ FDDEFPRM32, FDDEFPRM },
|
||||
{ FDGETPRM32, FDGETPRM },
|
||||
{ FDSETDRVPRM32, FDSETDRVPRM },
|
||||
{ FDGETDRVPRM32, FDGETDRVPRM },
|
||||
{ FDGETDRVSTAT32, FDGETDRVSTAT },
|
||||
{ FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
|
||||
{ FDGETFDCSTAT32, FDGETFDCSTAT },
|
||||
{ FDWERRORGET32, FDWERRORGET }
|
||||
};
|
||||
|
||||
#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
|
||||
|
||||
static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
mm_segment_t old_fs = get_fs();
|
||||
void *karg = NULL;
|
||||
unsigned int kcmd = 0;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
|
||||
if (cmd == fd_ioctl_trans_table[i].cmd32) {
|
||||
kcmd = fd_ioctl_trans_table[i].cmd;
|
||||
break;
|
||||
}
|
||||
if (!kcmd)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case FDSETPRM32:
|
||||
case FDDEFPRM32:
|
||||
case FDGETPRM32:
|
||||
{
|
||||
compat_uptr_t name;
|
||||
struct compat_floppy_struct __user *uf;
|
||||
struct floppy_struct *f;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
if (cmd == FDGETPRM32)
|
||||
break;
|
||||
err = __get_user(f->size, &uf->size);
|
||||
err |= __get_user(f->sect, &uf->sect);
|
||||
err |= __get_user(f->head, &uf->head);
|
||||
err |= __get_user(f->track, &uf->track);
|
||||
err |= __get_user(f->stretch, &uf->stretch);
|
||||
err |= __get_user(f->gap, &uf->gap);
|
||||
err |= __get_user(f->rate, &uf->rate);
|
||||
err |= __get_user(f->spec1, &uf->spec1);
|
||||
err |= __get_user(f->fmt_gap, &uf->fmt_gap);
|
||||
err |= __get_user(name, &uf->name);
|
||||
f->name = compat_ptr(name);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FDSETDRVPRM32:
|
||||
case FDGETDRVPRM32:
|
||||
{
|
||||
struct compat_floppy_drive_params __user *uf;
|
||||
struct floppy_drive_params *f;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
if (cmd == FDGETDRVPRM32)
|
||||
break;
|
||||
err = __get_user(f->cmos, &uf->cmos);
|
||||
err |= __get_user(f->max_dtr, &uf->max_dtr);
|
||||
err |= __get_user(f->hlt, &uf->hlt);
|
||||
err |= __get_user(f->hut, &uf->hut);
|
||||
err |= __get_user(f->srt, &uf->srt);
|
||||
err |= __get_user(f->spinup, &uf->spinup);
|
||||
err |= __get_user(f->spindown, &uf->spindown);
|
||||
err |= __get_user(f->spindown_offset, &uf->spindown_offset);
|
||||
err |= __get_user(f->select_delay, &uf->select_delay);
|
||||
err |= __get_user(f->rps, &uf->rps);
|
||||
err |= __get_user(f->tracks, &uf->tracks);
|
||||
err |= __get_user(f->timeout, &uf->timeout);
|
||||
err |= __get_user(f->interleave_sect, &uf->interleave_sect);
|
||||
err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
|
||||
err |= __get_user(f->flags, &uf->flags);
|
||||
err |= __get_user(f->read_track, &uf->read_track);
|
||||
err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
|
||||
err |= __get_user(f->checkfreq, &uf->checkfreq);
|
||||
err |= __get_user(f->native_format, &uf->native_format);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FDGETDRVSTAT32:
|
||||
case FDPOLLDRVSTAT32:
|
||||
karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
case FDGETFDCSTAT32:
|
||||
karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
case FDWERRORGET32:
|
||||
karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
set_fs(KERNEL_DS);
|
||||
err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
|
||||
set_fs(old_fs);
|
||||
if (err)
|
||||
goto out;
|
||||
switch (cmd) {
|
||||
case FDGETPRM32:
|
||||
{
|
||||
struct floppy_struct *f = karg;
|
||||
struct compat_floppy_struct __user *uf = compat_ptr(arg);
|
||||
|
||||
err = __put_user(f->size, &uf->size);
|
||||
err |= __put_user(f->sect, &uf->sect);
|
||||
err |= __put_user(f->head, &uf->head);
|
||||
err |= __put_user(f->track, &uf->track);
|
||||
err |= __put_user(f->stretch, &uf->stretch);
|
||||
err |= __put_user(f->gap, &uf->gap);
|
||||
err |= __put_user(f->rate, &uf->rate);
|
||||
err |= __put_user(f->spec1, &uf->spec1);
|
||||
err |= __put_user(f->fmt_gap, &uf->fmt_gap);
|
||||
err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
|
||||
break;
|
||||
}
|
||||
case FDGETDRVPRM32:
|
||||
{
|
||||
struct compat_floppy_drive_params __user *uf;
|
||||
struct floppy_drive_params *f = karg;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
err = __put_user(f->cmos, &uf->cmos);
|
||||
err |= __put_user(f->max_dtr, &uf->max_dtr);
|
||||
err |= __put_user(f->hlt, &uf->hlt);
|
||||
err |= __put_user(f->hut, &uf->hut);
|
||||
err |= __put_user(f->srt, &uf->srt);
|
||||
err |= __put_user(f->spinup, &uf->spinup);
|
||||
err |= __put_user(f->spindown, &uf->spindown);
|
||||
err |= __put_user(f->spindown_offset, &uf->spindown_offset);
|
||||
err |= __put_user(f->select_delay, &uf->select_delay);
|
||||
err |= __put_user(f->rps, &uf->rps);
|
||||
err |= __put_user(f->tracks, &uf->tracks);
|
||||
err |= __put_user(f->timeout, &uf->timeout);
|
||||
err |= __put_user(f->interleave_sect, &uf->interleave_sect);
|
||||
err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
|
||||
err |= __put_user(f->flags, &uf->flags);
|
||||
err |= __put_user(f->read_track, &uf->read_track);
|
||||
err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
|
||||
err |= __put_user(f->checkfreq, &uf->checkfreq);
|
||||
err |= __put_user(f->native_format, &uf->native_format);
|
||||
break;
|
||||
}
|
||||
case FDGETDRVSTAT32:
|
||||
case FDPOLLDRVSTAT32:
|
||||
{
|
||||
struct compat_floppy_drive_struct __user *uf;
|
||||
struct floppy_drive_struct *f = karg;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
err = __put_user(f->flags, &uf->flags);
|
||||
err |= __put_user(f->spinup_date, &uf->spinup_date);
|
||||
err |= __put_user(f->select_date, &uf->select_date);
|
||||
err |= __put_user(f->first_read_date, &uf->first_read_date);
|
||||
err |= __put_user(f->probed_format, &uf->probed_format);
|
||||
err |= __put_user(f->track, &uf->track);
|
||||
err |= __put_user(f->maxblock, &uf->maxblock);
|
||||
err |= __put_user(f->maxtrack, &uf->maxtrack);
|
||||
err |= __put_user(f->generation, &uf->generation);
|
||||
err |= __put_user(f->keep_data, &uf->keep_data);
|
||||
err |= __put_user(f->fd_ref, &uf->fd_ref);
|
||||
err |= __put_user(f->fd_device, &uf->fd_device);
|
||||
err |= __put_user(f->last_checked, &uf->last_checked);
|
||||
err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
|
||||
err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
|
||||
break;
|
||||
}
|
||||
case FDGETFDCSTAT32:
|
||||
{
|
||||
struct compat_floppy_fdc_state __user *uf;
|
||||
struct floppy_fdc_state *f = karg;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
err = __put_user(f->spec1, &uf->spec1);
|
||||
err |= __put_user(f->spec2, &uf->spec2);
|
||||
err |= __put_user(f->dtr, &uf->dtr);
|
||||
err |= __put_user(f->version, &uf->version);
|
||||
err |= __put_user(f->dor, &uf->dor);
|
||||
err |= __put_user(f->address, &uf->address);
|
||||
err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
|
||||
(char *)&f->address + sizeof(f->address), sizeof(int));
|
||||
err |= __put_user(f->driver_version, &uf->driver_version);
|
||||
err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
|
||||
break;
|
||||
}
|
||||
case FDWERRORGET32:
|
||||
{
|
||||
struct compat_floppy_write_errors __user *uf;
|
||||
struct floppy_write_errors *f = karg;
|
||||
|
||||
uf = compat_ptr(arg);
|
||||
err = __put_user(f->write_errors, &uf->write_errors);
|
||||
err |= __put_user(f->first_error_sector, &uf->first_error_sector);
|
||||
err |= __put_user(f->first_error_generation, &uf->first_error_generation);
|
||||
err |= __put_user(f->last_error_sector, &uf->last_error_sector);
|
||||
err |= __put_user(f->last_error_generation, &uf->last_error_generation);
|
||||
err |= __put_user(f->badness, &uf->badness);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
err = -EFAULT;
|
||||
|
||||
out:
|
||||
kfree(karg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -537,16 +221,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
case HDIO_GET_ADDRESS:
|
||||
case HDIO_GET_BUSSTATE:
|
||||
return compat_hdio_ioctl(bdev, mode, cmd, arg);
|
||||
case FDSETPRM32:
|
||||
case FDDEFPRM32:
|
||||
case FDGETPRM32:
|
||||
case FDSETDRVPRM32:
|
||||
case FDGETDRVPRM32:
|
||||
case FDGETDRVSTAT32:
|
||||
case FDPOLLDRVSTAT32:
|
||||
case FDGETFDCSTAT32:
|
||||
case FDWERRORGET32:
|
||||
return compat_fd_ioctl(bdev, mode, cmd, arg);
|
||||
case CDROMREADAUDIO:
|
||||
return compat_cdrom_read_audio(bdev, mode, cmd, arg);
|
||||
case CDROM_SEND_PACKET:
|
||||
|
@ -566,23 +240,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
case HDIO_DRIVE_CMD:
|
||||
/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
|
||||
case 0x330:
|
||||
/* 0x02 -- Floppy ioctls */
|
||||
case FDMSGON:
|
||||
case FDMSGOFF:
|
||||
case FDSETEMSGTRESH:
|
||||
case FDFLUSH:
|
||||
case FDWERRORCLR:
|
||||
case FDSETMAXERRS:
|
||||
case FDGETMAXERRS:
|
||||
case FDGETDRVTYP:
|
||||
case FDEJECT:
|
||||
case FDCLRPRM:
|
||||
case FDFMTBEG:
|
||||
case FDFMTEND:
|
||||
case FDRESET:
|
||||
case FDTWADDLE:
|
||||
case FDFMTTRK:
|
||||
case FDRAWCMD:
|
||||
/* CDROM stuff */
|
||||
case CDROMPAUSE:
|
||||
case CDROMRESUME:
|
||||
|
|
|
@ -192,6 +192,7 @@ static int print_unex = 1;
|
|||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
/*
|
||||
* PS/2 floppies have much slower step rates than regular floppies.
|
||||
|
@ -3568,6 +3569,330 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
struct compat_floppy_drive_params {
|
||||
char cmos;
|
||||
compat_ulong_t max_dtr;
|
||||
compat_ulong_t hlt;
|
||||
compat_ulong_t hut;
|
||||
compat_ulong_t srt;
|
||||
compat_ulong_t spinup;
|
||||
compat_ulong_t spindown;
|
||||
unsigned char spindown_offset;
|
||||
unsigned char select_delay;
|
||||
unsigned char rps;
|
||||
unsigned char tracks;
|
||||
compat_ulong_t timeout;
|
||||
unsigned char interleave_sect;
|
||||
struct floppy_max_errors max_errors;
|
||||
char flags;
|
||||
char read_track;
|
||||
short autodetect[8];
|
||||
compat_int_t checkfreq;
|
||||
compat_int_t native_format;
|
||||
};
|
||||
|
||||
struct compat_floppy_drive_struct {
|
||||
signed char flags;
|
||||
compat_ulong_t spinup_date;
|
||||
compat_ulong_t select_date;
|
||||
compat_ulong_t first_read_date;
|
||||
short probed_format;
|
||||
short track;
|
||||
short maxblock;
|
||||
short maxtrack;
|
||||
compat_int_t generation;
|
||||
compat_int_t keep_data;
|
||||
compat_int_t fd_ref;
|
||||
compat_int_t fd_device;
|
||||
compat_int_t last_checked;
|
||||
compat_caddr_t dmabuf;
|
||||
compat_int_t bufblocks;
|
||||
};
|
||||
|
||||
struct compat_floppy_fdc_state {
|
||||
compat_int_t spec1;
|
||||
compat_int_t spec2;
|
||||
compat_int_t dtr;
|
||||
unsigned char version;
|
||||
unsigned char dor;
|
||||
compat_ulong_t address;
|
||||
unsigned int rawcmd:2;
|
||||
unsigned int reset:1;
|
||||
unsigned int need_configure:1;
|
||||
unsigned int perp_mode:2;
|
||||
unsigned int has_fifo:1;
|
||||
unsigned int driver_version;
|
||||
unsigned char track[4];
|
||||
};
|
||||
|
||||
struct compat_floppy_write_errors {
|
||||
unsigned int write_errors;
|
||||
compat_ulong_t first_error_sector;
|
||||
compat_int_t first_error_generation;
|
||||
compat_ulong_t last_error_sector;
|
||||
compat_int_t last_error_generation;
|
||||
compat_uint_t badness;
|
||||
};
|
||||
|
||||
#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
|
||||
#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
|
||||
#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
|
||||
#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
|
||||
#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
|
||||
#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
|
||||
#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
|
||||
#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
|
||||
|
||||
static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
||||
struct compat_floppy_struct __user *arg)
|
||||
{
|
||||
struct floppy_struct v;
|
||||
int drive, type;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
|
||||
offsetof(struct compat_floppy_struct, name));
|
||||
|
||||
if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
|
||||
return -EPERM;
|
||||
|
||||
memset(&v, 0, sizeof(struct floppy_struct));
|
||||
if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&floppy_mutex);
|
||||
drive = (long)bdev->bd_disk->private_data;
|
||||
type = ITYPE(UDRS->fd_device);
|
||||
err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
|
||||
&v, drive, type, bdev);
|
||||
mutex_unlock(&floppy_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int compat_get_prm(int drive,
|
||||
struct compat_floppy_struct __user *arg)
|
||||
{
|
||||
struct compat_floppy_struct v;
|
||||
struct floppy_struct *p;
|
||||
int err;
|
||||
|
||||
memset(&v, 0, sizeof(v));
|
||||
mutex_lock(&floppy_mutex);
|
||||
err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
|
||||
if (err) {
|
||||
mutex_unlock(&floppy_mutex);
|
||||
return err;
|
||||
}
|
||||
memcpy(&v, p, offsetof(struct floppy_struct, name));
|
||||
mutex_unlock(&floppy_mutex);
|
||||
if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compat_setdrvprm(int drive,
|
||||
struct compat_floppy_drive_params __user *arg)
|
||||
{
|
||||
struct compat_floppy_drive_params v;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
|
||||
return -EFAULT;
|
||||
mutex_lock(&floppy_mutex);
|
||||
UDP->cmos = v.cmos;
|
||||
UDP->max_dtr = v.max_dtr;
|
||||
UDP->hlt = v.hlt;
|
||||
UDP->hut = v.hut;
|
||||
UDP->srt = v.srt;
|
||||
UDP->spinup = v.spinup;
|
||||
UDP->spindown = v.spindown;
|
||||
UDP->spindown_offset = v.spindown_offset;
|
||||
UDP->select_delay = v.select_delay;
|
||||
UDP->rps = v.rps;
|
||||
UDP->tracks = v.tracks;
|
||||
UDP->timeout = v.timeout;
|
||||
UDP->interleave_sect = v.interleave_sect;
|
||||
UDP->max_errors = v.max_errors;
|
||||
UDP->flags = v.flags;
|
||||
UDP->read_track = v.read_track;
|
||||
memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
|
||||
UDP->checkfreq = v.checkfreq;
|
||||
UDP->native_format = v.native_format;
|
||||
mutex_unlock(&floppy_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compat_getdrvprm(int drive,
|
||||
struct compat_floppy_drive_params __user *arg)
|
||||
{
|
||||
struct compat_floppy_drive_params v;
|
||||
|
||||
memset(&v, 0, sizeof(struct compat_floppy_drive_params));
|
||||
mutex_lock(&floppy_mutex);
|
||||
v.cmos = UDP->cmos;
|
||||
v.max_dtr = UDP->max_dtr;
|
||||
v.hlt = UDP->hlt;
|
||||
v.hut = UDP->hut;
|
||||
v.srt = UDP->srt;
|
||||
v.spinup = UDP->spinup;
|
||||
v.spindown = UDP->spindown;
|
||||
v.spindown_offset = UDP->spindown_offset;
|
||||
v.select_delay = UDP->select_delay;
|
||||
v.rps = UDP->rps;
|
||||
v.tracks = UDP->tracks;
|
||||
v.timeout = UDP->timeout;
|
||||
v.interleave_sect = UDP->interleave_sect;
|
||||
v.max_errors = UDP->max_errors;
|
||||
v.flags = UDP->flags;
|
||||
v.read_track = UDP->read_track;
|
||||
memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
|
||||
v.checkfreq = UDP->checkfreq;
|
||||
v.native_format = UDP->native_format;
|
||||
mutex_unlock(&floppy_mutex);
|
||||
|
||||
if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compat_getdrvstat(int drive, bool poll,
|
||||
struct compat_floppy_drive_struct __user *arg)
|
||||
{
|
||||
struct compat_floppy_drive_struct v;
|
||||
|
||||
memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
|
||||
mutex_lock(&floppy_mutex);
|
||||
|
||||
if (poll) {
|
||||
if (lock_fdc(drive))
|
||||
goto Eintr;
|
||||
if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
|
||||
goto Eintr;
|
||||
process_fd_request();
|
||||
}
|
||||
v.spinup_date = UDRS->spinup_date;
|
||||
v.select_date = UDRS->select_date;
|
||||
v.first_read_date = UDRS->first_read_date;
|
||||
v.probed_format = UDRS->probed_format;
|
||||
v.track = UDRS->track;
|
||||
v.maxblock = UDRS->maxblock;
|
||||
v.maxtrack = UDRS->maxtrack;
|
||||
v.generation = UDRS->generation;
|
||||
v.keep_data = UDRS->keep_data;
|
||||
v.fd_ref = UDRS->fd_ref;
|
||||
v.fd_device = UDRS->fd_device;
|
||||
v.last_checked = UDRS->last_checked;
|
||||
v.dmabuf = (uintptr_t)UDRS->dmabuf;
|
||||
v.bufblocks = UDRS->bufblocks;
|
||||
mutex_unlock(&floppy_mutex);
|
||||
|
||||
if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
Eintr:
|
||||
mutex_unlock(&floppy_mutex);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
static int compat_getfdcstat(int drive,
|
||||
struct compat_floppy_fdc_state __user *arg)
|
||||
{
|
||||
struct compat_floppy_fdc_state v32;
|
||||
struct floppy_fdc_state v;
|
||||
|
||||
mutex_lock(&floppy_mutex);
|
||||
v = *UFDCS;
|
||||
mutex_unlock(&floppy_mutex);
|
||||
|
||||
memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
|
||||
v32.spec1 = v.spec1;
|
||||
v32.spec2 = v.spec2;
|
||||
v32.dtr = v.dtr;
|
||||
v32.version = v.version;
|
||||
v32.dor = v.dor;
|
||||
v32.address = v.address;
|
||||
v32.rawcmd = v.rawcmd;
|
||||
v32.reset = v.reset;
|
||||
v32.need_configure = v.need_configure;
|
||||
v32.perp_mode = v.perp_mode;
|
||||
v32.has_fifo = v.has_fifo;
|
||||
v32.driver_version = v.driver_version;
|
||||
memcpy(v32.track, v.track, 4);
|
||||
if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compat_werrorget(int drive,
|
||||
struct compat_floppy_write_errors __user *arg)
|
||||
{
|
||||
struct compat_floppy_write_errors v32;
|
||||
struct floppy_write_errors v;
|
||||
|
||||
memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
|
||||
mutex_lock(&floppy_mutex);
|
||||
v = *UDRWE;
|
||||
mutex_unlock(&floppy_mutex);
|
||||
v32.write_errors = v.write_errors;
|
||||
v32.first_error_sector = v.first_error_sector;
|
||||
v32.first_error_generation = v.first_error_generation;
|
||||
v32.last_error_sector = v.last_error_sector;
|
||||
v32.last_error_generation = v.last_error_generation;
|
||||
v32.badness = v.badness;
|
||||
if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
||||
unsigned long param)
|
||||
{
|
||||
int drive = (long)bdev->bd_disk->private_data;
|
||||
switch (cmd) {
|
||||
case FDMSGON:
|
||||
case FDMSGOFF:
|
||||
case FDSETEMSGTRESH:
|
||||
case FDFLUSH:
|
||||
case FDWERRORCLR:
|
||||
case FDEJECT:
|
||||
case FDCLRPRM:
|
||||
case FDFMTBEG:
|
||||
case FDRESET:
|
||||
case FDTWADDLE:
|
||||
return fd_ioctl(bdev, mode, cmd, param);
|
||||
case FDSETMAXERRS:
|
||||
case FDGETMAXERRS:
|
||||
case FDGETDRVTYP:
|
||||
case FDFMTEND:
|
||||
case FDFMTTRK:
|
||||
case FDRAWCMD:
|
||||
return fd_ioctl(bdev, mode, cmd,
|
||||
(unsigned long)compat_ptr(param));
|
||||
case FDSETPRM32:
|
||||
case FDDEFPRM32:
|
||||
return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
|
||||
case FDGETPRM32:
|
||||
return compat_get_prm(drive, compat_ptr(param));
|
||||
case FDSETDRVPRM32:
|
||||
return compat_setdrvprm(drive, compat_ptr(param));
|
||||
case FDGETDRVPRM32:
|
||||
return compat_getdrvprm(drive, compat_ptr(param));
|
||||
case FDPOLLDRVSTAT32:
|
||||
return compat_getdrvstat(drive, true, compat_ptr(param));
|
||||
case FDGETDRVSTAT32:
|
||||
return compat_getdrvstat(drive, false, compat_ptr(param));
|
||||
case FDGETFDCSTAT32:
|
||||
return compat_getfdcstat(drive, compat_ptr(param));
|
||||
case FDWERRORGET32:
|
||||
return compat_werrorget(drive, compat_ptr(param));
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init config_types(void)
|
||||
{
|
||||
bool has_drive = false;
|
||||
|
@ -3885,6 +4210,9 @@ static const struct block_device_operations floppy_fops = {
|
|||
.getgeo = fd_getgeo,
|
||||
.check_events = floppy_check_events,
|
||||
.revalidate_disk = floppy_revalidate,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = fd_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -231,6 +231,102 @@ static int handle_send_req(ipmi_user_t user,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static int handle_recv(struct ipmi_file_private *priv,
|
||||
bool trunc, struct ipmi_recv *rsp,
|
||||
int (*copyout)(struct ipmi_recv *, void __user *),
|
||||
void __user *to)
|
||||
{
|
||||
int addr_len;
|
||||
struct list_head *entry;
|
||||
struct ipmi_recv_msg *msg;
|
||||
unsigned long flags;
|
||||
int rv = 0;
|
||||
|
||||
/* We claim a mutex because we don't want two
|
||||
users getting something from the queue at a time.
|
||||
Since we have to release the spinlock before we can
|
||||
copy the data to the user, it's possible another
|
||||
user will grab something from the queue, too. Then
|
||||
the messages might get out of order if something
|
||||
fails and the message gets put back onto the
|
||||
queue. This mutex prevents that problem. */
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
|
||||
/* Grab the message off the list. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
if (list_empty(&(priv->recv_msgs))) {
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
rv = -EAGAIN;
|
||||
goto recv_err;
|
||||
}
|
||||
entry = priv->recv_msgs.next;
|
||||
msg = list_entry(entry, struct ipmi_recv_msg, link);
|
||||
list_del(entry);
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
|
||||
addr_len = ipmi_addr_length(msg->addr.addr_type);
|
||||
if (rsp->addr_len < addr_len)
|
||||
{
|
||||
rv = -EINVAL;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
||||
if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
rsp->addr_len = addr_len;
|
||||
|
||||
rsp->recv_type = msg->recv_type;
|
||||
rsp->msgid = msg->msgid;
|
||||
rsp->msg.netfn = msg->msg.netfn;
|
||||
rsp->msg.cmd = msg->msg.cmd;
|
||||
|
||||
if (msg->msg.data_len > 0) {
|
||||
if (rsp->msg.data_len < msg->msg.data_len) {
|
||||
rv = -EMSGSIZE;
|
||||
if (trunc)
|
||||
msg->msg.data_len = rsp->msg.data_len;
|
||||
else
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
||||
if (copy_to_user(rsp->msg.data,
|
||||
msg->msg.data,
|
||||
msg->msg.data_len))
|
||||
{
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
rsp->msg.data_len = msg->msg.data_len;
|
||||
} else {
|
||||
rsp->msg.data_len = 0;
|
||||
}
|
||||
|
||||
rv = copyout(rsp, to);
|
||||
if (rv)
|
||||
goto recv_putback_on_err;
|
||||
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
ipmi_free_recv_msg(msg);
|
||||
return 0;
|
||||
|
||||
recv_putback_on_err:
|
||||
/* If we got an error, put the message back onto
|
||||
the head of the queue. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
list_add(entry, &(priv->recv_msgs));
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
recv_err:
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
|
||||
{
|
||||
return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int ipmi_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long data)
|
||||
|
@ -277,100 +373,12 @@ static int ipmi_ioctl(struct file *file,
|
|||
case IPMICTL_RECEIVE_MSG_TRUNC:
|
||||
{
|
||||
struct ipmi_recv rsp;
|
||||
int addr_len;
|
||||
struct list_head *entry;
|
||||
struct ipmi_recv_msg *msg;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
rv = 0;
|
||||
if (copy_from_user(&rsp, arg, sizeof(rsp))) {
|
||||
if (copy_from_user(&rsp, arg, sizeof(rsp)))
|
||||
rv = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We claim a mutex because we don't want two
|
||||
users getting something from the queue at a time.
|
||||
Since we have to release the spinlock before we can
|
||||
copy the data to the user, it's possible another
|
||||
user will grab something from the queue, too. Then
|
||||
the messages might get out of order if something
|
||||
fails and the message gets put back onto the
|
||||
queue. This mutex prevents that problem. */
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
|
||||
/* Grab the message off the list. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
if (list_empty(&(priv->recv_msgs))) {
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
rv = -EAGAIN;
|
||||
goto recv_err;
|
||||
}
|
||||
entry = priv->recv_msgs.next;
|
||||
msg = list_entry(entry, struct ipmi_recv_msg, link);
|
||||
list_del(entry);
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
|
||||
addr_len = ipmi_addr_length(msg->addr.addr_type);
|
||||
if (rsp.addr_len < addr_len)
|
||||
{
|
||||
rv = -EINVAL;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
||||
if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
rsp.addr_len = addr_len;
|
||||
|
||||
rsp.recv_type = msg->recv_type;
|
||||
rsp.msgid = msg->msgid;
|
||||
rsp.msg.netfn = msg->msg.netfn;
|
||||
rsp.msg.cmd = msg->msg.cmd;
|
||||
|
||||
if (msg->msg.data_len > 0) {
|
||||
if (rsp.msg.data_len < msg->msg.data_len) {
|
||||
rv = -EMSGSIZE;
|
||||
if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
|
||||
msg->msg.data_len = rsp.msg.data_len;
|
||||
} else {
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy_to_user(rsp.msg.data,
|
||||
msg->msg.data,
|
||||
msg->msg.data_len))
|
||||
{
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
rsp.msg.data_len = msg->msg.data_len;
|
||||
} else {
|
||||
rsp.msg.data_len = 0;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &rsp, sizeof(rsp))) {
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
ipmi_free_recv_msg(msg);
|
||||
break;
|
||||
|
||||
recv_putback_on_err:
|
||||
/* If we got an error, put the message back onto
|
||||
the head of the queue. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
list_add(entry, &(priv->recv_msgs));
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
break;
|
||||
|
||||
recv_err:
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
else
|
||||
rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
|
||||
&rsp, copyout_recv, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -696,85 +704,56 @@ struct compat_ipmi_req_settime {
|
|||
/*
|
||||
* Define some helper functions for copying IPMI data
|
||||
*/
|
||||
static long get_compat_ipmi_msg(struct ipmi_msg *p64,
|
||||
struct compat_ipmi_msg __user *p32)
|
||||
static void get_compat_ipmi_msg(struct ipmi_msg *p64,
|
||||
struct compat_ipmi_msg *p32)
|
||||
{
|
||||
compat_uptr_t tmp;
|
||||
|
||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
||||
__get_user(p64->netfn, &p32->netfn) ||
|
||||
__get_user(p64->cmd, &p32->cmd) ||
|
||||
__get_user(p64->data_len, &p32->data_len) ||
|
||||
__get_user(tmp, &p32->data))
|
||||
return -EFAULT;
|
||||
p64->data = compat_ptr(tmp);
|
||||
return 0;
|
||||
p64->netfn = p32->netfn;
|
||||
p64->cmd = p32->cmd;
|
||||
p64->data_len = p32->data_len;
|
||||
p64->data = compat_ptr(p32->data);
|
||||
}
|
||||
|
||||
static long put_compat_ipmi_msg(struct ipmi_msg *p64,
|
||||
struct compat_ipmi_msg __user *p32)
|
||||
static void get_compat_ipmi_req(struct ipmi_req *p64,
|
||||
struct compat_ipmi_req *p32)
|
||||
{
|
||||
if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
|
||||
__put_user(p64->netfn, &p32->netfn) ||
|
||||
__put_user(p64->cmd, &p32->cmd) ||
|
||||
__put_user(p64->data_len, &p32->data_len))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
p64->addr = compat_ptr(p32->addr);
|
||||
p64->addr_len = p32->addr_len;
|
||||
p64->msgid = p32->msgid;
|
||||
get_compat_ipmi_msg(&p64->msg, &p32->msg);
|
||||
}
|
||||
|
||||
static long get_compat_ipmi_req(struct ipmi_req *p64,
|
||||
struct compat_ipmi_req __user *p32)
|
||||
static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
|
||||
struct compat_ipmi_req_settime *p32)
|
||||
{
|
||||
|
||||
compat_uptr_t tmp;
|
||||
|
||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
||||
__get_user(tmp, &p32->addr) ||
|
||||
__get_user(p64->addr_len, &p32->addr_len) ||
|
||||
__get_user(p64->msgid, &p32->msgid) ||
|
||||
get_compat_ipmi_msg(&p64->msg, &p32->msg))
|
||||
return -EFAULT;
|
||||
p64->addr = compat_ptr(tmp);
|
||||
return 0;
|
||||
get_compat_ipmi_req(&p64->req, &p32->req);
|
||||
p64->retries = p32->retries;
|
||||
p64->retry_time_ms = p32->retry_time_ms;
|
||||
}
|
||||
|
||||
static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
|
||||
struct compat_ipmi_req_settime __user *p32)
|
||||
static void get_compat_ipmi_recv(struct ipmi_recv *p64,
|
||||
struct compat_ipmi_recv *p32)
|
||||
{
|
||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
||||
get_compat_ipmi_req(&p64->req, &p32->req) ||
|
||||
__get_user(p64->retries, &p32->retries) ||
|
||||
__get_user(p64->retry_time_ms, &p32->retry_time_ms))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
memset(p64, 0, sizeof(struct ipmi_recv));
|
||||
p64->recv_type = p32->recv_type;
|
||||
p64->addr = compat_ptr(p32->addr);
|
||||
p64->addr_len = p32->addr_len;
|
||||
p64->msgid = p32->msgid;
|
||||
get_compat_ipmi_msg(&p64->msg, &p32->msg);
|
||||
}
|
||||
|
||||
static long get_compat_ipmi_recv(struct ipmi_recv *p64,
|
||||
struct compat_ipmi_recv __user *p32)
|
||||
static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
|
||||
{
|
||||
compat_uptr_t tmp;
|
||||
|
||||
if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
|
||||
__get_user(p64->recv_type, &p32->recv_type) ||
|
||||
__get_user(tmp, &p32->addr) ||
|
||||
__get_user(p64->addr_len, &p32->addr_len) ||
|
||||
__get_user(p64->msgid, &p32->msgid) ||
|
||||
get_compat_ipmi_msg(&p64->msg, &p32->msg))
|
||||
return -EFAULT;
|
||||
p64->addr = compat_ptr(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
struct compat_ipmi_recv v32;
|
||||
memset(&v32, 0, sizeof(struct compat_ipmi_recv));
|
||||
v32.recv_type = p64->recv_type;
|
||||
v32.addr = ptr_to_compat(p64->addr);
|
||||
v32.addr_len = p64->addr_len;
|
||||
v32.msgid = p64->msgid;
|
||||
v32.msg.netfn = p64->msg.netfn;
|
||||
v32.msg.cmd = p64->msg.cmd;
|
||||
v32.msg.data_len = p64->msg.data_len;
|
||||
v32.msg.data = ptr_to_compat(p64->msg.data);
|
||||
return copy_to_user(to, &v32, sizeof(v32)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -783,17 +762,19 @@ static long put_compat_ipmi_recv(struct ipmi_recv *p64,
|
|||
static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int rc;
|
||||
struct ipmi_file_private *priv = filep->private_data;
|
||||
|
||||
switch(cmd) {
|
||||
case COMPAT_IPMICTL_SEND_COMMAND:
|
||||
{
|
||||
struct ipmi_req rp;
|
||||
struct compat_ipmi_req r32;
|
||||
|
||||
if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
|
||||
if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
|
||||
return -EFAULT;
|
||||
|
||||
get_compat_ipmi_req(&rp, &r32);
|
||||
|
||||
return handle_send_req(priv->user, &rp,
|
||||
priv->default_retries,
|
||||
priv->default_retry_time_ms);
|
||||
|
@ -801,42 +782,30 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
|
|||
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
|
||||
{
|
||||
struct ipmi_req_settime sp;
|
||||
struct compat_ipmi_req_settime sp32;
|
||||
|
||||
if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
|
||||
if (copy_from_user(&sp32, compat_ptr(arg), sizeof(sp32)))
|
||||
return -EFAULT;
|
||||
|
||||
get_compat_ipmi_req_settime(&sp, &sp32);
|
||||
|
||||
return handle_send_req(priv->user, &sp.req,
|
||||
sp.retries, sp.retry_time_ms);
|
||||
}
|
||||
case COMPAT_IPMICTL_RECEIVE_MSG:
|
||||
case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
|
||||
{
|
||||
struct ipmi_recv __user *precv64;
|
||||
struct ipmi_recv recv64;
|
||||
struct compat_ipmi_recv recv32;
|
||||
|
||||
memset(&recv64, 0, sizeof(recv64));
|
||||
if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
|
||||
if (copy_from_user(&recv32, compat_ptr(arg), sizeof(recv32)))
|
||||
return -EFAULT;
|
||||
|
||||
precv64 = compat_alloc_user_space(sizeof(recv64));
|
||||
if (copy_to_user(precv64, &recv64, sizeof(recv64)))
|
||||
return -EFAULT;
|
||||
get_compat_ipmi_recv(&recv64, &recv32);
|
||||
|
||||
rc = ipmi_ioctl(filep,
|
||||
((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
|
||||
? IPMICTL_RECEIVE_MSG
|
||||
: IPMICTL_RECEIVE_MSG_TRUNC),
|
||||
(unsigned long) precv64);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (copy_from_user(&recv64, precv64, sizeof(recv64)))
|
||||
return -EFAULT;
|
||||
|
||||
if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
|
||||
return -EFAULT;
|
||||
|
||||
return rc;
|
||||
return handle_recv(priv,
|
||||
cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
|
||||
&recv64, copyout_recv32, compat_ptr(arg));
|
||||
}
|
||||
default:
|
||||
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,
|
||||
struct usbdevfs_urb32 __user *uurb)
|
||||
{
|
||||
__u32 uptr;
|
||||
if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) ||
|
||||
__get_user(kurb->type, &uurb->type) ||
|
||||
__get_user(kurb->endpoint, &uurb->endpoint) ||
|
||||
__get_user(kurb->status, &uurb->status) ||
|
||||
__get_user(kurb->flags, &uurb->flags) ||
|
||||
__get_user(kurb->buffer_length, &uurb->buffer_length) ||
|
||||
__get_user(kurb->actual_length, &uurb->actual_length) ||
|
||||
__get_user(kurb->start_frame, &uurb->start_frame) ||
|
||||
__get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
|
||||
__get_user(kurb->error_count, &uurb->error_count) ||
|
||||
__get_user(kurb->signr, &uurb->signr))
|
||||
struct usbdevfs_urb32 urb32;
|
||||
if (copy_from_user(&urb32, uurb, sizeof(*uurb)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__get_user(uptr, &uurb->buffer))
|
||||
return -EFAULT;
|
||||
kurb->buffer = compat_ptr(uptr);
|
||||
if (__get_user(uptr, &uurb->usercontext))
|
||||
return -EFAULT;
|
||||
kurb->usercontext = compat_ptr(uptr);
|
||||
|
||||
kurb->type = urb32.type;
|
||||
kurb->endpoint = urb32.endpoint;
|
||||
kurb->status = urb32.status;
|
||||
kurb->flags = urb32.flags;
|
||||
kurb->buffer = compat_ptr(urb32.buffer);
|
||||
kurb->buffer_length = urb32.buffer_length;
|
||||
kurb->actual_length = urb32.actual_length;
|
||||
kurb->start_frame = urb32.start_frame;
|
||||
kurb->number_of_packets = urb32.number_of_packets;
|
||||
kurb->error_count = urb32.error_count;
|
||||
kurb->signr = urb32.signr;
|
||||
kurb->usercontext = compat_ptr(urb32.usercontext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2198,18 +2192,14 @@ static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)
|
|||
#ifdef CONFIG_COMPAT
|
||||
static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)
|
||||
{
|
||||
struct usbdevfs_ioctl32 __user *uioc;
|
||||
struct usbdevfs_ioctl32 ioc32;
|
||||
struct usbdevfs_ioctl ctrl;
|
||||
u32 udata;
|
||||
|
||||
uioc = compat_ptr((long)arg);
|
||||
if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) ||
|
||||
__get_user(ctrl.ifno, &uioc->ifno) ||
|
||||
__get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
|
||||
__get_user(udata, &uioc->data))
|
||||
if (copy_from_user(&ioc32, compat_ptr(arg), sizeof(ioc32)))
|
||||
return -EFAULT;
|
||||
ctrl.data = compat_ptr(udata);
|
||||
|
||||
ctrl.ifno = ioc32.ifno;
|
||||
ctrl.ioctl_code = ioc32.ioctl_code;
|
||||
ctrl.data = compat_ptr(ioc32.data);
|
||||
return proc_ioctl(ps, &ctrl);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1331,22 +1331,13 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
|
|||
static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
struct fb_fix_screeninfo fix;
|
||||
struct fb_fix_screeninfo32 __user *fix32;
|
||||
int err;
|
||||
|
||||
fix32 = compat_ptr(arg);
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
|
||||
set_fs(old_fs);
|
||||
|
||||
if (!err)
|
||||
err = do_fscreeninfo_to_user(&fix, fix32);
|
||||
|
||||
return err;
|
||||
if (!lock_fb_info(info))
|
||||
return -ENODEV;
|
||||
fix = info->fix;
|
||||
unlock_fb_info(info);
|
||||
return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
|
||||
}
|
||||
|
||||
static long fb_compat_ioctl(struct file *file, unsigned int cmd,
|
||||
|
|
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,
|
||||
unsigned long *fdset)
|
||||
{
|
||||
nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
|
||||
if (ufdset) {
|
||||
unsigned long odd;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
|
||||
return -EFAULT;
|
||||
|
||||
odd = nr & 1UL;
|
||||
nr &= ~1UL;
|
||||
while (nr) {
|
||||
unsigned long h, l;
|
||||
if (__get_user(l, ufdset) || __get_user(h, ufdset+1))
|
||||
return -EFAULT;
|
||||
ufdset += 2;
|
||||
*fdset++ = h << 32 | l;
|
||||
nr -= 2;
|
||||
}
|
||||
if (odd && __get_user(*fdset, ufdset))
|
||||
return -EFAULT;
|
||||
return compat_get_bitmap(fdset, ufdset, nr);
|
||||
} else {
|
||||
/* Tricky, must clear full unsigned long in the
|
||||
* kernel fdset at the end, this makes sure that
|
||||
* kernel fdset at the end, ALIGN makes sure that
|
||||
* actually happens.
|
||||
*/
|
||||
memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
|
||||
memset(fdset, 0, ALIGN(nr, BITS_PER_LONG));
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
|
||||
unsigned long *fdset)
|
||||
{
|
||||
unsigned long odd;
|
||||
nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
|
||||
|
||||
if (!ufdset)
|
||||
return 0;
|
||||
|
||||
odd = nr & 1UL;
|
||||
nr &= ~1UL;
|
||||
while (nr) {
|
||||
unsigned long h, l;
|
||||
l = *fdset++;
|
||||
h = l >> 32;
|
||||
if (__put_user(l, ufdset) || __put_user(h, ufdset+1))
|
||||
return -EFAULT;
|
||||
ufdset += 2;
|
||||
nr -= 2;
|
||||
}
|
||||
if (odd && __put_user(*fdset, ufdset))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
return compat_put_bitmap(ufdset, fdset, nr);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -402,8 +402,7 @@ asmlinkage long compat_sys_wait4(compat_pid_t pid,
|
|||
|
||||
#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t))
|
||||
|
||||
#define BITS_TO_COMPAT_LONGS(bits) \
|
||||
(((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG)
|
||||
#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
|
||||
|
||||
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
|
||||
unsigned long bitmap_size);
|
||||
|
|
|
@ -243,8 +243,6 @@ extern int do_send_sig_info(int sig, struct siginfo *info,
|
|||
struct task_struct *p, bool group);
|
||||
extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
|
||||
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
|
||||
extern int do_sigtimedwait(const sigset_t *, siginfo_t *,
|
||||
const struct timespec *);
|
||||
extern int sigprocmask(int, sigset_t *, sigset_t *);
|
||||
extern void set_current_blocked(sigset_t *);
|
||||
extern void __set_current_blocked(const sigset_t *);
|
||||
|
|
|
@ -650,7 +650,7 @@ asmlinkage long sys_olduname(struct oldold_utsname __user *);
|
|||
|
||||
asmlinkage long sys_getrlimit(unsigned int resource,
|
||||
struct rlimit __user *rlim);
|
||||
#if defined(COMPAT_RLIM_OLD_INFINITY) || !(defined(CONFIG_IA64))
|
||||
#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
|
||||
#endif
|
||||
asmlinkage long sys_setrlimit(unsigned int resource,
|
||||
|
|
|
@ -180,9 +180,6 @@ extern int do_getitimer(int which, struct itimerval *value);
|
|||
|
||||
extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
|
||||
|
||||
struct tms;
|
||||
extern void do_sys_times(struct tms *);
|
||||
|
||||
/*
|
||||
* Similar to the struct tm in userspace <time.h>, but it needs to be here so
|
||||
* that the kernel source is self contained.
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
|
||||
obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o
|
||||
obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
|
||||
obj_mq-$(CONFIG_COMPAT) += compat_mq.o
|
||||
obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
|
||||
obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
|
||||
obj-$(CONFIG_IPC_NS) += namespace.o
|
||||
obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
|
||||
|
||||
|
|
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,
|
||||
ktime_t *expires, struct timespec *ts)
|
||||
struct timespec *ts)
|
||||
{
|
||||
if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
|
||||
return -EFAULT;
|
||||
if (!timespec_valid(ts))
|
||||
return -EINVAL;
|
||||
|
||||
*expires = timespec_to_ktime(*ts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -770,23 +768,19 @@ static struct file *do_open(struct path *path, int oflag)
|
|||
return dentry_open(path, oflag, current_cred());
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
||||
struct mq_attr __user *, u_attr)
|
||||
static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||
struct mq_attr *attr)
|
||||
{
|
||||
struct path path;
|
||||
struct file *filp;
|
||||
struct filename *name;
|
||||
struct mq_attr attr;
|
||||
int fd, error;
|
||||
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
|
||||
struct vfsmount *mnt = ipc_ns->mq_mnt;
|
||||
struct dentry *root = mnt->mnt_root;
|
||||
int ro;
|
||||
|
||||
if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
|
||||
return -EFAULT;
|
||||
|
||||
audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
|
||||
audit_mq_open(oflag, mode, attr);
|
||||
|
||||
if (IS_ERR(name = getname(u_name)))
|
||||
return PTR_ERR(name);
|
||||
|
@ -819,9 +813,8 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
|||
goto out;
|
||||
}
|
||||
audit_inode_parent_hidden(name, root);
|
||||
filp = do_create(ipc_ns, d_inode(root),
|
||||
&path, oflag, mode,
|
||||
u_attr ? &attr : NULL);
|
||||
filp = do_create(ipc_ns, d_inode(root), &path,
|
||||
oflag, mode, attr);
|
||||
}
|
||||
} else {
|
||||
if (d_really_is_negative(path.dentry)) {
|
||||
|
@ -851,6 +844,16 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
|||
return fd;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
|
||||
struct mq_attr __user *, u_attr)
|
||||
{
|
||||
struct mq_attr attr;
|
||||
if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
|
||||
return -EFAULT;
|
||||
|
||||
return do_mq_open(u_name, oflag, mode, u_attr ? &attr : NULL);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||
{
|
||||
int err;
|
||||
|
@ -957,9 +960,9 @@ static inline void pipelined_receive(struct wake_q_head *wake_q,
|
|||
sender->state = STATE_READY;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
|
||||
size_t, msg_len, unsigned int, msg_prio,
|
||||
const struct timespec __user *, u_abs_timeout)
|
||||
static int do_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
|
||||
size_t msg_len, unsigned int msg_prio,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct fd f;
|
||||
struct inode *inode;
|
||||
|
@ -968,22 +971,19 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
|
|||
struct msg_msg *msg_ptr;
|
||||
struct mqueue_inode_info *info;
|
||||
ktime_t expires, *timeout = NULL;
|
||||
struct timespec ts;
|
||||
struct posix_msg_tree_node *new_leaf = NULL;
|
||||
int ret = 0;
|
||||
DEFINE_WAKE_Q(wake_q);
|
||||
|
||||
if (u_abs_timeout) {
|
||||
int res = prepare_timeout(u_abs_timeout, &expires, &ts);
|
||||
if (res)
|
||||
return res;
|
||||
timeout = &expires;
|
||||
}
|
||||
|
||||
if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL);
|
||||
if (ts) {
|
||||
expires = timespec_to_ktime(*ts);
|
||||
timeout = &expires;
|
||||
}
|
||||
|
||||
audit_mq_sendrecv(mqdes, msg_len, msg_prio, ts);
|
||||
|
||||
f = fdget(mqdes);
|
||||
if (unlikely(!f.file)) {
|
||||
|
@ -1078,9 +1078,9 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
|
||||
size_t, msg_len, unsigned int __user *, u_msg_prio,
|
||||
const struct timespec __user *, u_abs_timeout)
|
||||
static int do_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
|
||||
size_t msg_len, unsigned int __user *u_msg_prio,
|
||||
struct timespec *ts)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct msg_msg *msg_ptr;
|
||||
|
@ -1089,17 +1089,14 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
|
|||
struct mqueue_inode_info *info;
|
||||
struct ext_wait_queue wait;
|
||||
ktime_t expires, *timeout = NULL;
|
||||
struct timespec ts;
|
||||
struct posix_msg_tree_node *new_leaf = NULL;
|
||||
|
||||
if (u_abs_timeout) {
|
||||
int res = prepare_timeout(u_abs_timeout, &expires, &ts);
|
||||
if (res)
|
||||
return res;
|
||||
if (ts) {
|
||||
expires = timespec_to_ktime(*ts);
|
||||
timeout = &expires;
|
||||
}
|
||||
|
||||
audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL);
|
||||
audit_mq_sendrecv(mqdes, msg_len, 0, ts);
|
||||
|
||||
f = fdget(mqdes);
|
||||
if (unlikely(!f.file)) {
|
||||
|
@ -1183,42 +1180,62 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
|
||||
size_t, msg_len, unsigned int, msg_prio,
|
||||
const struct timespec __user *, u_abs_timeout)
|
||||
{
|
||||
struct timespec ts, *p = NULL;
|
||||
if (u_abs_timeout) {
|
||||
int res = prepare_timeout(u_abs_timeout, &ts);
|
||||
if (res)
|
||||
return res;
|
||||
p = &ts;
|
||||
}
|
||||
return do_mq_timedsend(mqdes, u_msg_ptr, msg_len, msg_prio, p);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
|
||||
size_t, msg_len, unsigned int __user *, u_msg_prio,
|
||||
const struct timespec __user *, u_abs_timeout)
|
||||
{
|
||||
struct timespec ts, *p = NULL;
|
||||
if (u_abs_timeout) {
|
||||
int res = prepare_timeout(u_abs_timeout, &ts);
|
||||
if (res)
|
||||
return res;
|
||||
p = &ts;
|
||||
}
|
||||
return do_mq_timedreceive(mqdes, u_msg_ptr, msg_len, u_msg_prio, p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notes: the case when user wants us to deregister (with NULL as pointer)
|
||||
* and he isn't currently owner of notification, will be silently discarded.
|
||||
* It isn't explicitly defined in the POSIX.
|
||||
*/
|
||||
SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
||||
const struct sigevent __user *, u_notification)
|
||||
static int do_mq_notify(mqd_t mqdes, const struct sigevent *notification)
|
||||
{
|
||||
int ret;
|
||||
struct fd f;
|
||||
struct sock *sock;
|
||||
struct inode *inode;
|
||||
struct sigevent notification;
|
||||
struct mqueue_inode_info *info;
|
||||
struct sk_buff *nc;
|
||||
|
||||
if (u_notification) {
|
||||
if (copy_from_user(¬ification, u_notification,
|
||||
sizeof(struct sigevent)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
audit_mq_notify(mqdes, u_notification ? ¬ification : NULL);
|
||||
audit_mq_notify(mqdes, notification);
|
||||
|
||||
nc = NULL;
|
||||
sock = NULL;
|
||||
if (u_notification != NULL) {
|
||||
if (unlikely(notification.sigev_notify != SIGEV_NONE &&
|
||||
notification.sigev_notify != SIGEV_SIGNAL &&
|
||||
notification.sigev_notify != SIGEV_THREAD))
|
||||
if (notification != NULL) {
|
||||
if (unlikely(notification->sigev_notify != SIGEV_NONE &&
|
||||
notification->sigev_notify != SIGEV_SIGNAL &&
|
||||
notification->sigev_notify != SIGEV_THREAD))
|
||||
return -EINVAL;
|
||||
if (notification.sigev_notify == SIGEV_SIGNAL &&
|
||||
!valid_signal(notification.sigev_signo)) {
|
||||
if (notification->sigev_notify == SIGEV_SIGNAL &&
|
||||
!valid_signal(notification->sigev_signo)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (notification.sigev_notify == SIGEV_THREAD) {
|
||||
if (notification->sigev_notify == SIGEV_THREAD) {
|
||||
long timeo;
|
||||
|
||||
/* create the notify skb */
|
||||
|
@ -1228,7 +1245,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
goto out;
|
||||
}
|
||||
if (copy_from_user(nc->data,
|
||||
notification.sigev_value.sival_ptr,
|
||||
notification->sigev_value.sival_ptr,
|
||||
NOTIFY_COOKIE_LEN)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
|
@ -1238,7 +1255,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
skb_put(nc, NOTIFY_COOKIE_LEN);
|
||||
/* and attach it to the socket */
|
||||
retry:
|
||||
f = fdget(notification.sigev_signo);
|
||||
f = fdget(notification->sigev_signo);
|
||||
if (!f.file) {
|
||||
ret = -EBADF;
|
||||
goto out;
|
||||
|
@ -1278,7 +1295,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
|
||||
ret = 0;
|
||||
spin_lock(&info->lock);
|
||||
if (u_notification == NULL) {
|
||||
if (notification == NULL) {
|
||||
if (info->notify_owner == task_tgid(current)) {
|
||||
remove_notification(info);
|
||||
inode->i_atime = inode->i_ctime = current_time(inode);
|
||||
|
@ -1286,7 +1303,7 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
} else if (info->notify_owner != NULL) {
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
switch (notification.sigev_notify) {
|
||||
switch (notification->sigev_notify) {
|
||||
case SIGEV_NONE:
|
||||
info->notify.sigev_notify = SIGEV_NONE;
|
||||
break;
|
||||
|
@ -1298,8 +1315,8 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
info->notify.sigev_notify = SIGEV_THREAD;
|
||||
break;
|
||||
case SIGEV_SIGNAL:
|
||||
info->notify.sigev_signo = notification.sigev_signo;
|
||||
info->notify.sigev_value = notification.sigev_value;
|
||||
info->notify.sigev_signo = notification->sigev_signo;
|
||||
info->notify.sigev_value = notification->sigev_value;
|
||||
info->notify.sigev_notify = SIGEV_SIGNAL;
|
||||
break;
|
||||
}
|
||||
|
@ -1320,44 +1337,49 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
||||
const struct mq_attr __user *, u_mqstat,
|
||||
struct mq_attr __user *, u_omqstat)
|
||||
SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
|
||||
const struct sigevent __user *, u_notification)
|
||||
{
|
||||
struct sigevent n, *p = NULL;
|
||||
if (u_notification) {
|
||||
if (copy_from_user(&n, u_notification, sizeof(struct sigevent)))
|
||||
return -EFAULT;
|
||||
p = &n;
|
||||
}
|
||||
return do_mq_notify(mqdes, p);
|
||||
}
|
||||
|
||||
static int do_mq_getsetattr(int mqdes, struct mq_attr *new, struct mq_attr *old)
|
||||
{
|
||||
int ret;
|
||||
struct mq_attr mqstat, omqstat;
|
||||
struct fd f;
|
||||
struct inode *inode;
|
||||
struct mqueue_inode_info *info;
|
||||
|
||||
if (u_mqstat != NULL) {
|
||||
if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr)))
|
||||
return -EFAULT;
|
||||
if (mqstat.mq_flags & (~O_NONBLOCK))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new && (new->mq_flags & (~O_NONBLOCK)))
|
||||
return -EINVAL;
|
||||
|
||||
f = fdget(mqdes);
|
||||
if (!f.file) {
|
||||
ret = -EBADF;
|
||||
goto out;
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
||||
fdput(f);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
inode = file_inode(f.file);
|
||||
if (unlikely(f.file->f_op != &mqueue_file_operations)) {
|
||||
ret = -EBADF;
|
||||
goto out_fput;
|
||||
}
|
||||
info = MQUEUE_I(inode);
|
||||
|
||||
spin_lock(&info->lock);
|
||||
|
||||
omqstat = info->attr;
|
||||
omqstat.mq_flags = f.file->f_flags & O_NONBLOCK;
|
||||
if (u_mqstat) {
|
||||
audit_mq_getsetattr(mqdes, &mqstat);
|
||||
if (old) {
|
||||
*old = info->attr;
|
||||
old->mq_flags = f.file->f_flags & O_NONBLOCK;
|
||||
}
|
||||
if (new) {
|
||||
audit_mq_getsetattr(mqdes, new);
|
||||
spin_lock(&f.file->f_lock);
|
||||
if (mqstat.mq_flags & O_NONBLOCK)
|
||||
if (new->mq_flags & O_NONBLOCK)
|
||||
f.file->f_flags |= O_NONBLOCK;
|
||||
else
|
||||
f.file->f_flags &= ~O_NONBLOCK;
|
||||
|
@ -1367,18 +1389,169 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
|
|||
}
|
||||
|
||||
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);
|
||||
out:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.lookup = simple_lookup,
|
||||
.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;
|
||||
}
|
||||
|
||||
static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
|
||||
{
|
||||
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
|
||||
{
|
||||
if (tbuf) {
|
||||
struct tms tms;
|
||||
struct compat_tms tmp;
|
||||
|
||||
do_sys_times(&tms);
|
||||
/* Convert our struct tms to the compat version. */
|
||||
tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
|
||||
tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
|
||||
tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
|
||||
tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
|
||||
if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
}
|
||||
force_successful_syscall_return();
|
||||
return compat_jiffies_to_clock_t(jiffies);
|
||||
}
|
||||
|
||||
#ifdef __ARCH_WANT_SYS_SIGPENDING
|
||||
|
||||
/*
|
||||
* Assumption: old_sigset_t and compat_old_sigset_t are both
|
||||
* types that can be passed to put_user()/get_user().
|
||||
*/
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set)
|
||||
{
|
||||
old_sigset_t s;
|
||||
long ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
ret = sys_sigpending((old_sigset_t __user *) &s);
|
||||
set_fs(old_fs);
|
||||
if (ret == 0)
|
||||
ret = put_user(s, set);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ARCH_WANT_SYS_SIGPROCMASK
|
||||
|
||||
/*
|
||||
|
@ -348,94 +301,29 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
|
|||
|
||||
#endif
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
|
||||
if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
|
||||
__get_user(r.rlim_cur, &rlim->rlim_cur) ||
|
||||
__get_user(r.rlim_max, &rlim->rlim_max))
|
||||
return -EFAULT;
|
||||
|
||||
if (r.rlim_cur == COMPAT_RLIM_INFINITY)
|
||||
r.rlim_cur = RLIM_INFINITY;
|
||||
if (r.rlim_max == COMPAT_RLIM_INFINITY)
|
||||
r.rlim_max = RLIM_INFINITY;
|
||||
return do_prlimit(current, resource, &r, NULL);
|
||||
}
|
||||
|
||||
#ifdef COMPAT_RLIM_OLD_INFINITY
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
int ret;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
ret = sys_old_getrlimit(resource, (struct rlimit __user *)&r);
|
||||
set_fs(old_fs);
|
||||
|
||||
if (!ret) {
|
||||
if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
|
||||
r.rlim_cur = COMPAT_RLIM_INFINITY;
|
||||
if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
|
||||
r.rlim_max = COMPAT_RLIM_INFINITY;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
|
||||
__put_user(r.rlim_cur, &rlim->rlim_cur) ||
|
||||
__put_user(r.rlim_max, &rlim->rlim_max))
|
||||
return -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
int ret;
|
||||
|
||||
ret = do_prlimit(current, resource, NULL, &r);
|
||||
if (!ret) {
|
||||
if (r.rlim_cur > COMPAT_RLIM_INFINITY)
|
||||
r.rlim_cur = COMPAT_RLIM_INFINITY;
|
||||
if (r.rlim_max > COMPAT_RLIM_INFINITY)
|
||||
r.rlim_max = COMPAT_RLIM_INFINITY;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
|
||||
__put_user(r.rlim_cur, &rlim->rlim_cur) ||
|
||||
__put_user(r.rlim_max, &rlim->rlim_max))
|
||||
return -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
|
||||
{
|
||||
if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
|
||||
__put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
|
||||
__put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
|
||||
__put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
|
||||
__put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
|
||||
__put_user(r->ru_maxrss, &ru->ru_maxrss) ||
|
||||
__put_user(r->ru_ixrss, &ru->ru_ixrss) ||
|
||||
__put_user(r->ru_idrss, &ru->ru_idrss) ||
|
||||
__put_user(r->ru_isrss, &ru->ru_isrss) ||
|
||||
__put_user(r->ru_minflt, &ru->ru_minflt) ||
|
||||
__put_user(r->ru_majflt, &ru->ru_majflt) ||
|
||||
__put_user(r->ru_nswap, &ru->ru_nswap) ||
|
||||
__put_user(r->ru_inblock, &ru->ru_inblock) ||
|
||||
__put_user(r->ru_oublock, &ru->ru_oublock) ||
|
||||
__put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
|
||||
__put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
|
||||
__put_user(r->ru_nsignals, &ru->ru_nsignals) ||
|
||||
__put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
|
||||
__put_user(r->ru_nivcsw, &ru->ru_nivcsw))
|
||||
struct compat_rusage r32;
|
||||
memset(&r32, 0, sizeof(r32));
|
||||
r32.ru_utime.tv_sec = r->ru_utime.tv_sec;
|
||||
r32.ru_utime.tv_usec = r->ru_utime.tv_usec;
|
||||
r32.ru_stime.tv_sec = r->ru_stime.tv_sec;
|
||||
r32.ru_stime.tv_usec = r->ru_stime.tv_usec;
|
||||
r32.ru_maxrss = r->ru_maxrss;
|
||||
r32.ru_ixrss = r->ru_ixrss;
|
||||
r32.ru_idrss = r->ru_idrss;
|
||||
r32.ru_isrss = r->ru_isrss;
|
||||
r32.ru_minflt = r->ru_minflt;
|
||||
r32.ru_majflt = r->ru_majflt;
|
||||
r32.ru_nswap = r->ru_nswap;
|
||||
r32.ru_inblock = r->ru_inblock;
|
||||
r32.ru_oublock = r->ru_oublock;
|
||||
r32.ru_msgsnd = r->ru_msgsnd;
|
||||
r32.ru_msgrcv = r->ru_msgrcv;
|
||||
r32.ru_nsignals = r->ru_nsignals;
|
||||
r32.ru_nvcsw = r->ru_nvcsw;
|
||||
r32.ru_nivcsw = r->ru_nivcsw;
|
||||
if (copy_to_user(ru, &r32, sizeof(r32)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,84 +453,59 @@ int get_compat_sigevent(struct sigevent *event,
|
|||
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
|
||||
unsigned long bitmap_size)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long m;
|
||||
compat_ulong_t um;
|
||||
unsigned long nr_compat_longs;
|
||||
|
||||
/* align bitmap up to nearest compat_long_t boundary */
|
||||
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
|
||||
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
|
||||
|
||||
if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
|
||||
return -EFAULT;
|
||||
|
||||
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
|
||||
m = 0;
|
||||
|
||||
for (j = 0; j < sizeof(m)/sizeof(um); j++) {
|
||||
/*
|
||||
* We dont want to read past the end of the userspace
|
||||
* bitmap. We must however ensure the end of the
|
||||
* kernel bitmap is zeroed.
|
||||
*/
|
||||
if (nr_compat_longs) {
|
||||
nr_compat_longs--;
|
||||
if (__get_user(um, umask))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
um = 0;
|
||||
}
|
||||
|
||||
umask++;
|
||||
m |= (long)um << (j * BITS_PER_COMPAT_LONG);
|
||||
}
|
||||
*mask++ = m;
|
||||
user_access_begin();
|
||||
while (nr_compat_longs > 1) {
|
||||
compat_ulong_t l1, l2;
|
||||
unsafe_get_user(l1, umask++, Efault);
|
||||
unsafe_get_user(l2, umask++, Efault);
|
||||
*mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
|
||||
nr_compat_longs -= 2;
|
||||
}
|
||||
|
||||
if (nr_compat_longs)
|
||||
unsafe_get_user(*mask, umask++, Efault);
|
||||
user_access_end();
|
||||
return 0;
|
||||
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
|
||||
unsigned long bitmap_size)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long m;
|
||||
compat_ulong_t um;
|
||||
unsigned long nr_compat_longs;
|
||||
|
||||
/* align bitmap up to nearest compat_long_t boundary */
|
||||
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
|
||||
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
|
||||
return -EFAULT;
|
||||
|
||||
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
|
||||
m = *mask++;
|
||||
|
||||
for (j = 0; j < sizeof(m)/sizeof(um); j++) {
|
||||
um = m;
|
||||
|
||||
/*
|
||||
* We dont want to write past the end of the userspace
|
||||
* bitmap.
|
||||
*/
|
||||
if (nr_compat_longs) {
|
||||
nr_compat_longs--;
|
||||
if (__put_user(um, umask))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
umask++;
|
||||
m >>= 4*sizeof(um);
|
||||
m >>= 4*sizeof(um);
|
||||
}
|
||||
user_access_begin();
|
||||
while (nr_compat_longs > 1) {
|
||||
unsigned long m = *mask++;
|
||||
unsafe_put_user((compat_ulong_t)m, umask++, Efault);
|
||||
unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
|
||||
nr_compat_longs -= 2;
|
||||
}
|
||||
|
||||
if (nr_compat_longs)
|
||||
unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
|
||||
user_access_end();
|
||||
return 0;
|
||||
Efault:
|
||||
user_access_end();
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -668,38 +531,6 @@ sigset_to_compat(compat_sigset_t *compat, const sigset_t *set)
|
|||
}
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
|
||||
struct compat_siginfo __user *, uinfo,
|
||||
struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
|
||||
{
|
||||
compat_sigset_t s32;
|
||||
sigset_t s;
|
||||
struct timespec t;
|
||||
siginfo_t info;
|
||||
long ret;
|
||||
|
||||
if (sigsetsize != sizeof(sigset_t))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
|
||||
return -EFAULT;
|
||||
sigset_from_compat(&s, &s32);
|
||||
|
||||
if (uts) {
|
||||
if (compat_get_timespec(&t, uts))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
|
||||
|
||||
if (ret > 0 && uinfo) {
|
||||
if (copy_siginfo_to_user32(uinfo, &info))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
|
||||
compat_uptr_t __user *, pages32,
|
||||
|
|
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
|
||||
* @ts: upper bound on process time suspension
|
||||
*/
|
||||
int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
|
||||
static int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
ktime_t *to = NULL, timeout = KTIME_MAX;
|
||||
|
@ -2865,6 +2865,40 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
|
||||
struct compat_siginfo __user *, uinfo,
|
||||
struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
|
||||
{
|
||||
compat_sigset_t s32;
|
||||
sigset_t s;
|
||||
struct timespec t;
|
||||
siginfo_t info;
|
||||
long ret;
|
||||
|
||||
if (sigsetsize != sizeof(sigset_t))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
|
||||
return -EFAULT;
|
||||
sigset_from_compat(&s, &s32);
|
||||
|
||||
if (uts) {
|
||||
if (compat_get_timespec(&t, uts))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
|
||||
|
||||
if (ret > 0 && uinfo) {
|
||||
if (copy_siginfo_to_user32(uinfo, &info))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sys_kill - send a signal to a process
|
||||
* @pid: the PID of the process
|
||||
|
@ -3121,78 +3155,68 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
|
|||
}
|
||||
|
||||
static int
|
||||
do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp)
|
||||
do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
|
||||
{
|
||||
stack_t oss;
|
||||
int error;
|
||||
struct task_struct *t = current;
|
||||
|
||||
oss.ss_sp = (void __user *) current->sas_ss_sp;
|
||||
oss.ss_size = current->sas_ss_size;
|
||||
oss.ss_flags = sas_ss_flags(sp) |
|
||||
(current->sas_ss_flags & SS_FLAG_BITS);
|
||||
if (oss) {
|
||||
memset(oss, 0, sizeof(stack_t));
|
||||
oss->ss_sp = (void __user *) t->sas_ss_sp;
|
||||
oss->ss_size = t->sas_ss_size;
|
||||
oss->ss_flags = sas_ss_flags(sp) |
|
||||
(current->sas_ss_flags & SS_FLAG_BITS);
|
||||
}
|
||||
|
||||
if (uss) {
|
||||
void __user *ss_sp;
|
||||
size_t ss_size;
|
||||
unsigned ss_flags;
|
||||
if (ss) {
|
||||
void __user *ss_sp = ss->ss_sp;
|
||||
size_t ss_size = ss->ss_size;
|
||||
unsigned ss_flags = ss->ss_flags;
|
||||
int ss_mode;
|
||||
|
||||
error = -EFAULT;
|
||||
if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
|
||||
goto out;
|
||||
error = __get_user(ss_sp, &uss->ss_sp) |
|
||||
__get_user(ss_flags, &uss->ss_flags) |
|
||||
__get_user(ss_size, &uss->ss_size);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = -EPERM;
|
||||
if (on_sig_stack(sp))
|
||||
goto out;
|
||||
if (unlikely(on_sig_stack(sp)))
|
||||
return -EPERM;
|
||||
|
||||
ss_mode = ss_flags & ~SS_FLAG_BITS;
|
||||
error = -EINVAL;
|
||||
if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
|
||||
ss_mode != 0)
|
||||
goto out;
|
||||
if (unlikely(ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK &&
|
||||
ss_mode != 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (ss_mode == SS_DISABLE) {
|
||||
ss_size = 0;
|
||||
ss_sp = NULL;
|
||||
} else {
|
||||
error = -ENOMEM;
|
||||
if (ss_size < MINSIGSTKSZ)
|
||||
goto out;
|
||||
if (unlikely(ss_size < MINSIGSTKSZ))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
current->sas_ss_sp = (unsigned long) ss_sp;
|
||||
current->sas_ss_size = ss_size;
|
||||
current->sas_ss_flags = ss_flags;
|
||||
t->sas_ss_sp = (unsigned long) ss_sp;
|
||||
t->sas_ss_size = ss_size;
|
||||
t->sas_ss_flags = ss_flags;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
if (uoss) {
|
||||
error = -EFAULT;
|
||||
if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
|
||||
goto out;
|
||||
error = __put_user(oss.ss_sp, &uoss->ss_sp) |
|
||||
__put_user(oss.ss_size, &uoss->ss_size) |
|
||||
__put_user(oss.ss_flags, &uoss->ss_flags);
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
|
||||
{
|
||||
return do_sigaltstack(uss, uoss, current_user_stack_pointer());
|
||||
stack_t new, old;
|
||||
int err;
|
||||
if (uss && copy_from_user(&new, uss, sizeof(stack_t)))
|
||||
return -EFAULT;
|
||||
err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL,
|
||||
current_user_stack_pointer());
|
||||
if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t)))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
int restore_altstack(const stack_t __user *uss)
|
||||
{
|
||||
int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
|
||||
stack_t new;
|
||||
if (copy_from_user(&new, uss, sizeof(stack_t)))
|
||||
return -EFAULT;
|
||||
(void)do_sigaltstack(&new, NULL, current_user_stack_pointer());
|
||||
/* squash all but EFAULT for now */
|
||||
return err == -EFAULT ? err : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __save_altstack(stack_t __user *uss, unsigned long sp)
|
||||
|
@ -3215,29 +3239,24 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
|
|||
{
|
||||
stack_t uss, uoss;
|
||||
int ret;
|
||||
mm_segment_t seg;
|
||||
|
||||
if (uss_ptr) {
|
||||
compat_stack_t uss32;
|
||||
|
||||
memset(&uss, 0, sizeof(stack_t));
|
||||
if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
|
||||
return -EFAULT;
|
||||
uss.ss_sp = compat_ptr(uss32.ss_sp);
|
||||
uss.ss_flags = uss32.ss_flags;
|
||||
uss.ss_size = uss32.ss_size;
|
||||
}
|
||||
seg = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
|
||||
(stack_t __force __user *) &uoss,
|
||||
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
|
||||
compat_user_stack_pointer());
|
||||
set_fs(seg);
|
||||
if (ret >= 0 && uoss_ptr) {
|
||||
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
|
||||
__put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
|
||||
__put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
|
||||
__put_user(uoss.ss_size, &uoss_ptr->ss_size))
|
||||
compat_stack_t old;
|
||||
memset(&old, 0, sizeof(old));
|
||||
old.ss_sp = ptr_to_compat(uoss.ss_sp);
|
||||
old.ss_flags = uoss.ss_flags;
|
||||
old.ss_size = uoss.ss_size;
|
||||
if (copy_to_user(uoss_ptr, &old, sizeof(compat_stack_t)))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
|
@ -3277,6 +3296,18 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
|
|||
return sys_rt_sigpending((sigset_t __user *)set, sizeof(old_sigset_t));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32)
|
||||
{
|
||||
sigset_t set;
|
||||
int err = do_sigpending(&set, sizeof(old_sigset_t));
|
||||
if (err == 0)
|
||||
if (copy_to_user(set32, &set, sizeof(old_sigset_t)))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ARCH_WANT_SYS_SIGPROCMASK
|
||||
|
|
100
kernel/sys.c
100
kernel/sys.c
|
@ -886,7 +886,7 @@ SYSCALL_DEFINE0(getegid)
|
|||
return from_kgid_munged(current_user_ns(), current_egid());
|
||||
}
|
||||
|
||||
void do_sys_times(struct tms *tms)
|
||||
static void do_sys_times(struct tms *tms)
|
||||
{
|
||||
u64 tgutime, tgstime, cutime, cstime;
|
||||
|
||||
|
@ -912,6 +912,32 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
|
|||
return (long) jiffies_64_to_clock_t(get_jiffies_64());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
|
||||
{
|
||||
return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)
|
||||
{
|
||||
if (tbuf) {
|
||||
struct tms tms;
|
||||
struct compat_tms tmp;
|
||||
|
||||
do_sys_times(&tms);
|
||||
/* Convert our struct tms to the compat version. */
|
||||
tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
|
||||
tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
|
||||
tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
|
||||
tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
|
||||
if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
}
|
||||
force_successful_syscall_return();
|
||||
return compat_jiffies_to_clock_t(jiffies);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This needs some heavy checking ...
|
||||
* I just haven't the stomach for it. I also don't fully
|
||||
|
@ -1306,6 +1332,54 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
struct compat_rlimit r32;
|
||||
|
||||
if (copy_from_user(&r32, rlim, sizeof(struct compat_rlimit)))
|
||||
return -EFAULT;
|
||||
|
||||
if (r32.rlim_cur == COMPAT_RLIM_INFINITY)
|
||||
r.rlim_cur = RLIM_INFINITY;
|
||||
else
|
||||
r.rlim_cur = r32.rlim_cur;
|
||||
if (r32.rlim_max == COMPAT_RLIM_INFINITY)
|
||||
r.rlim_max = RLIM_INFINITY;
|
||||
else
|
||||
r.rlim_max = r32.rlim_max;
|
||||
return do_prlimit(current, resource, &r, NULL);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
int ret;
|
||||
|
||||
ret = do_prlimit(current, resource, NULL, &r);
|
||||
if (!ret) {
|
||||
struct rlimit r32;
|
||||
if (r.rlim_cur > COMPAT_RLIM_INFINITY)
|
||||
r32.rlim_cur = COMPAT_RLIM_INFINITY;
|
||||
else
|
||||
r32.rlim_cur = r.rlim_cur;
|
||||
if (r.rlim_max > COMPAT_RLIM_INFINITY)
|
||||
r32.rlim_max = COMPAT_RLIM_INFINITY;
|
||||
else
|
||||
r32.rlim_max = r.rlim_max;
|
||||
|
||||
if (copy_to_user(rlim, &r32, sizeof(struct compat_rlimit)))
|
||||
return -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
|
||||
/*
|
||||
|
@ -1328,6 +1402,30 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
|||
return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
||||
struct compat_rlimit __user *, rlim)
|
||||
{
|
||||
struct rlimit r;
|
||||
|
||||
if (resource >= RLIM_NLIMITS)
|
||||
return -EINVAL;
|
||||
|
||||
task_lock(current->group_leader);
|
||||
r = current->signal->rlim[resource];
|
||||
task_unlock(current->group_leader);
|
||||
if (r.rlim_cur > 0x7FFFFFFF)
|
||||
r.rlim_cur = 0x7FFFFFFF;
|
||||
if (r.rlim_max > 0x7FFFFFFF)
|
||||
r.rlim_max = 0x7FFFFFFF;
|
||||
|
||||
if (put_user(r.rlim_cur, &rlim->rlim_cur) ||
|
||||
put_user(r.rlim_max, &rlim->rlim_max))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool rlim64_is_infinity(__u64 rlim64)
|
||||
|
|
Loading…
Reference in New Issue