lkml.org 
[lkml]   [2003]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patches in this message
    /
    Date
    From
    SubjectRe: must-fix list, v5
    Hi!

    > This part won't work on sparc64 because it has separate address spaces
    > for user/kernel.
    >
    > Yes, in fact I happen to be working in this area hold on...
    >
    > I'm redoing Andi's x86_64 ioctl32 bug fixes more cleanly
    > for sparc64 by instead using alloc_user_space().
    >
    > Sorry Andi, I just couldn't bring myself to allow those bogus
    > artificial limits you added just to fix these bugs... :-)
    >
    > This work also pointed out many bugs in this area which should
    > be fixed by my stuff. (CDROMREAD* ioctls don't take struct cdrom_read
    > they take struct cdrom_msf which is compatible, struct
    > cdrom_generic_command32 was missing some members, etc. etc.)
    >
    > This is a 2.4.x patch but should be easy to push over to the 2.5.x
    > ioctl stuff using the appropriate compat types.

    It was painfull but easy to port 2.5.X. Here it is.

    Andi, can you take uaccess.h part? Davem, does trivial copy_in_user I
    created have expected semantics?
    Pavel

    --- linux.clean/include/asm-x86_64/uaccess.h 2003-03-18 08:23:12.000000000 -0800
    +++ linux/include/asm-x86_64/uaccess.h 2003-05-29 06:06:07.000000000 -0700
    @@ -298,6 +298,19 @@
    }
    }

    +static inline int copy_in_user(void *dst, const void *src, unsigned size)
    +{
    + int i, ret;
    + unsigned char c;
    + for (i=0; i<size; i++) {
    + ret = copy_from_user(&c, src, 1);
    + if (ret) return ret;
    + ret = copy_to_user(dst, &c, 1);
    + if (ret) return ret;
    + }
    + return ret;
    +}
    +
    long strncpy_from_user(char *dst, const char *src, long count);
    long __strncpy_from_user(char *dst, const char *src, long count);
    long strnlen_user(const char *str, long n);
    --- linux.clean/include/linux/compat_ioctl.h 2003-05-27 04:52:28.000000000 -0700
    +++ linux/include/linux/compat_ioctl.h 2003-05-29 05:35:16.000000000 -0700
    @@ -355,6 +355,15 @@
    COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
    COMPATIBLE_IOCTL(CDROM_DEBUG)
    COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
    +/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
    + * not take a struct cdrom_read, instead they take a struct cdrom_msf
    + * which is compatible.
    + */
    +COMPATIBLE_IOCTL(CDROMREADMODE2)
    +COMPATIBLE_IOCTL(CDROMREADMODE1)
    +COMPATIBLE_IOCTL(CDROMREADRAW)
    +COMPATIBLE_IOCTL(CDROMREADCOOKED)
    +COMPATIBLE_IOCTL(CDROMREADALL)
    /* DVD ioctls */
    COMPATIBLE_IOCTL(DVD_READ_STRUCT)
    COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
    --- linux.clean/fs/compat_ioctl.c 2003-05-27 07:36:47.000000000 -0700
    +++ linux/fs/compat_ioctl.c 2003-05-29 05:55:16.000000000 -0700
    @@ -554,74 +554,27 @@

    static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - struct ifreq ifr;
    - mm_segment_t old_fs;
    - int err, len;
    - u32 data, ethcmd;
    + struct ifreq *ifr;
    + struct ifreq32 *ifr32;
    + u32 data;
    + void *datap;

    - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
    - return -EFAULT;
    - ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
    - if (!ifr.ifr_data)
    - return -EAGAIN;
    -
    - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
    -
    - if (get_user(ethcmd, (u32 *)compat_ptr(data))) {
    - err = -EFAULT;
    - goto out;
    - }
    - switch (ethcmd) {
    - case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break;
    - case ETHTOOL_GMSGLVL:
    - case ETHTOOL_SMSGLVL:
    - case ETHTOOL_GLINK:
    - case ETHTOOL_NWAY_RST: len = sizeof(struct ethtool_value); break;
    - case ETHTOOL_GREGS: {
    - struct ethtool_regs *regaddr = compat_ptr(data);
    - /* darned variable size arguments */
    - if (get_user(len, (u32 *)&regaddr->len)) {
    - err = -EFAULT;
    - goto out;
    - }
    - if (len > PAGE_SIZE - sizeof(struct ethtool_regs)) {
    - err = -EINVAL;
    - goto out;
    - }
    - len += sizeof(struct ethtool_regs);
    - break;
    - }
    - case ETHTOOL_GSET:
    - case ETHTOOL_SSET: len = sizeof(struct ethtool_cmd); break;
    - default:
    - err = -EOPNOTSUPP;
    - goto out;
    - }
    + ifr = compat_alloc_user_space(sizeof(*ifr));
    + ifr32 = (struct ifreq32 *) arg;

    - if (copy_from_user(ifr.ifr_data, compat_ptr(data), len)) {
    - err = -EFAULT;
    - goto out;
    - }
    + if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
    + return -EFAULT;

    - old_fs = get_fs();
    - set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
    - set_fs (old_fs);
    - if (!err) {
    - u32 data;
    + if (get_user(data, &ifr32->ifr_ifru.ifru_data))
    + return -EFAULT;

    - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
    - len = copy_to_user(compat_ptr(data), ifr.ifr_data, len);
    - if (len)
    - err = -EFAULT;
    - }
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, &ifr->ifr_ifru.ifru_data))
    + return -EFAULT;

    -out:
    - free_page((unsigned long)ifr.ifr_data);
    - return err;
    + return sys_ioctl(fd, cmd, (unsigned long) ifr);
    }

    -
    static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
    {
    struct ifreq ifr;
    @@ -894,65 +847,113 @@
    compat_caddr_t transp;
    };

    -static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
    +static int do_cmap_ptr(__u16 **ptr64, __u32 *ptr32)
    {
    - mm_segment_t old_fs = get_fs();
    - u32 red = 0, green = 0, blue = 0, transp = 0;
    + __u32 data;
    + void *datap;
    +
    + if (get_user(data, ptr32))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, ptr64))
    + return -EFAULT;
    + return 0;
    +}
    +
    +static int fb_getput_cmap(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + struct fb_cmap *cmap;
    + struct fb_cmap32 *cmap32;
    + int err;
    +
    + cmap = compat_alloc_user_space(sizeof(*cmap));
    + cmap32 = (struct fb_cmap32 *) arg;
    +
    + if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
    + return -EFAULT;
    +
    + if (do_cmap_ptr(&cmap->red, &cmap32->red) ||
    + do_cmap_ptr(&cmap->green, &cmap32->green) ||
    + do_cmap_ptr(&cmap->blue, &cmap32->blue) ||
    + do_cmap_ptr(&cmap->transp, &cmap32->transp))
    + return -EFAULT;
    +
    + err = sys_ioctl(fd, cmd, (unsigned long) cmap);
    +
    + if (!err) {
    + if (copy_in_user(&cmap32->start,
    + &cmap->start,
    + 2 * sizeof(__u32)))
    + err = -EFAULT;
    + }
    + return err;
    +}
    +
    +static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
    + struct fb_fix_screeninfo32 *fix32)
    +{
    + __u32 data;
    + int err;
    +
    + err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
    +
    + data = (__u32) (unsigned long) fix->smem_start;
    + err |= put_user(data, &fix32->smem_start);
    +
    + err |= put_user(fix->smem_len, &fix32->smem_len);
    + err |= put_user(fix->type, &fix32->type);
    + err |= put_user(fix->type_aux, &fix32->type_aux);
    + err |= put_user(fix->visual, &fix32->visual);
    + err |= put_user(fix->xpanstep, &fix32->xpanstep);
    + err |= put_user(fix->ypanstep, &fix32->ypanstep);
    + err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
    + err |= put_user(fix->line_length, &fix32->line_length);
    +
    + data = (__u32) (unsigned long) fix->mmio_start;
    + err |= put_user(data, &fix32->mmio_start);
    +
    + err |= put_user(fix->mmio_len, &fix32->mmio_len);
    + err |= put_user(fix->accel, &fix32->accel);
    + err |= copy_to_user(fix32->reserved, fix->reserved,
    + sizeof(fix->reserved));
    +
    + return err;
    +}
    +
    +static int fb_get_fscreeninfo(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + mm_segment_t old_fs;
    struct fb_fix_screeninfo fix;
    - struct fb_cmap cmap;
    - void *karg;
    - int err = 0;
    + struct fb_fix_screeninfo32 *fix32;
    + int err;
    +
    + fix32 = (struct fb_fix_screeninfo32 *) arg;
    +
    + old_fs = get_fs();
    + set_fs(KERNEL_DS);
    + err = sys_ioctl(fd, cmd, (unsigned long) &fix);
    + set_fs(old_fs);
    +
    + if (!err)
    + err = do_fscreeninfo_to_user(&fix, fix32);
    +
    + return err;
    +}
    +
    +static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + int err;

    - memset(&cmap, 0, sizeof(cmap));
    switch (cmd) {
    case FBIOGET_FSCREENINFO:
    - karg = &fix;
    + err = fb_get_fscreeninfo(fd,cmd, arg);
    break;
    - case FBIOGETCMAP:
    - case FBIOPUTCMAP:
    - karg = &cmap;
    - err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
    - err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
    - err |= __get_user(red, &((struct fb_cmap32 *)arg)->red);
    - err |= __get_user(green, &((struct fb_cmap32 *)arg)->green);
    - err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue);
    - err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp);
    - if (err) {
    - err = -EFAULT;
    - goto out;
    - }
    - if (cmap.len > PAGE_SIZE/sizeof(u16)) {
    - err = -EINVAL;
    - goto out;
    - }
    - err = -ENOMEM;
    - cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
    - if (!cmap.red)
    - goto out;
    - cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
    - if (!cmap.green)
    - goto out;
    - cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
    - if (!cmap.blue)
    - goto out;
    - if (transp) {
    - cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
    - if (!cmap.transp)
    - goto out;
    - }
    -
    - if (cmd == FBIOGETCMAP)
    - break;

    - err = __copy_from_user(cmap.red, compat_ptr(red), cmap.len * sizeof(__u16));
    - err |= __copy_from_user(cmap.green, compat_ptr(green), cmap.len * sizeof(__u16));
    - err |= __copy_from_user(cmap.blue, compat_ptr(blue), cmap.len * sizeof(__u16));
    - if (cmap.transp) err |= __copy_from_user(cmap.transp, compat_ptr(transp), cmap.len * sizeof(__u16));
    - if (err) {
    - err = -EFAULT;
    - goto out;
    - }
    + case FBIOGETCMAP:
    + case FBIOPUTCMAP:
    + err = fb_getput_cmap(fd, cmd, arg);
    break;
    +
    default:
    do {
    static int count;
    @@ -961,47 +962,10 @@
    "cmd(%08x) arg(%08lx)\n",
    __FUNCTION__, fd, cmd, arg);
    } while(0);
    - return -ENOSYS;
    - }
    - set_fs(KERNEL_DS);
    - err = sys_ioctl(fd, cmd, (unsigned long)karg);
    - set_fs(old_fs);
    - if (err)
    - goto out;
    - switch (cmd) {
    - case FBIOGET_FSCREENINFO:
    - err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id));
    - err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start);
    - err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len);
    - err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type);
    - err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux);
    - err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual);
    - err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep);
    - err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep);
    - err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep);
    - err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length);
    - err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start);
    - err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len);
    - err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel);
    - err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved));
    - break;
    - case FBIOGETCMAP:
    - err = __copy_to_user(compat_ptr(red), cmap.red, cmap.len * sizeof(__u16));
    - err |= __copy_to_user(compat_ptr(green), cmap.blue, cmap.len * sizeof(__u16));
    - err |= __copy_to_user(compat_ptr(blue), cmap.blue, cmap.len * sizeof(__u16));
    - if (cmap.transp)
    - err |= __copy_to_user(compat_ptr(transp), cmap.transp, cmap.len * sizeof(__u16));
    + err = -ENOSYS;
    break;
    - case FBIOPUTCMAP:
    - break;
    - }
    - if (err)
    - err = -EFAULT;
    + };

    -out: if (cmap.red) kfree(cmap.red);
    - if (cmap.green) kfree(cmap.green);
    - if (cmap.blue) kfree(cmap.blue);
    - if (cmap.transp) kfree(cmap.transp);
    return err;
    }

    @@ -1056,141 +1020,118 @@
    compat_uint_t iov_len;
    } sg_iovec32_t;

    -#define EMU_SG_MAX 128
    -
    -static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
    +static int sg_build_iovec(sg_io_hdr_t *sgio, void *dxferp, u16 iovec_count)
    {
    - sg_iovec32_t *uiov = compat_ptr(uptr32);
    - sg_iovec_t *kiov;
    + sg_iovec_t *iov = (sg_iovec_t *) (sgio + 1);
    + sg_iovec32_t *iov32 = dxferp;
    int i;

    - if (sgp->iovec_count > EMU_SG_MAX)
    - return -EINVAL;
    - sgp->dxferp = kmalloc(sgp->iovec_count *
    - sizeof(sg_iovec_t), GFP_KERNEL);
    - if (!sgp->dxferp)
    - return -ENOMEM;
    - memset(sgp->dxferp, 0,
    - sgp->iovec_count * sizeof(sg_iovec_t));
    -
    - kiov = (sg_iovec_t *) sgp->dxferp;
    - for (i = 0; i < sgp->iovec_count; i++) {
    - u32 iov_base32;
    - if (__get_user(iov_base32, &uiov->iov_base) ||
    - __get_user(kiov->iov_len, &uiov->iov_len))
    - return -EFAULT;
    - if (verify_area(VERIFY_WRITE, compat_ptr(iov_base32), kiov->iov_len))
    + for (i = 0; i < iovec_count; i++) {
    + u32 base, len;
    +
    + if (get_user(base, &iov32[i].iov_base) ||
    + get_user(len, &iov32[i].iov_len) ||
    + put_user((void *)(unsigned long)base, &iov[i].iov_base) ||
    + put_user(len, &iov[i].iov_len))
    return -EFAULT;
    - kiov->iov_base = compat_ptr(iov_base32);
    - uiov++;
    - kiov++;
    }

    return 0;
    }

    -static void free_sg_iovec(sg_io_hdr_t *sgp)
    -{
    - kfree(sgp->dxferp);
    - sgp->dxferp = NULL;
    -}
    -
    static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - sg_io_hdr32_t *sg_io32;
    - sg_io_hdr_t sg_io64;
    - u32 dxferp32, cmdp32, sbp32;
    - mm_segment_t old_fs;
    - int err = 0;
    + sg_io_hdr_t *sgio;
    + sg_io_hdr32_t *sgio32;
    + u16 iovec_count;
    + u32 data;
    + void *dxferp;
    + int err;

    - sg_io32 = (sg_io_hdr32_t *)arg;
    - err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
    - err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
    - err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
    - err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
    - err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
    - err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
    - err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
    - err |= __get_user(sg_io64.flags, &sg_io32->flags);
    - err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
    -
    - sg_io64.dxferp = NULL;
    - sg_io64.cmdp = NULL;
    - sg_io64.sbp = NULL;
    -
    - err |= __get_user(cmdp32, &sg_io32->cmdp);
    - sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
    - if (copy_from_user(sg_io64.cmdp,
    - compat_ptr(cmdp32),
    - sg_io64.cmd_len)) {
    - err = -EFAULT;
    - goto out;
    - }
    + sgio32 = (sg_io_hdr32_t *) arg;
    + if (get_user(iovec_count, &sgio32->iovec_count))
    + return -EFAULT;

    - err |= __get_user(sbp32, &sg_io32->sbp);
    - sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
    - if (!sg_io64.sbp) {
    - err = -ENOMEM;
    - goto out;
    - }
    - if (copy_from_user(sg_io64.sbp,
    - compat_ptr(sbp32),
    - sg_io64.mx_sb_len)) {
    - err = -EFAULT;
    - goto out;
    + {
    + void *new, *top;
    +
    + top = compat_alloc_user_space(0);
    + new = compat_alloc_user_space(sizeof(sg_io_hdr_t) +
    + (iovec_count *
    + sizeof(sg_iovec_t)));
    + if (new > top)
    + return -EINVAL;
    +
    + sgio = new;
    }

    - err |= __get_user(dxferp32, &sg_io32->dxferp);
    - if (sg_io64.iovec_count) {
    - int ret;
    -
    - if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
    - err = ret;
    - goto out;
    - }
    + /* Ok, now construct. */
    + if (copy_in_user(&sgio->interface_id, &sgio32->interface_id,
    + (2 * sizeof(int)) +
    + (2 * sizeof(unsigned char)) +
    + (1 * sizeof(unsigned short)) +
    + (1 * sizeof(unsigned int))))
    + return -EFAULT;
    +
    + if (get_user(data, &sgio32->dxferp))
    + return -EFAULT;
    + dxferp = (void *) (unsigned long) data;
    + if (iovec_count) {
    + if (sg_build_iovec(sgio, dxferp, iovec_count))
    + return -EFAULT;
    } else {
    - err = verify_area(VERIFY_WRITE, compat_ptr(dxferp32), sg_io64.dxfer_len);
    - if (err)
    - goto out;
    + if (put_user(dxferp, &sgio->dxferp))
    + return -EFAULT;
    + }
    +
    + {
    + unsigned char *cmdp, *sbp;
    +
    + if (get_user(data, &sgio32->cmdp))
    + return -EFAULT;
    + cmdp = (unsigned char *) (unsigned long) data;

    - sg_io64.dxferp = compat_ptr(dxferp32);
    + if (get_user(data, &sgio32->sbp))
    + return -EFAULT;
    + sbp = (unsigned char *) (unsigned long) data;
    +
    + if (put_user(cmdp, &sgio->cmdp) ||
    + put_user(sbp, &sgio->sbp))
    + return -EFAULT;
    }

    - /* Unused internally, do not even bother to copy it over. */
    - sg_io64.usr_ptr = NULL;
    + if (copy_in_user(&sgio->timeout, &sgio32->timeout,
    + 3 * sizeof(int)))
    + return -EFAULT;

    - if (err)
    + if (get_user(data, &sgio32->usr_ptr))
    + return -EFAULT;
    + if (put_user((void *)(unsigned long)data, &sgio->usr_ptr))
    return -EFAULT;

    - old_fs = get_fs();
    - set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
    - set_fs (old_fs);
    + if (copy_in_user(&sgio->status, &sgio32->status,
    + (4 * sizeof(unsigned char)) +
    + (2 * sizeof(unsigned (short))) +
    + (3 * sizeof(int))))
    + return -EFAULT;

    - if (err < 0)
    - goto out;
    + err = sys_ioctl(fd, cmd, (unsigned long) sgio);

    - err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
    - err |= __put_user(sg_io64.status, &sg_io32->status);
    - err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
    - err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
    - err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
    - err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
    - err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
    - err |= __put_user(sg_io64.resid, &sg_io32->resid);
    - err |= __put_user(sg_io64.duration, &sg_io32->duration);
    - err |= __put_user(sg_io64.info, &sg_io32->info);
    - err |= copy_to_user(compat_ptr(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
    - if (err)
    - err = -EFAULT;
    + if (err >= 0) {
    + void *datap;
    +
    + if (copy_in_user(&sgio32->pack_id, &sgio->pack_id,
    + sizeof(int)) ||
    + get_user(datap, &sgio->usr_ptr) ||
    + put_user((u32)(unsigned long)datap,
    + &sgio32->usr_ptr) ||
    + copy_in_user(&sgio32->status, &sgio->status,
    + (4 * sizeof(unsigned char)) +
    + (2 * sizeof(unsigned short)) +
    + (3 * sizeof(int))))
    + err = -EFAULT;
    + }

    -out:
    - if (sg_io64.cmdp)
    - kfree(sg_io64.cmdp);
    - if (sg_io64.sbp)
    - kfree(sg_io64.sbp);
    - if (sg_io64.dxferp && sg_io64.iovec_count)
    - free_sg_iovec(&sg_io64);
    return err;
    }

    @@ -1241,39 +1182,65 @@
    };
    #define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)

    +static int ppp_gidle(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + struct ppp_idle *idle;
    + struct ppp_idle32 *idle32;
    + __kernel_time_t xmit, recv;
    + int err;
    +
    + idle = compat_alloc_user_space(sizeof(*idle));
    + idle32 = (struct ppp_idle32 *) arg;
    +
    + err = sys_ioctl(fd, PPPIOCGIDLE, (unsigned long) idle);
    +
    + if (!err) {
    + if (get_user(xmit, &idle->xmit_idle) ||
    + get_user(recv, &idle->recv_idle) ||
    + put_user(xmit, &idle32->xmit_idle) ||
    + put_user(recv, &idle32->recv_idle))
    + err = -EFAULT;
    + }
    + return err;
    +}
    +
    +static int ppp_scompress(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + struct ppp_option_data *odata;
    + struct ppp_option_data32 *odata32;
    + __u32 data;
    + void *datap;
    +
    + odata = compat_alloc_user_space(sizeof(*odata));
    + odata32 = (struct ppp_option_data32 *) arg;
    +
    + if (get_user(data, &odata32->ptr))
    + return -EFAULT;
    +
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, &odata->ptr))
    + return -EFAULT;
    +
    + if (copy_in_user(&odata->length, &odata32->length,
    + sizeof(__u32) + sizeof(int)))
    + return -EFAULT;
    +
    + return sys_ioctl(fd, PPPIOCSCOMPRESS, (unsigned long) odata);
    +}
    +
    static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - mm_segment_t old_fs = get_fs();
    - struct ppp_option_data32 data32;
    - struct ppp_option_data data;
    - struct ppp_idle32 idle32;
    - struct ppp_idle idle;
    - unsigned int kcmd;
    - void *karg;
    - int err = 0;
    + int err;

    switch (cmd) {
    case PPPIOCGIDLE32:
    - kcmd = PPPIOCGIDLE;
    - karg = &idle;
    + err = ppp_gidle(fd, cmd, arg);
    break;
    +
    case PPPIOCSCOMPRESS32:
    - if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
    - return -EFAULT;
    - if (data32.length > PAGE_SIZE)
    - return -EINVAL;
    - data.ptr = kmalloc (data32.length, GFP_KERNEL);
    - if (!data.ptr)
    - return -ENOMEM;
    - if (copy_from_user(data.ptr, compat_ptr(data32.ptr), data32.length)) {
    - kfree(data.ptr);
    - return -EFAULT;
    - }
    - data.length = data32.length;
    - data.transmit = data32.transmit;
    - kcmd = PPPIOCSCOMPRESS;
    - karg = &data;
    + err = ppp_scompress(fd, cmd, arg);
    break;
    +
    default:
    do {
    static int count;
    @@ -1282,26 +1249,10 @@
    "cmd(%08x) arg(%08x)\n",
    (int)fd, (unsigned int)cmd, (unsigned int)arg);
    } while(0);
    - return -EINVAL;
    - }
    - set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, kcmd, (unsigned long)karg);
    - set_fs (old_fs);
    - switch (cmd) {
    - case PPPIOCGIDLE32:
    - if (err)
    - return err;
    - idle32.xmit_idle = idle.xmit_idle;
    - idle32.recv_idle = idle.recv_idle;
    - if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32)))
    - return -EFAULT;
    - break;
    - case PPPIOCSCOMPRESS32:
    - kfree(data.ptr);
    - break;
    - default:
    + err = -EINVAL;
    break;
    - }
    + };
    +
    return err;
    }

    @@ -1429,12 +1380,6 @@
    return err ? -EFAULT: 0;
    }

    -struct cdrom_read32 {
    - compat_int_t cdread_lba;
    - compat_caddr_t cdread_bufaddr;
    - compat_int_t cdread_buflen;
    -};
    -
    struct cdrom_read_audio32 {
    union cdrom_addr addr;
    u8 addr_format;
    @@ -1448,60 +1393,94 @@
    compat_uint_t buflen;
    compat_int_t stat;
    compat_caddr_t sense;
    - compat_caddr_t reserved[3]; /* Oops? it has data_direction, quiet and timeout fields? */
    -};
    + unsigned char data_direction;
    + compat_int_t quiet;
    + compat_int_t timeout;
    + compat_caddr_t reserved[1];
    +};
    +
    +static int cdrom_do_read_audio(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + struct cdrom_read_audio *cdread_audio;
    + struct cdrom_read_audio32 *cdread_audio32;
    + __u32 data;
    + void *datap;
    +
    + cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
    + cdread_audio32 = (struct cdrom_read_audio32 *) arg;
    +
    + if (copy_in_user(&cdread_audio->addr,
    + &cdread_audio32->addr,
    + (sizeof(*cdread_audio32) -
    + sizeof(compat_caddr_t))))
    + return -EFAULT;
    +
    + if (get_user(data, &cdread_audio32->buf))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, &cdread_audio->buf))
    + return -EFAULT;
    +
    + return sys_ioctl(fd, cmd, (unsigned long) cdread_audio);
    +}
    +
    +static int __cgc_do_ptr(void **ptr64, __u32 *ptr32)
    +{
    + u32 data;
    + void *datap;
    +
    + if (get_user(data, ptr32))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, ptr64))
    + return -EFAULT;
    +
    + return 0;
    +}
    +
    +static int cdrom_do_generic_command(unsigned int fd, unsigned int cmd, unsigned long arg)
    +{
    + struct cdrom_generic_command *cgc;
    + struct cdrom_generic_command32 *cgc32;
    + unsigned char dir;
    +
    + cgc = compat_alloc_user_space(sizeof(*cgc));
    + cgc32 = (struct cdrom_generic_command32 *) arg;
    +
    + if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
    + __cgc_do_ptr((void **) &cgc->buffer, &cgc32->buffer) ||
    + copy_in_user(&cgc->buflen, &cgc32->buflen,
    + (sizeof(unsigned int) + sizeof(int))) ||
    + __cgc_do_ptr((void **) &cgc->sense, &cgc32->sense))
    + return -EFAULT;
    +
    + if (get_user(dir, &cgc->data_direction) ||
    + put_user(dir, &cgc32->data_direction))
    + return -EFAULT;
    +
    + if (copy_in_user(&cgc->quiet, &cgc32->quiet,
    + 2 * sizeof(int)))
    + return -EFAULT;
    +
    + if (__cgc_do_ptr(&cgc->reserved[0], &cgc32->reserved[0]))
    + return -EFAULT;
    +
    + return sys_ioctl(fd, cmd, (unsigned long) cgc);
    +}

    static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - mm_segment_t old_fs = get_fs();
    - struct cdrom_read cdread;
    - struct cdrom_read_audio cdreadaudio;
    - struct cdrom_generic_command cgc;
    - compat_caddr_t addr;
    - char *data = 0;
    - void *karg;
    - int err = 0;
    + int err;

    switch(cmd) {
    - case CDROMREADMODE2:
    - case CDROMREADMODE1:
    - case CDROMREADRAW:
    - case CDROMREADCOOKED:
    - karg = &cdread;
    - err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba);
    - err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr);
    - err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen);
    - if (err)
    - return -EFAULT;
    - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cdread.cdread_buflen))
    - return -EFAULT;
    - cdread.cdread_bufaddr = compat_ptr(addr);
    - break;
    case CDROMREADAUDIO:
    - karg = &cdreadaudio;
    - err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr));
    - err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format);
    - err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes);
    - err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
    - if (err)
    - return -EFAULT;
    -
    -
    - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cdreadaudio.nframes*2352))
    - return -EFAULT;
    - cdreadaudio.buf = compat_ptr(addr);
    + err = cdrom_do_read_audio(fd, cmd, arg);
    break;
    +
    case CDROM_SEND_PACKET:
    - karg = &cgc;
    - err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd));
    - err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer);
    - err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
    - if (err)
    - return -EFAULT;
    - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cgc.buflen))
    - return -EFAULT;
    - cgc.buffer = compat_ptr(addr);
    + err = cdrom_do_generic_command(fd, cmd, arg);
    break;
    +
    default:
    do {
    static int count;
    @@ -1510,14 +1489,11 @@
    "cmd(%08x) arg(%08x)\n",
    (int)fd, (unsigned int)cmd, (unsigned int)arg);
    } while(0);
    - return -EINVAL;
    - }
    - set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, cmd, (unsigned long)karg);
    - set_fs (old_fs);
    - if (data)
    - kfree(data);
    - return err ? -EFAULT : 0;
    + err = -EINVAL;
    + break;
    + };
    +
    + return err;
    }

    struct loop_info32 {
    @@ -1547,7 +1523,6 @@
    err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
    err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
    err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
    -
    err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
    8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
    if (err) {
    @@ -1792,68 +1767,62 @@

    static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - struct atm_iobuf32 iobuf32;
    - struct atm_iobuf iobuf = { 0, NULL };
    - mm_segment_t old_fs;
    - int err;
    + struct atm_iobuf *iobuf;
    + struct atm_iobuf32 *iobuf32;
    + u32 data;
    + void *datap;
    + int len, err;

    - err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg,
    - sizeof(struct atm_iobuf32));
    - if (err)
    + iobuf = compat_alloc_user_space(sizeof(*iobuf));
    + iobuf32 = (struct atm_iobuf32 *) arg;
    +
    + if (get_user(len, &iobuf32->length) ||
    + get_user(data, &iobuf32->buffer))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(len, &iobuf->length) ||
    + put_user(datap, &iobuf->buffer))
    return -EFAULT;

    - iobuf.length = iobuf32.length;
    + err = sys_ioctl(fd, cmd, (unsigned long)iobuf);

    - if (iobuf32.buffer == (compat_caddr_t) NULL || iobuf32.length == 0) {
    - iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
    - } else {
    - iobuf.buffer = compat_ptr(iobuf32.buffer);
    - if (verify_area(VERIFY_WRITE, iobuf.buffer, iobuf.length))
    - return -EINVAL;
    + if (!err) {
    + if (copy_in_user(&iobuf32->length, &iobuf->length,
    + sizeof(int)))
    + err = -EFAULT;
    }

    - old_fs = get_fs(); set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);
    - set_fs (old_fs);
    - if(!err)
    - err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
    -
    return err;
    }

    -
    static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - struct atmif_sioc32 sioc32;
    - struct atmif_sioc sioc = { 0, 0, NULL };
    - mm_segment_t old_fs;
    - int err;
    + struct atmif_sioc *sioc;
    + struct atmif_sioc32 *sioc32;
    + u32 data;
    + void *datap;
    + int err;

    - err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg,
    - sizeof(struct atmif_sioc32));
    - if (err)
    - return -EFAULT;
    + sioc = compat_alloc_user_space(sizeof(*sioc));
    + sioc32 = (struct atmif_sioc32 *) arg;

    - sioc.number = sioc32.number;
    - sioc.length = sioc32.length;
    -
    - if (sioc32.arg == (compat_caddr_t) NULL || sioc32.length == 0) {
    - sioc.arg = (void*)(unsigned long)sioc32.arg;
    - } else {
    - sioc.arg = compat_ptr(sioc32.arg);
    - if (verify_area(VERIFY_WRITE, sioc.arg, sioc32.length))
    - return -EFAULT;
    - }
    -
    - old_fs = get_fs(); set_fs (KERNEL_DS);
    - err = sys_ioctl (fd, cmd, (unsigned long)&sioc);
    - set_fs (old_fs);
    - if (!err)
    - err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
    + if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
    + get_user(data, &sioc32->arg))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, &sioc->arg))
    + return -EFAULT;
    +
    + err = sys_ioctl(fd, cmd, (unsigned long) sioc);
    +
    + if (!err) {
    + if (copy_in_user(&sioc32->length, &sioc->length,
    + sizeof(int)))
    + err = -EFAULT;
    + }
    return err;
    }

    -
    static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
    {
    int i;
    @@ -1871,15 +1840,14 @@
    return do_atmif_sioc(fd, cmd32, arg);
    }

    - for (i = 0; i < NR_ATM_IOCTL; i++) {
    - if (cmd32 == atm_ioctl_map[i].cmd32) {
    - cmd = atm_ioctl_map[i].cmd;
    - break;
    - }
    + for (i = 0; i < NR_ATM_IOCTL; i++) {
    + if (cmd32 == atm_ioctl_map[i].cmd32) {
    + cmd = atm_ioctl_map[i].cmd;
    + break;
    }
    - if (i == NR_ATM_IOCTL) {
    + }
    + if (i == NR_ATM_IOCTL)
    return -EINVAL;
    - }

    switch (cmd) {
    case ATM_GETNAMES:
    @@ -2310,36 +2278,33 @@

    static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
    {
    - mm_segment_t old_fs = get_fs();
    - struct mtd_oob_buf32 *uarg = (struct mtd_oob_buf32 *)arg;
    - struct mtd_oob_buf karg;
    - u32 tmp;
    - int ret;
    + struct mtd_oob_buf *buf = compat_alloc_user_space(sizeof(*buf));
    + struct mtd_oob_buf32 *buf32 = (struct mtd_oob_buf32 *) arg;
    + u32 data;
    + char *datap;
    + unsigned int real_cmd;
    + int err;

    - if (get_user(karg.start, &uarg->start) ||
    - get_user(karg.length, &uarg->length) ||
    - get_user(tmp, &uarg->ptr))
    - return -EFAULT;
    + real_cmd = (cmd == MEMREADOOB32) ?
    + MEMREADOOB : MEMWRITEOOB;

    - karg.ptr = compat_ptr(tmp);
    - if (verify_area(VERIFY_WRITE, karg.ptr, karg.length))
    + if (copy_in_user(&buf->start, &buf32->start,
    + 2 * sizeof(u32)) ||
    + get_user(data, &buf32->ptr))
    + return -EFAULT;
    + datap = (void *) (unsigned long) data;
    + if (put_user(datap, &buf->ptr))
    return -EFAULT;

    - set_fs(KERNEL_DS);
    - if (MEMREADOOB32 == cmd)
    - ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
    - else if (MEMWRITEOOB32 == cmd)
    - ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
    - else
    - ret = -EINVAL;
    - set_fs(old_fs);
    + err = sys_ioctl(fd, real_cmd, (unsigned long) buf);

    - if (0 == ret && cmd == MEMREADOOB32) {
    - ret = put_user(karg.start, &uarg->start);
    - ret |= put_user(karg.length, &uarg->length);
    + if (!err) {
    + if (copy_in_user(&buf32->start, &buf->start,
    + 2 * sizeof(u32)))
    + err = -EFAULT;
    }

    - return ret;
    + return err;
    }

    #undef CODE
    @@ -2426,12 +2391,7 @@
    HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
    HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
    HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans)
    -HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans)
    -HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans)
    -HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans)
    -HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans)
    HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
    -HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans)
    HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
    HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
    HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)


    --
    When do you have a heart between your knees?
    [Johanka's followup: and *two* hearts?]
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 13:35    [W:0.076 / U:0.728 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site