cregit-Linux how code gets into the kernel

Release 4.11 fs/compat_ioctl.c

Directory: fs
 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
 * Copyright (C) 1997-2000  Jakub Jelinek  (
 * Copyright (C) 1998  Eddie C. Dost  (
 * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
 * Copyright (C) 2003       Pavel Machek (
 * These routines maintain argument size conversion between 32bit and 64bit
 * ioctls.

#include <linux/joystick.h>

#include <linux/types.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/capability.h>
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/ioctl.h>
#include <linux/if.h>
#include <linux/if_bridge.h>
#include <linux/raid/md_u.h>
#include <linux/kd.h>
#include <linux/route.h>
#include <linux/in6.h>
#include <linux/ipv6_route.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/vt.h>
#include <linux/falloc.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/ppp_defs.h>
#include <linux/ppp-ioctl.h>
#include <linux/if_pppox.h>
#include <linux/mtio.h>
#include <linux/auto_fs.h>
#include <linux/auto_fs4.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <linux/fb.h>
#include <linux/videodev2.h>
#include <linux/netdevice.h>
#include <linux/raw.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/rtc.h>
#include <linux/pci.h>
#include <linux/serial.h>
#include <linux/if_tun.h>
#include <linux/ctype.h>
#include <linux/syscalls.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/atalk.h>
#include <linux/gfp.h>
#include <linux/cec.h>

#include "internal.h"

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/rfcomm.h>

#include <linux/capi.h>
#include <linux/gigaset_dev.h>

#include <linux/cdrom.h>
#include <linux/fd.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>

#include <linux/uaccess.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_bonding.h>
#include <linux/watchdog.h>

#include <linux/soundcard.h>
#include <linux/lp.h>
#include <linux/ppdev.h>

#include <linux/atm.h>
#include <linux/atmarp.h>
#include <linux/atmclip.h>
#include <linux/atmdev.h>
#include <linux/atmioc.h>
#include <linux/atmlec.h>
#include <linux/atmmpc.h>
#include <linux/atmsvc.h>
#include <linux/atm_tcp.h>
#include <linux/sonet.h>
#include <linux/atm_suni.h>

#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/nbd.h>
#include <linux/random.h>
#include <linux/filter.h>

#include <linux/hiddev.h>

#define __DVB_CORE__
#include <linux/dvb/audio.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>

#include <linux/sort.h>

#include <asm/fbio.h>

#define convert_in_user(srcptr, dstptr)			\
({                                                      \
        typeof(*srcptr) val;                            \
        get_user(val, srcptr) || put_user(val, dstptr); \

static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err; err = security_file_ioctl(file, cmd, arg); if (err) return err; return vfs_ioctl(file, cmd, arg); }


Jann Horn4998.00%150.00%
Al Viro12.00%150.00%

static int w_long(struct file *file, unsigned int cmd, compat_ulong_t __user *argp) { int err; unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp)); if (valp == NULL) return -EFAULT; err = do_ioctl(file, cmd, (unsigned long)valp); if (err) return err; if (convert_in_user(valp, argp)) return -EFAULT; return 0; }


Andrew Morton4248.84%240.00%
Jann Horn3945.35%240.00%
Arnd Bergmann55.81%120.00%

struct compat_video_event { int32_t type; compat_time_t timestamp; union { video_size_t size; unsigned int frame_rate; } u; };
static int do_video_get_event(struct file *file, unsigned int cmd, struct compat_video_event __user *up) { struct video_event __user *kevent = compat_alloc_user_space(sizeof(*kevent)); int err; if (kevent == NULL) return -EFAULT; err = do_ioctl(file, cmd, (unsigned long)kevent); if (!err) { err = convert_in_user(&kevent->type, &up->type); err |= convert_in_user(&kevent->timestamp, &up->timestamp); err |= convert_in_user(&kevent->u.size.w, &up->u.size.w); err |= convert_in_user(&kevent->u.size.h, &up->u.size.h); err |= convert_in_user(&kevent->u.size.aspect_ratio, &up->u.size.aspect_ratio); if (err) err = -EFAULT; } return err; }


David S. Miller13473.63%125.00%
Jann Horn4323.63%250.00%
Arnd Bergmann52.75%125.00%

struct compat_video_still_picture { compat_uptr_t iFrame; int32_t size; };
static int do_video_stillpicture(struct file *file, unsigned int cmd, struct compat_video_still_picture __user *up) { struct video_still_picture __user *up_native; compat_uptr_t fp; int32_t size; int err; err = get_user(fp, &up->iFrame); err |= get_user(size, &up->size); if (err) return -EFAULT; up_native = compat_alloc_user_space(sizeof(struct video_still_picture)); err = put_user(compat_ptr(fp), &up_native->iFrame); err |= put_user(size, &up_native->size); if (err) return -EFAULT; err = do_ioctl(file, cmd, (unsigned long) up_native); return err; }


David S. Miller7758.33%120.00%
Andrew Morton3325.00%120.00%
Heiko Carstens129.09%120.00%
Jann Horn86.06%120.00%
Arnd Bergmann21.52%120.00%

struct compat_video_spu_palette { int length; compat_uptr_t palette; };
static int do_video_set_spu_palette(struct file *file, unsigned int cmd, struct compat_video_spu_palette __user *up) { struct video_spu_palette __user *up_native; compat_uptr_t palp; int length, err; err = get_user(palp, &up->palette); err |= get_user(length, &up->length); if (err) return -EFAULT; up_native = compat_alloc_user_space(sizeof(struct video_spu_palette)); err = put_user(compat_ptr(palp), &up_native->palette); err |= put_user(length, &up_native->length); if (err) return -EFAULT; err = do_ioctl(file, cmd, (unsigned long) up_native); return err; }


David S. Miller7053.44%116.67%
Andrew Morton3123.66%116.67%
Heiko Carstens129.16%116.67%
Kees Cook86.11%116.67%
Jann Horn86.11%116.67%
Arnd Bergmann21.53%116.67%

#ifdef CONFIG_BLOCK typedef struct sg_io_hdr32 { compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ compat_int_t dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no scatter gather */ compat_uint_t dxfer_len; /* [i] byte count of data transfer */ compat_uint_t dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ compat_int_t pack_id; /* [i->o] unused internally (normally) */ compat_uptr_t usr_ptr; /* [i->o] unused internally */ unsigned char status; /* [o] scsi status */ unsigned char masked_status; /* [o] shifted, masked scsi status */ unsigned char msg_status; /* [o] messaging level data (optional) */ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ unsigned short host_status; /* [o] errors from host adapter */ unsigned short driver_status; /* [o] errors from software driver */ compat_int_t resid; /* [o] dxfer_len - actual_transferred */ compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ compat_uint_t info; /* [o] auxiliary information */ } sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ typedef struct sg_iovec32 { compat_uint_t iov_base; compat_uint_t iov_len; } sg_iovec32_t;
static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) { sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); sg_iovec32_t __user *iov32 = dxferp; int i; 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(compat_ptr(base), &iov[i].iov_base) || put_user(len, &iov[i].iov_len)) return -EFAULT; } if (put_user(iov, &sgio->dxferp)) return -EFAULT; return 0; }


Andrew Morton12787.59%375.00%
Al Viro1812.41%125.00%

static int sg_ioctl_trans(struct file *file, unsigned int cmd, sg_io_hdr32_t __user *sgio32) { sg_io_hdr_t __user *sgio; u16 iovec_count; u32 data; void __user *dxferp; int err; int interface_id; if (get_user(interface_id, &sgio32->interface_id)) return -EFAULT; if (interface_id != 'S') return do_ioctl(file, cmd, (unsigned long)sgio32); if (get_user(iovec_count, &sgio32->iovec_count)) return -EFAULT; { void __user *top = compat_alloc_user_space(0); void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + (iovec_count * sizeof(sg_iovec_t))); if (new > top) return -EINVAL; sgio = new; } /* 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 = compat_ptr(data); if (iovec_count) { if (sg_build_iovec(sgio, dxferp, iovec_count)) return -EFAULT; } else { if (put_user(dxferp, &sgio->dxferp)) return -EFAULT; } { unsigned char __user *cmdp; unsigned char __user *sbp; if (get_user(data, &sgio32->cmdp)) return -EFAULT; cmdp = compat_ptr(data); if (get_user(data, &sgio32->sbp)) return -EFAULT; sbp = compat_ptr(data); if (put_user(cmdp, &sgio->cmdp) || put_user(sbp, &sgio->sbp)) return -EFAULT; } if (copy_in_user(&sgio->timeout, &sgio32->timeout, 3 * sizeof(int))) return -EFAULT; if (get_user(data, &sgio32->usr_ptr)) return -EFAULT; if (put_user(compat_ptr(data), &sgio->usr_ptr)) return -EFAULT; err = do_ioctl(file, cmd, (unsigned long) sgio); if (err >= 0) { void __user *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; } return err; }


Andrew Morton36167.35%225.00%
Arnd Bergmann6311.75%225.00%
Andi Kleen509.33%112.50%
FUJITA Tomonori366.72%112.50%
Al Viro152.80%112.50%
Jann Horn112.05%112.50%

struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ char req_state; char orphan; char sg_io_owned; char problem; int pack_id; compat_uptr_t usr_ptr; unsigned int duration; int unused; };
static int sg_grt_trans(struct file *file, unsigned int cmd, struct compat_sg_req_info __user *o) { int err, i; sg_req_info_t __user *r; r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE); err = do_ioctl(file, cmd, (unsigned long)r); if (err < 0) return err; for (i = 0; i < SG_MAX_QUEUE; i++) { void __user *ptr; int d; if (copy_in_user(o + i, r + i, offsetof(sg_req_info_t, usr_ptr)) || get_user(ptr, &r[i].usr_ptr) || get_user(d, &r[i].duration) || put_user((u32)(unsigned long)(ptr), &o[i].usr_ptr) || put_user(d, &o[i].duration)) return -EFAULT; } return err; }


Arnd Bergmann10257.30%233.33%
Andrew Morton6737.64%233.33%
Jann Horn84.49%116.67%
Al Viro10.56%116.67%

#endif /* CONFIG_BLOCK */ struct sock_fprog32 { unsigned short len; compat_caddr_t filter; }; #define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32) #define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
static int ppp_sock_fprog_ioctl_trans(struct file *file, unsigned int cmd, struct sock_fprog32 __user *u_fprog32) { struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog)); void __user *fptr64; u32 fptr32; u16 flen; if (get_user(flen, &u_fprog32->len) || get_user(fptr32, &u_fprog32->filter)) return -EFAULT; fptr64 = compat_ptr(fptr32); if (put_user(flen, &u_fprog64->len) || put_user(fptr64, &u_fprog64->filter)) return -EFAULT; if (cmd == PPPIOCSPASS32) cmd = PPPIOCSPASS; else cmd = PPPIOCSACTIVE; return do_ioctl(file, cmd, (unsigned long) u_fprog64); }


Andrew Morton6850.37%233.33%
Arnd Bergmann5742.22%233.33%
Jann Horn85.93%116.67%
Al Viro21.48%116.67%

struct ppp_option_data32 { compat_caddr_t ptr; u32 length; compat_int_t transmit; }; #define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) struct ppp_idle32 { compat_time_t xmit_idle; compat_time_t recv_idle; }; #define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
static int ppp_gidle(struct file *file, unsigned int cmd, struct ppp_idle32 __user *idle32) { struct ppp_idle __user *idle; __kernel_time_t xmit, recv; int err; idle = compat_alloc_user_space(sizeof(*idle)); err = do_ioctl(file, 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; }


Arnd Bergmann9580.51%360.00%
Andrew Morton1512.71%120.00%
Jann Horn86.78%120.00%

static int ppp_scompress(struct file *file, unsigned int cmd, struct ppp_option_data32 __user *odata32) { struct ppp_option_data __user *odata; __u32 data; void __user *datap; odata = compat_alloc_user_space(sizeof(*odata)); if (get_user(data, &odata32->ptr)) return -EFAULT; datap = compat_ptr(data); if (put_user(datap, &odata->ptr)) return -EFAULT; if (copy_in_user(&odata->length, &odata32->length, sizeof(__u32) + sizeof(int))) return -EFAULT; return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata); }


Arnd Bergmann8364.84%240.00%
Andrew Morton3325.78%120.00%
Jann Horn86.25%120.00%
Hugh Dickins43.12%120.00%

#ifdef CONFIG_BLOCK struct mtget32 { compat_long_t mt_type; compat_long_t mt_resid; compat_long_t mt_dsreg; compat_long_t mt_gstat; compat_long_t mt_erreg; compat_daddr_t mt_fileno; compat_daddr_t mt_blkno; }; #define MTIOCGET32 _IOR('m', 2, struct mtget32) struct mtpos32 { compat_long_t mt_blkno; }; #define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
static int mt_ioctl_trans(struct file *file, unsigned int cmd, void __user *argp) { /* NULL initialization to make gcc shut up */ struct mtget __user *get = NULL; struct mtget32 __user *umget32; struct mtpos __user *pos = NULL; struct mtpos32 __user *upos32; unsigned long kcmd; void *karg; int err = 0; switch(cmd) { case MTIOCPOS32: kcmd = MTIOCPOS; pos = compat_alloc_user_space(sizeof(*pos)); karg = pos; break; default: /* MTIOCGET32 */ kcmd = MTIOCGET; get = compat_alloc_user_space(sizeof(*get)); karg = get; break; } if (karg == NULL) return -EFAULT; err = do_ioctl(file, kcmd, (unsigned long)karg); if (err) return err; switch (cmd) { case MTIOCPOS32: upos32 = argp; err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno); break; case MTIOCGET32: umget32 = argp; err = convert_in_user(&get->mt_type, &umget32->mt_type); err |= convert_in_user(&get->mt_resid, &umget32->mt_resid); err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg); err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat); err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg); err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno); err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno); break; } return err ? -EFAULT: 0; }


Arnd Bergmann13445.42%225.00%
Jann Horn7324.75%225.00%
Andrew Morton5518.64%337.50%
Al Viro3311.19%112.50%

#endif /* CONFIG_BLOCK */ /* Bluetooth ioctls */ #define HCIUARTSETPROTO _IOW('U', 200, int) #define HCIUARTGETPROTO _IOR('U', 201, int) #define HCIUARTGETDEVICE _IOR('U', 202, int) #define HCIUARTSETFLAGS _IOW('U', 203, int) #define HCIUARTGETFLAGS _IOR('U', 204, int) #define BNEPCONNADD _IOW('B', 200, int) #define BNEPCONNDEL _IOW('B', 201, int) #define BNEPGETCONNLIST _IOR('B', 210, int) #define BNEPGETCONNINFO _IOR('B', 211, int) #define BNEPGETSUPPFEAT _IOR('B', 212, int) #define CMTPCONNADD _IOW('C', 200, int) #define CMTPCONNDEL _IOW('C', 201, int) #define CMTPGETCONNLIST _IOR('C', 210, int) #define CMTPGETCONNINFO _IOR('C', 211, int) #define HIDPCONNADD _IOW('H', 200, int) #define HIDPCONNDEL _IOW('H', 201, int) #define HIDPGETCONNLIST _IOR('H', 210, int) #define HIDPGETCONNINFO _IOR('H', 211, int) struct serial_struct32 { compat_int_t type; compat_int_t line; compat_uint_t port; compat_int_t irq; compat_int_t flags; compat_int_t xmit_fifo_size; compat_int_t custom_divisor; compat_int_t baud_base; unsigned short close_delay; char io_type; char reserved_char[1]; compat_int_t hub6; unsigned short closing_wait; /* time to wait before closing */ unsigned short closing_wait2; /* no longer used... */ compat_uint_t iomem_base; unsigned short iomem_reg_shift; unsigned int port_high; /* compat_ulong_t iomap_base FIXME */ compat_int_t reserved[1]; };
static int serial_struct_ioctl(struct file *file, unsigned cmd, struct serial_struct32 __user *ss32) { typedef struct serial_struct32 SS32; int err; struct serial_struct __user *ss = compat_alloc_user_space(sizeof(*ss)); __u32 udata; unsigned int base; unsigned char *iomem_base; if (ss == NULL) return -EFAULT; if (cmd == TIOCSSERIAL) { if (copy_in_user(ss, ss32, offsetof(SS32, iomem_base)) || get_user(udata, &ss32->iomem_base)) return -EFAULT; iomem_base = compat_ptr(udata); if (put_user(iomem_base, &ss->iomem_base) || convert_in_user(&ss32->iomem_reg_shift, &ss->iomem_reg_shift) || convert_in_user(&ss32->port_high, &ss->port_high) || put_user(0UL,