diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-06 20:57:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-06 20:57:13 -0700 |
commit | c856863988ebf612d159e55eeddbcd27de63b40d (patch) | |
tree | 88ce68d58f66679aabe029a93230280191b58d32 /drivers | |
parent | 771d3feb4b79f8569bf0033b9075a434d0365fa2 (diff) | |
parent | 0d0606060baefdb13d3d80dba1b4c816b0676e16 (diff) | |
download | lwn-c856863988ebf612d159e55eeddbcd27de63b40d.tar.gz lwn-c856863988ebf612d159e55eeddbcd27de63b40d.zip |
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
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/floppy.c | 328 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_devintf.c | 333 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 48 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 19 |
4 files changed, 503 insertions, 225 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index ce823647a9c4..9c00f29e40c1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -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 }; /* diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index f45119c5337d..2ffca4232686 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -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))) { - rv = -EFAULT; - break; - } - - /* We claim a mutex because we don't want two - users getting something from the queue at a time. - Since we have to release the spinlock before we can - copy the data to the user, it's possible another - user will grab something from the queue, too. Then - the messages might get out of order if something - fails and the message gets put back onto the - queue. This mutex prevents that problem. */ - mutex_lock(&priv->recv_mutex); - - /* Grab the message off the list. */ - spin_lock_irqsave(&(priv->recv_msg_lock), flags); - if (list_empty(&(priv->recv_msgs))) { - spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); - rv = -EAGAIN; - goto recv_err; - } - entry = priv->recv_msgs.next; - msg = list_entry(entry, struct ipmi_recv_msg, link); - list_del(entry); - spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); - - addr_len = ipmi_addr_length(msg->addr.addr_type); - if (rsp.addr_len < addr_len) - { - rv = -EINVAL; - goto recv_putback_on_err; - } - if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) { + if (copy_from_user(&rsp, arg, sizeof(rsp))) rv = -EFAULT; - 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) -{ - compat_uptr_t tmp; - - if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || - __get_user(p64->netfn, &p32->netfn) || - __get_user(p64->cmd, &p32->cmd) || - __get_user(p64->data_len, &p32->data_len) || - __get_user(tmp, &p32->data)) - return -EFAULT; - p64->data = compat_ptr(tmp); - return 0; -} - -static long put_compat_ipmi_msg(struct ipmi_msg *p64, - struct compat_ipmi_msg __user *p32) +static void get_compat_ipmi_msg(struct ipmi_msg *p64, + struct compat_ipmi_msg *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->netfn = p32->netfn; + p64->cmd = p32->cmd; + p64->data_len = p32->data_len; + p64->data = compat_ptr(p32->data); } -static long get_compat_ipmi_req(struct ipmi_req *p64, - struct compat_ipmi_req __user *p32) +static void get_compat_ipmi_req(struct ipmi_req *p64, + struct compat_ipmi_req *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; + 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_settime(struct ipmi_req_settime *p64, - struct compat_ipmi_req_settime __user *p32) +static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, + struct compat_ipmi_req_settime *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; + 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_recv(struct ipmi_recv *p64, - struct compat_ipmi_recv __user *p32) +static void get_compat_ipmi_recv(struct ipmi_recv *p64, + struct compat_ipmi_recv *p32) { - 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; + 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 put_compat_ipmi_recv(struct ipmi_recv *p64, - struct compat_ipmi_recv __user *p32) +static int copyout_recv32(struct ipmi_recv *p64, void __user *to) { - 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; - - 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; + get_compat_ipmi_recv(&recv64, &recv32); - 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); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 0e7d0e81a7cb..ebe27595c4af 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -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 diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 069fe7960df1..5324358f110f 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -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, |