linux/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
<<
>>
Prefs
   1/*
   2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
   3 *      Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
   4 *
   5 * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
   6 * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
   7 * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
   8 * Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
   9 * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
  10 * Copyright (C) 2008       Hans Verkuil <hverkuil@xs4all.nl>
  11 *
  12 * These routines maintain argument size conversion between 32bit and 64bit
  13 * ioctls.
  14 */
  15
  16#include <linux/compat.h>
  17#include <linux/module.h>
  18#include <linux/videodev2.h>
  19#include <linux/v4l2-subdev.h>
  20#include <media/v4l2-dev.h>
  21#include <media/v4l2-fh.h>
  22#include <media/v4l2-ctrls.h>
  23#include <media/v4l2-ioctl.h>
  24
  25/**
  26 * assign_in_user() - Copy from one __user var to another one
  27 *
  28 * @to: __user var where data will be stored
  29 * @from: __user var where data will be retrieved.
  30 *
  31 * As this code very often needs to allocate userspace memory, it is easier
  32 * to have a macro that will do both get_user() and put_user() at once.
  33 *
  34 * This function complements the macros defined at asm-generic/uaccess.h.
  35 * It uses the same argument order as copy_in_user()
  36 */
  37#define assign_in_user(to, from)                                        \
  38({                                                                      \
  39        typeof(*from) __assign_tmp;                                     \
  40                                                                        \
  41        get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
  42})
  43
  44/**
  45 * get_user_cast() - Stores at a kernelspace local var the contents from a
  46 *              pointer with userspace data that is not tagged with __user.
  47 *
  48 * @__x: var where data will be stored
  49 * @__ptr: var where data will be retrieved.
  50 *
  51 * Sometimes we need to declare a pointer without __user because it
  52 * comes from a pointer struct field that will be retrieved from userspace
  53 * by the 64-bit native ioctl handler. This function ensures that the
  54 * @__ptr will be cast to __user before calling get_user() in order to
  55 * avoid warnings with static code analyzers like smatch.
  56 */
  57#define get_user_cast(__x, __ptr)                                       \
  58({                                                                      \
  59        get_user(__x, (typeof(*__ptr) __user *)(__ptr));                \
  60})
  61
  62/**
  63 * put_user_force() - Stores the contents of a kernelspace local var
  64 *                    into a userspace pointer, removing any __user cast.
  65 *
  66 * @__x: var where data will be stored
  67 * @__ptr: var where data will be retrieved.
  68 *
  69 * Sometimes we need to remove the __user attribute from some data,
  70 * by passing the __force macro. This function ensures that the
  71 * @__ptr will be cast with __force before calling put_user(), in order to
  72 * avoid warnings with static code analyzers like smatch.
  73 */
  74#define put_user_force(__x, __ptr)                                      \
  75({                                                                      \
  76        put_user((typeof(*__x) __force *)(__x), __ptr);                 \
  77})
  78
  79/**
  80 * assign_in_user_cast() - Copy from one __user var to another one
  81 *
  82 * @to: __user var where data will be stored
  83 * @from: var where data will be retrieved that needs to be cast to __user.
  84 *
  85 * As this code very often needs to allocate userspace memory, it is easier
  86 * to have a macro that will do both get_user_cast() and put_user() at once.
  87 *
  88 * This function should be used instead of assign_in_user() when the @from
  89 * variable was not declared as __user. See get_user_cast() for more details.
  90 *
  91 * This function complements the macros defined at asm-generic/uaccess.h.
  92 * It uses the same argument order as copy_in_user()
  93 */
  94#define assign_in_user_cast(to, from)                                   \
  95({                                                                      \
  96        typeof(*from) __assign_tmp;                                     \
  97                                                                        \
  98        get_user_cast(__assign_tmp, from) || put_user(__assign_tmp, to);\
  99})
 100
 101/**
 102 * native_ioctl - Ancillary function that calls the native 64 bits ioctl
 103 * handler.
 104 *
 105 * @file: pointer to &struct file with the file handler
 106 * @cmd: ioctl to be called
 107 * @arg: arguments passed from/to the ioctl handler
 108 *
 109 * This function calls the native ioctl handler at v4l2-dev, e. g. v4l2_ioctl()
 110 */
 111static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 112{
 113        long ret = -ENOIOCTLCMD;
 114
 115        if (file->f_op->unlocked_ioctl)
 116                ret = file->f_op->unlocked_ioctl(file, cmd, arg);
 117
 118        return ret;
 119}
 120
 121
 122/*
 123 * Per-ioctl data copy handlers.
 124 *
 125 * Those come in pairs, with a get_v4l2_foo() and a put_v4l2_foo() routine,
 126 * where "v4l2_foo" is the name of the V4L2 struct.
 127 *
 128 * They basically get two __user pointers, one with a 32-bits struct that
 129 * came from the userspace call and a 64-bits struct, also allocated as
 130 * userspace, but filled internally by do_video_ioctl().
 131 *
 132 * For ioctls that have pointers inside it, the functions will also
 133 * receive an ancillary buffer with extra space, used to pass extra
 134 * data to the routine.
 135 */
 136
 137struct v4l2_clip32 {
 138        struct v4l2_rect        c;
 139        compat_caddr_t          next;
 140};
 141
 142struct v4l2_window32 {
 143        struct v4l2_rect        w;
 144        __u32                   field;  /* enum v4l2_field */
 145        __u32                   chromakey;
 146        compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
 147        __u32                   clipcount;
 148        compat_caddr_t          bitmap;
 149        __u8                    global_alpha;
 150};
 151
 152static int get_v4l2_window32(struct v4l2_window __user *p64,
 153                             struct v4l2_window32 __user *p32,
 154                             void __user *aux_buf, u32 aux_space)
 155{
 156        struct v4l2_clip32 __user *uclips;
 157        struct v4l2_clip __user *kclips;
 158        compat_caddr_t p;
 159        u32 clipcount;
 160
 161        if (!access_ok(p32, sizeof(*p32)) ||
 162            copy_in_user(&p64->w, &p32->w, sizeof(p32->w)) ||
 163            assign_in_user(&p64->field, &p32->field) ||
 164            assign_in_user(&p64->chromakey, &p32->chromakey) ||
 165            assign_in_user(&p64->global_alpha, &p32->global_alpha) ||
 166            get_user(clipcount, &p32->clipcount) ||
 167            put_user(clipcount, &p64->clipcount))
 168                return -EFAULT;
 169        if (clipcount > 2048)
 170                return -EINVAL;
 171        if (!clipcount)
 172                return put_user(NULL, &p64->clips);
 173
 174        if (get_user(p, &p32->clips))
 175                return -EFAULT;
 176        uclips = compat_ptr(p);
 177        if (aux_space < clipcount * sizeof(*kclips))
 178                return -EFAULT;
 179        kclips = aux_buf;
 180        if (put_user(kclips, &p64->clips))
 181                return -EFAULT;
 182
 183        while (clipcount--) {
 184                if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
 185                        return -EFAULT;
 186                if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
 187                        return -EFAULT;
 188                uclips++;
 189                kclips++;
 190        }
 191        return 0;
 192}
 193
 194static int put_v4l2_window32(struct v4l2_window __user *p64,
 195                             struct v4l2_window32 __user *p32)
 196{
 197        struct v4l2_clip __user *kclips;
 198        struct v4l2_clip32 __user *uclips;
 199        compat_caddr_t p;
 200        u32 clipcount;
 201
 202        if (copy_in_user(&p32->w, &p64->w, sizeof(p64->w)) ||
 203            assign_in_user(&p32->field, &p64->field) ||
 204            assign_in_user(&p32->chromakey, &p64->chromakey) ||
 205            assign_in_user(&p32->global_alpha, &p64->global_alpha) ||
 206            get_user(clipcount, &p64->clipcount) ||
 207            put_user(clipcount, &p32->clipcount))
 208                return -EFAULT;
 209        if (!clipcount)
 210                return 0;
 211
 212        if (get_user(kclips, &p64->clips))
 213                return -EFAULT;
 214        if (get_user(p, &p32->clips))
 215                return -EFAULT;
 216        uclips = compat_ptr(p);
 217        while (clipcount--) {
 218                if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
 219                        return -EFAULT;
 220                uclips++;
 221                kclips++;
 222        }
 223        return 0;
 224}
 225
 226struct v4l2_format32 {
 227        __u32   type;   /* enum v4l2_buf_type */
 228        union {
 229                struct v4l2_pix_format  pix;
 230                struct v4l2_pix_format_mplane   pix_mp;
 231                struct v4l2_window32    win;
 232                struct v4l2_vbi_format  vbi;
 233                struct v4l2_sliced_vbi_format   sliced;
 234                struct v4l2_sdr_format  sdr;
 235                struct v4l2_meta_format meta;
 236                __u8    raw_data[200];        /* user-defined */
 237        } fmt;
 238};
 239
 240/**
 241 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
 242 * @index:      on return, index of the first created buffer
 243 * @count:      entry: number of requested buffers,
 244 *              return: number of created buffers
 245 * @memory:     buffer memory type
 246 * @format:     frame format, for which buffers are requested
 247 * @capabilities: capabilities of this buffer type.
 248 * @reserved:   future extensions
 249 */
 250struct v4l2_create_buffers32 {
 251        __u32                   index;
 252        __u32                   count;
 253        __u32                   memory; /* enum v4l2_memory */
 254        struct v4l2_format32    format;
 255        __u32                   capabilities;
 256        __u32                   reserved[7];
 257};
 258
 259static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
 260{
 261        u32 type;
 262
 263        if (get_user(type, &p32->type))
 264                return -EFAULT;
 265
 266        switch (type) {
 267        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 268        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
 269                u32 clipcount;
 270
 271                if (get_user(clipcount, &p32->fmt.win.clipcount))
 272                        return -EFAULT;
 273                if (clipcount > 2048)
 274                        return -EINVAL;
 275                *size = clipcount * sizeof(struct v4l2_clip);
 276                return 0;
 277        }
 278        default:
 279                *size = 0;
 280                return 0;
 281        }
 282}
 283
 284static int bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
 285{
 286        if (!access_ok(p32, sizeof(*p32)))
 287                return -EFAULT;
 288        return __bufsize_v4l2_format(p32, size);
 289}
 290
 291static int __get_v4l2_format32(struct v4l2_format __user *p64,
 292                               struct v4l2_format32 __user *p32,
 293                               void __user *aux_buf, u32 aux_space)
 294{
 295        u32 type;
 296
 297        if (get_user(type, &p32->type) || put_user(type, &p64->type))
 298                return -EFAULT;
 299
 300        switch (type) {
 301        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 302        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 303                return copy_in_user(&p64->fmt.pix, &p32->fmt.pix,
 304                                    sizeof(p64->fmt.pix)) ? -EFAULT : 0;
 305        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 306        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 307                return copy_in_user(&p64->fmt.pix_mp, &p32->fmt.pix_mp,
 308                                    sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
 309        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 310        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 311                return get_v4l2_window32(&p64->fmt.win, &p32->fmt.win,
 312                                         aux_buf, aux_space);
 313        case V4L2_BUF_TYPE_VBI_CAPTURE:
 314        case V4L2_BUF_TYPE_VBI_OUTPUT:
 315                return copy_in_user(&p64->fmt.vbi, &p32->fmt.vbi,
 316                                    sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
 317        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 318        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 319                return copy_in_user(&p64->fmt.sliced, &p32->fmt.sliced,
 320                                    sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
 321        case V4L2_BUF_TYPE_SDR_CAPTURE:
 322        case V4L2_BUF_TYPE_SDR_OUTPUT:
 323                return copy_in_user(&p64->fmt.sdr, &p32->fmt.sdr,
 324                                    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 325        case V4L2_BUF_TYPE_META_CAPTURE:
 326        case V4L2_BUF_TYPE_META_OUTPUT:
 327                return copy_in_user(&p64->fmt.meta, &p32->fmt.meta,
 328                                    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 329        default:
 330                return -EINVAL;
 331        }
 332}
 333
 334static int get_v4l2_format32(struct v4l2_format __user *p64,
 335                             struct v4l2_format32 __user *p32,
 336                             void __user *aux_buf, u32 aux_space)
 337{
 338        if (!access_ok(p32, sizeof(*p32)))
 339                return -EFAULT;
 340        return __get_v4l2_format32(p64, p32, aux_buf, aux_space);
 341}
 342
 343static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *p32,
 344                               u32 *size)
 345{
 346        if (!access_ok(p32, sizeof(*p32)))
 347                return -EFAULT;
 348        return __bufsize_v4l2_format(&p32->format, size);
 349}
 350
 351static int get_v4l2_create32(struct v4l2_create_buffers __user *p64,
 352                             struct v4l2_create_buffers32 __user *p32,
 353                             void __user *aux_buf, u32 aux_space)
 354{
 355        if (!access_ok(p32, sizeof(*p32)) ||
 356            copy_in_user(p64, p32,
 357                         offsetof(struct v4l2_create_buffers32, format)))
 358                return -EFAULT;
 359        return __get_v4l2_format32(&p64->format, &p32->format,
 360                                   aux_buf, aux_space);
 361}
 362
 363static int __put_v4l2_format32(struct v4l2_format __user *p64,
 364                               struct v4l2_format32 __user *p32)
 365{
 366        u32 type;
 367
 368        if (get_user(type, &p64->type))
 369                return -EFAULT;
 370
 371        switch (type) {
 372        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 373        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 374                return copy_in_user(&p32->fmt.pix, &p64->fmt.pix,
 375                                    sizeof(p64->fmt.pix)) ? -EFAULT : 0;
 376        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 377        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 378                return copy_in_user(&p32->fmt.pix_mp, &p64->fmt.pix_mp,
 379                                    sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
 380        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 381        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 382                return put_v4l2_window32(&p64->fmt.win, &p32->fmt.win);
 383        case V4L2_BUF_TYPE_VBI_CAPTURE:
 384        case V4L2_BUF_TYPE_VBI_OUTPUT:
 385                return copy_in_user(&p32->fmt.vbi, &p64->fmt.vbi,
 386                                    sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
 387        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 388        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 389                return copy_in_user(&p32->fmt.sliced, &p64->fmt.sliced,
 390                                    sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
 391        case V4L2_BUF_TYPE_SDR_CAPTURE:
 392        case V4L2_BUF_TYPE_SDR_OUTPUT:
 393                return copy_in_user(&p32->fmt.sdr, &p64->fmt.sdr,
 394                                    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 395        case V4L2_BUF_TYPE_META_CAPTURE:
 396        case V4L2_BUF_TYPE_META_OUTPUT:
 397                return copy_in_user(&p32->fmt.meta, &p64->fmt.meta,
 398                                    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 399        default:
 400                return -EINVAL;
 401        }
 402}
 403
 404static int put_v4l2_format32(struct v4l2_format __user *p64,
 405                             struct v4l2_format32 __user *p32)
 406{
 407        if (!access_ok(p32, sizeof(*p32)))
 408                return -EFAULT;
 409        return __put_v4l2_format32(p64, p32);
 410}
 411
 412static int put_v4l2_create32(struct v4l2_create_buffers __user *p64,
 413                             struct v4l2_create_buffers32 __user *p32)
 414{
 415        if (!access_ok(p32, sizeof(*p32)) ||
 416            copy_in_user(p32, p64,
 417                         offsetof(struct v4l2_create_buffers32, format)) ||
 418            assign_in_user(&p32->capabilities, &p64->capabilities) ||
 419            copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
 420                return -EFAULT;
 421        return __put_v4l2_format32(&p64->format, &p32->format);
 422}
 423
 424struct v4l2_standard32 {
 425        __u32                index;
 426        compat_u64           id;
 427        __u8                 name[24];
 428        struct v4l2_fract    frameperiod; /* Frames, not fields */
 429        __u32                framelines;
 430        __u32                reserved[4];
 431};
 432
 433static int get_v4l2_standard32(struct v4l2_standard __user *p64,
 434                               struct v4l2_standard32 __user *p32)
 435{
 436        /* other fields are not set by the user, nor used by the driver */
 437        if (!access_ok(p32, sizeof(*p32)) ||
 438            assign_in_user(&p64->index, &p32->index))
 439                return -EFAULT;
 440        return 0;
 441}
 442
 443static int put_v4l2_standard32(struct v4l2_standard __user *p64,
 444                               struct v4l2_standard32 __user *p32)
 445{
 446        if (!access_ok(p32, sizeof(*p32)) ||
 447            assign_in_user(&p32->index, &p64->index) ||
 448            assign_in_user(&p32->id, &p64->id) ||
 449            copy_in_user(p32->name, p64->name, sizeof(p32->name)) ||
 450            copy_in_user(&p32->frameperiod, &p64->frameperiod,
 451                         sizeof(p32->frameperiod)) ||
 452            assign_in_user(&p32->framelines, &p64->framelines) ||
 453            copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
 454                return -EFAULT;
 455        return 0;
 456}
 457
 458struct v4l2_plane32 {
 459        __u32                   bytesused;
 460        __u32                   length;
 461        union {
 462                __u32           mem_offset;
 463                compat_long_t   userptr;
 464                __s32           fd;
 465        } m;
 466        __u32                   data_offset;
 467        __u32                   reserved[11];
 468};
 469
 470struct v4l2_buffer32 {
 471        __u32                   index;
 472        __u32                   type;   /* enum v4l2_buf_type */
 473        __u32                   bytesused;
 474        __u32                   flags;
 475        __u32                   field;  /* enum v4l2_field */
 476        struct compat_timeval   timestamp;
 477        struct v4l2_timecode    timecode;
 478        __u32                   sequence;
 479
 480        /* memory location */
 481        __u32                   memory; /* enum v4l2_memory */
 482        union {
 483                __u32           offset;
 484                compat_long_t   userptr;
 485                compat_caddr_t  planes;
 486                __s32           fd;
 487        } m;
 488        __u32                   length;
 489        __u32                   reserved2;
 490        __s32                   request_fd;
 491};
 492
 493static int get_v4l2_plane32(struct v4l2_plane __user *p64,
 494                            struct v4l2_plane32 __user *p32,
 495                            enum v4l2_memory memory)
 496{
 497        compat_ulong_t p;
 498
 499        if (copy_in_user(p64, p32, 2 * sizeof(__u32)) ||
 500            copy_in_user(&p64->data_offset, &p32->data_offset,
 501                         sizeof(p64->data_offset)))
 502                return -EFAULT;
 503
 504        switch (memory) {
 505        case V4L2_MEMORY_MMAP:
 506        case V4L2_MEMORY_OVERLAY:
 507                if (copy_in_user(&p64->m.mem_offset, &p32->m.mem_offset,
 508                                 sizeof(p32->m.mem_offset)))
 509                        return -EFAULT;
 510                break;
 511        case V4L2_MEMORY_USERPTR:
 512                if (get_user(p, &p32->m.userptr) ||
 513                    put_user((unsigned long)compat_ptr(p), &p64->m.userptr))
 514                        return -EFAULT;
 515                break;
 516        case V4L2_MEMORY_DMABUF:
 517                if (copy_in_user(&p64->m.fd, &p32->m.fd, sizeof(p32->m.fd)))
 518                        return -EFAULT;
 519                break;
 520        }
 521
 522        return 0;
 523}
 524
 525static int put_v4l2_plane32(struct v4l2_plane __user *p64,
 526                            struct v4l2_plane32 __user *p32,
 527                            enum v4l2_memory memory)
 528{
 529        unsigned long p;
 530
 531        if (copy_in_user(p32, p64, 2 * sizeof(__u32)) ||
 532            copy_in_user(&p32->data_offset, &p64->data_offset,
 533                         sizeof(p64->data_offset)))
 534                return -EFAULT;
 535
 536        switch (memory) {
 537        case V4L2_MEMORY_MMAP:
 538        case V4L2_MEMORY_OVERLAY:
 539                if (copy_in_user(&p32->m.mem_offset, &p64->m.mem_offset,
 540                                 sizeof(p64->m.mem_offset)))
 541                        return -EFAULT;
 542                break;
 543        case V4L2_MEMORY_USERPTR:
 544                if (get_user(p, &p64->m.userptr) ||
 545                    put_user((compat_ulong_t)ptr_to_compat((void __user *)p),
 546                             &p32->m.userptr))
 547                        return -EFAULT;
 548                break;
 549        case V4L2_MEMORY_DMABUF:
 550                if (copy_in_user(&p32->m.fd, &p64->m.fd, sizeof(p64->m.fd)))
 551                        return -EFAULT;
 552                break;
 553        }
 554
 555        return 0;
 556}
 557
 558static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *p32, u32 *size)
 559{
 560        u32 type;
 561        u32 length;
 562
 563        if (!access_ok(p32, sizeof(*p32)) ||
 564            get_user(type, &p32->type) ||
 565            get_user(length, &p32->length))
 566                return -EFAULT;
 567
 568        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 569                if (length > VIDEO_MAX_PLANES)
 570                        return -EINVAL;
 571
 572                /*
 573                 * We don't really care if userspace decides to kill itself
 574                 * by passing a very big length value
 575                 */
 576                *size = length * sizeof(struct v4l2_plane);
 577        } else {
 578                *size = 0;
 579        }
 580        return 0;
 581}
 582
 583static int get_v4l2_buffer32(struct v4l2_buffer __user *p64,
 584                             struct v4l2_buffer32 __user *p32,
 585                             void __user *aux_buf, u32 aux_space)
 586{
 587        u32 type;
 588        u32 length;
 589        s32 request_fd;
 590        enum v4l2_memory memory;
 591        struct v4l2_plane32 __user *uplane32;
 592        struct v4l2_plane __user *uplane;
 593        compat_caddr_t p;
 594        int ret;
 595
 596        if (!access_ok(p32, sizeof(*p32)) ||
 597            assign_in_user(&p64->index, &p32->index) ||
 598            get_user(type, &p32->type) ||
 599            put_user(type, &p64->type) ||
 600            assign_in_user(&p64->flags, &p32->flags) ||
 601            get_user(memory, &p32->memory) ||
 602            put_user(memory, &p64->memory) ||
 603            get_user(length, &p32->length) ||
 604            put_user(length, &p64->length) ||
 605            get_user(request_fd, &p32->request_fd) ||
 606            put_user(request_fd, &p64->request_fd))
 607                return -EFAULT;
 608
 609        if (V4L2_TYPE_IS_OUTPUT(type))
 610                if (assign_in_user(&p64->bytesused, &p32->bytesused) ||
 611                    assign_in_user(&p64->field, &p32->field) ||
 612                    assign_in_user(&p64->timestamp.tv_sec,
 613                                   &p32->timestamp.tv_sec) ||
 614                    assign_in_user(&p64->timestamp.tv_usec,
 615                                   &p32->timestamp.tv_usec))
 616                        return -EFAULT;
 617
 618        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 619                u32 num_planes = length;
 620
 621                if (num_planes == 0) {
 622                        /*
 623                         * num_planes == 0 is legal, e.g. when userspace doesn't
 624                         * need planes array on DQBUF
 625                         */
 626                        return put_user(NULL, &p64->m.planes);
 627                }
 628                if (num_planes > VIDEO_MAX_PLANES)
 629                        return -EINVAL;
 630
 631                if (get_user(p, &p32->m.planes))
 632                        return -EFAULT;
 633
 634                uplane32 = compat_ptr(p);
 635                if (!access_ok(uplane32,
 636                               num_planes * sizeof(*uplane32)))
 637                        return -EFAULT;
 638
 639                /*
 640                 * We don't really care if userspace decides to kill itself
 641                 * by passing a very big num_planes value
 642                 */
 643                if (aux_space < num_planes * sizeof(*uplane))
 644                        return -EFAULT;
 645
 646                uplane = aux_buf;
 647                if (put_user_force(uplane, &p64->m.planes))
 648                        return -EFAULT;
 649
 650                while (num_planes--) {
 651                        ret = get_v4l2_plane32(uplane, uplane32, memory);
 652                        if (ret)
 653                                return ret;
 654                        uplane++;
 655                        uplane32++;
 656                }
 657        } else {
 658                switch (memory) {
 659                case V4L2_MEMORY_MMAP:
 660                case V4L2_MEMORY_OVERLAY:
 661                        if (assign_in_user(&p64->m.offset, &p32->m.offset))
 662                                return -EFAULT;
 663                        break;
 664                case V4L2_MEMORY_USERPTR: {
 665                        compat_ulong_t userptr;
 666
 667                        if (get_user(userptr, &p32->m.userptr) ||
 668                            put_user((unsigned long)compat_ptr(userptr),
 669                                     &p64->m.userptr))
 670                                return -EFAULT;
 671                        break;
 672                }
 673                case V4L2_MEMORY_DMABUF:
 674                        if (assign_in_user(&p64->m.fd, &p32->m.fd))
 675                                return -EFAULT;
 676                        break;
 677                }
 678        }
 679
 680        return 0;
 681}
 682
 683static int put_v4l2_buffer32(struct v4l2_buffer __user *p64,
 684                             struct v4l2_buffer32 __user *p32)
 685{
 686        u32 type;
 687        u32 length;
 688        enum v4l2_memory memory;
 689        struct v4l2_plane32 __user *uplane32;
 690        struct v4l2_plane *uplane;
 691        compat_caddr_t p;
 692        int ret;
 693
 694        if (!access_ok(p32, sizeof(*p32)) ||
 695            assign_in_user(&p32->index, &p64->index) ||
 696            get_user(type, &p64->type) ||
 697            put_user(type, &p32->type) ||
 698            assign_in_user(&p32->flags, &p64->flags) ||
 699            get_user(memory, &p64->memory) ||
 700            put_user(memory, &p32->memory))
 701                return -EFAULT;
 702
 703        if (assign_in_user(&p32->bytesused, &p64->bytesused) ||
 704            assign_in_user(&p32->field, &p64->field) ||
 705            assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
 706            assign_in_user(&p32->timestamp.tv_usec, &p64->timestamp.tv_usec) ||
 707            copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) ||
 708            assign_in_user(&p32->sequence, &p64->sequence) ||
 709            assign_in_user(&p32->reserved2, &p64->reserved2) ||
 710            assign_in_user(&p32->request_fd, &p64->request_fd) ||
 711            get_user(length, &p64->length) ||
 712            put_user(length, &p32->length))
 713                return -EFAULT;
 714
 715        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 716                u32 num_planes = length;
 717
 718                if (num_planes == 0)
 719                        return 0;
 720                /* We need to define uplane without __user, even though
 721                 * it does point to data in userspace here. The reason is
 722                 * that v4l2-ioctl.c copies it from userspace to kernelspace,
 723                 * so its definition in videodev2.h doesn't have a
 724                 * __user markup. Defining uplane with __user causes
 725                 * smatch warnings, so instead declare it without __user
 726                 * and cast it as a userspace pointer to put_v4l2_plane32().
 727                 */
 728                if (get_user(uplane, &p64->m.planes))
 729                        return -EFAULT;
 730                if (get_user(p, &p32->m.planes))
 731                        return -EFAULT;
 732                uplane32 = compat_ptr(p);
 733
 734                while (num_planes--) {
 735                        ret = put_v4l2_plane32((void __user *)uplane,
 736                                               uplane32, memory);
 737                        if (ret)
 738                                return ret;
 739                        ++uplane;
 740                        ++uplane32;
 741                }
 742        } else {
 743                switch (memory) {
 744                case V4L2_MEMORY_MMAP:
 745                case V4L2_MEMORY_OVERLAY:
 746                        if (assign_in_user(&p32->m.offset, &p64->m.offset))
 747                                return -EFAULT;
 748                        break;
 749                case V4L2_MEMORY_USERPTR:
 750                        if (assign_in_user(&p32->m.userptr, &p64->m.userptr))
 751                                return -EFAULT;
 752                        break;
 753                case V4L2_MEMORY_DMABUF:
 754                        if (assign_in_user(&p32->m.fd, &p64->m.fd))
 755                                return -EFAULT;
 756                        break;
 757                }
 758        }
 759
 760        return 0;
 761}
 762
 763struct v4l2_framebuffer32 {
 764        __u32                   capability;
 765        __u32                   flags;
 766        compat_caddr_t          base;
 767        struct {
 768                __u32           width;
 769                __u32           height;
 770                __u32           pixelformat;
 771                __u32           field;
 772                __u32           bytesperline;
 773                __u32           sizeimage;
 774                __u32           colorspace;
 775                __u32           priv;
 776        } fmt;
 777};
 778
 779static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
 780                                  struct v4l2_framebuffer32 __user *p32)
 781{
 782        compat_caddr_t tmp;
 783
 784        if (!access_ok(p32, sizeof(*p32)) ||
 785            get_user(tmp, &p32->base) ||
 786            put_user_force(compat_ptr(tmp), &p64->base) ||
 787            assign_in_user(&p64->capability, &p32->capability) ||
 788            assign_in_user(&p64->flags, &p32->flags) ||
 789            copy_in_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
 790                return -EFAULT;
 791        return 0;
 792}
 793
 794static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64,
 795                                  struct v4l2_framebuffer32 __user *p32)
 796{
 797        void *base;
 798
 799        if (!access_ok(p32, sizeof(*p32)) ||
 800            get_user(base, &p64->base) ||
 801            put_user(ptr_to_compat((void __user *)base), &p32->base) ||
 802            assign_in_user(&p32->capability, &p64->capability) ||
 803            assign_in_user(&p32->flags, &p64->flags) ||
 804            copy_in_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
 805                return -EFAULT;
 806        return 0;
 807}
 808
 809struct v4l2_input32 {
 810        __u32        index;             /*  Which input */
 811        __u8         name[32];          /*  Label */
 812        __u32        type;              /*  Type of input */
 813        __u32        audioset;          /*  Associated audios (bitfield) */
 814        __u32        tuner;             /*  Associated tuner */
 815        compat_u64   std;
 816        __u32        status;
 817        __u32        capabilities;
 818        __u32        reserved[3];
 819};
 820
 821/*
 822 * The 64-bit v4l2_input struct has extra padding at the end of the struct.
 823 * Otherwise it is identical to the 32-bit version.
 824 */
 825static inline int get_v4l2_input32(struct v4l2_input __user *p64,
 826                                   struct v4l2_input32 __user *p32)
 827{
 828        if (copy_in_user(p64, p32, sizeof(*p32)))
 829                return -EFAULT;
 830        return 0;
 831}
 832
 833static inline int put_v4l2_input32(struct v4l2_input __user *p64,
 834                                   struct v4l2_input32 __user *p32)
 835{
 836        if (copy_in_user(p32, p64, sizeof(*p32)))
 837                return -EFAULT;
 838        return 0;
 839}
 840
 841struct v4l2_ext_controls32 {
 842        __u32 which;
 843        __u32 count;
 844        __u32 error_idx;
 845        __s32 request_fd;
 846        __u32 reserved[1];
 847        compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 848};
 849
 850struct v4l2_ext_control32 {
 851        __u32 id;
 852        __u32 size;
 853        __u32 reserved2[1];
 854        union {
 855                __s32 value;
 856                __s64 value64;
 857                compat_caddr_t string; /* actually char * */
 858        };
 859} __attribute__ ((packed));
 860
 861/* Return true if this control is a pointer type. */
 862static inline bool ctrl_is_pointer(struct file *file, u32 id)
 863{
 864        struct video_device *vdev = video_devdata(file);
 865        struct v4l2_fh *fh = NULL;
 866        struct v4l2_ctrl_handler *hdl = NULL;
 867        struct v4l2_query_ext_ctrl qec = { id };
 868        const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
 869
 870        if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
 871                fh = file->private_data;
 872
 873        if (fh && fh->ctrl_handler)
 874                hdl = fh->ctrl_handler;
 875        else if (vdev->ctrl_handler)
 876                hdl = vdev->ctrl_handler;
 877
 878        if (hdl) {
 879                struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
 880
 881                return ctrl && ctrl->is_ptr;
 882        }
 883
 884        if (!ops || !ops->vidioc_query_ext_ctrl)
 885                return false;
 886
 887        return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
 888                (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
 889}
 890
 891static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *p32,
 892                                     u32 *size)
 893{
 894        u32 count;
 895
 896        if (!access_ok(p32, sizeof(*p32)) ||
 897            get_user(count, &p32->count))
 898                return -EFAULT;
 899        if (count > V4L2_CID_MAX_CTRLS)
 900                return -EINVAL;
 901        *size = count * sizeof(struct v4l2_ext_control);
 902        return 0;
 903}
 904
 905static int get_v4l2_ext_controls32(struct file *file,
 906                                   struct v4l2_ext_controls __user *p64,
 907                                   struct v4l2_ext_controls32 __user *p32,
 908                                   void __user *aux_buf, u32 aux_space)
 909{
 910        struct v4l2_ext_control32 __user *ucontrols;
 911        struct v4l2_ext_control __user *kcontrols;
 912        u32 count;
 913        u32 n;
 914        compat_caddr_t p;
 915
 916        if (!access_ok(p32, sizeof(*p32)) ||
 917            assign_in_user(&p64->which, &p32->which) ||
 918            get_user(count, &p32->count) ||
 919            put_user(count, &p64->count) ||
 920            assign_in_user(&p64->error_idx, &p32->error_idx) ||
 921            assign_in_user(&p64->request_fd, &p32->request_fd) ||
 922            copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved)))
 923                return -EFAULT;
 924
 925        if (count == 0)
 926                return put_user(NULL, &p64->controls);
 927        if (count > V4L2_CID_MAX_CTRLS)
 928                return -EINVAL;
 929        if (get_user(p, &p32->controls))
 930                return -EFAULT;
 931        ucontrols = compat_ptr(p);
 932        if (!access_ok(ucontrols, count * sizeof(*ucontrols)))
 933                return -EFAULT;
 934        if (aux_space < count * sizeof(*kcontrols))
 935                return -EFAULT;
 936        kcontrols = aux_buf;
 937        if (put_user_force(kcontrols, &p64->controls))
 938                return -EFAULT;
 939
 940        for (n = 0; n < count; n++) {
 941                u32 id;
 942
 943                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
 944                        return -EFAULT;
 945
 946                if (get_user(id, &kcontrols->id))
 947                        return -EFAULT;
 948
 949                if (ctrl_is_pointer(file, id)) {
 950                        void __user *s;
 951
 952                        if (get_user(p, &ucontrols->string))
 953                                return -EFAULT;
 954                        s = compat_ptr(p);
 955                        if (put_user(s, &kcontrols->string))
 956                                return -EFAULT;
 957                }
 958                ucontrols++;
 959                kcontrols++;
 960        }
 961        return 0;
 962}
 963
 964static int put_v4l2_ext_controls32(struct file *file,
 965                                   struct v4l2_ext_controls __user *p64,
 966                                   struct v4l2_ext_controls32 __user *p32)
 967{
 968        struct v4l2_ext_control32 __user *ucontrols;
 969        struct v4l2_ext_control *kcontrols;
 970        u32 count;
 971        u32 n;
 972        compat_caddr_t p;
 973
 974        /*
 975         * We need to define kcontrols without __user, even though it does
 976         * point to data in userspace here. The reason is that v4l2-ioctl.c
 977         * copies it from userspace to kernelspace, so its definition in
 978         * videodev2.h doesn't have a __user markup. Defining kcontrols
 979         * with __user causes smatch warnings, so instead declare it
 980         * without __user and cast it as a userspace pointer where needed.
 981         */
 982        if (!access_ok(p32, sizeof(*p32)) ||
 983            assign_in_user(&p32->which, &p64->which) ||
 984            get_user(count, &p64->count) ||
 985            put_user(count, &p32->count) ||
 986            assign_in_user(&p32->error_idx, &p64->error_idx) ||
 987            assign_in_user(&p32->request_fd, &p64->request_fd) ||
 988            copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)) ||
 989            get_user(kcontrols, &p64->controls))
 990                return -EFAULT;
 991
 992        if (!count || count > (U32_MAX/sizeof(*ucontrols)))
 993                return 0;
 994        if (get_user(p, &p32->controls))
 995                return -EFAULT;
 996        ucontrols = compat_ptr(p);
 997        if (!access_ok(ucontrols, count * sizeof(*ucontrols)))
 998                return -EFAULT;
 999
1000        for (n = 0; n < count; n++) {
1001                unsigned int size = sizeof(*ucontrols);
1002                u32 id;
1003
1004                if (get_user_cast(id, &kcontrols->id) ||
1005                    put_user(id, &ucontrols->id) ||
1006                    assign_in_user_cast(&ucontrols->size, &kcontrols->size) ||
1007                    copy_in_user(&ucontrols->reserved2,
1008                                 (void __user *)&kcontrols->reserved2,
1009                                 sizeof(ucontrols->reserved2)))
1010                        return -EFAULT;
1011
1012                /*
1013                 * Do not modify the pointer when copying a pointer control.
1014                 * The contents of the pointer was changed, not the pointer
1015                 * itself.
1016                 */
1017                if (ctrl_is_pointer(file, id))
1018                        size -= sizeof(ucontrols->value64);
1019
1020                if (copy_in_user(ucontrols,
1021                                 (void __user *)kcontrols, size))
1022                        return -EFAULT;
1023
1024                ucontrols++;
1025                kcontrols++;
1026        }
1027        return 0;
1028}
1029
1030struct v4l2_event32 {
1031        __u32                           type;
1032        union {
1033                compat_s64              value64;
1034                __u8                    data[64];
1035        } u;
1036        __u32                           pending;
1037        __u32                           sequence;
1038        struct compat_timespec          timestamp;
1039        __u32                           id;
1040        __u32                           reserved[8];
1041};
1042
1043static int put_v4l2_event32(struct v4l2_event __user *p64,
1044                            struct v4l2_event32 __user *p32)
1045{
1046        if (!access_ok(p32, sizeof(*p32)) ||
1047            assign_in_user(&p32->type, &p64->type) ||
1048            copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) ||
1049            assign_in_user(&p32->pending, &p64->pending) ||
1050            assign_in_user(&p32->sequence, &p64->sequence) ||
1051            assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) ||
1052            assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) ||
1053            assign_in_user(&p32->id, &p64->id) ||
1054            copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
1055                return -EFAULT;
1056        return 0;
1057}
1058
1059struct v4l2_edid32 {
1060        __u32 pad;
1061        __u32 start_block;
1062        __u32 blocks;
1063        __u32 reserved[5];
1064        compat_caddr_t edid;
1065};
1066
1067static int get_v4l2_edid32(struct v4l2_edid __user *p64,
1068                           struct v4l2_edid32 __user *p32)
1069{
1070        compat_uptr_t tmp;
1071
1072        if (!access_ok(p32, sizeof(*p32)) ||
1073            assign_in_user(&p64->pad, &p32->pad) ||
1074            assign_in_user(&p64->start_block, &p32->start_block) ||
1075            assign_in_user_cast(&p64->blocks, &p32->blocks) ||
1076            get_user(tmp, &p32->edid) ||
1077            put_user_force(compat_ptr(tmp), &p64->edid) ||
1078            copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved)))
1079                return -EFAULT;
1080        return 0;
1081}
1082
1083static int put_v4l2_edid32(struct v4l2_edid __user *p64,
1084                           struct v4l2_edid32 __user *p32)
1085{
1086        void *edid;
1087
1088        if (!access_ok(p32, sizeof(*p32)) ||
1089            assign_in_user(&p32->pad, &p64->pad) ||
1090            assign_in_user(&p32->start_block, &p64->start_block) ||
1091            assign_in_user(&p32->blocks, &p64->blocks) ||
1092            get_user(edid, &p64->edid) ||
1093            put_user(ptr_to_compat((void __user *)edid), &p32->edid) ||
1094            copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
1095                return -EFAULT;
1096        return 0;
1097}
1098
1099/*
1100 * List of ioctls that require 32-bits/64-bits conversion
1101 *
1102 * The V4L2 ioctls that aren't listed there don't have pointer arguments
1103 * and the struct size is identical for both 32 and 64 bits versions, so
1104 * they don't need translations.
1105 */
1106
1107#define VIDIOC_G_FMT32          _IOWR('V',  4, struct v4l2_format32)
1108#define VIDIOC_S_FMT32          _IOWR('V',  5, struct v4l2_format32)
1109#define VIDIOC_QUERYBUF32       _IOWR('V',  9, struct v4l2_buffer32)
1110#define VIDIOC_G_FBUF32         _IOR ('V', 10, struct v4l2_framebuffer32)
1111#define VIDIOC_S_FBUF32         _IOW ('V', 11, struct v4l2_framebuffer32)
1112#define VIDIOC_QBUF32           _IOWR('V', 15, struct v4l2_buffer32)
1113#define VIDIOC_DQBUF32          _IOWR('V', 17, struct v4l2_buffer32)
1114#define VIDIOC_ENUMSTD32        _IOWR('V', 25, struct v4l2_standard32)
1115#define VIDIOC_ENUMINPUT32      _IOWR('V', 26, struct v4l2_input32)
1116#define VIDIOC_G_EDID32         _IOWR('V', 40, struct v4l2_edid32)
1117#define VIDIOC_S_EDID32         _IOWR('V', 41, struct v4l2_edid32)
1118#define VIDIOC_TRY_FMT32        _IOWR('V', 64, struct v4l2_format32)
1119#define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
1120#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
1121#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
1122#define VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
1123#define VIDIOC_CREATE_BUFS32    _IOWR('V', 92, struct v4l2_create_buffers32)
1124#define VIDIOC_PREPARE_BUF32    _IOWR('V', 93, struct v4l2_buffer32)
1125
1126#define VIDIOC_OVERLAY32        _IOW ('V', 14, s32)
1127#define VIDIOC_STREAMON32       _IOW ('V', 18, s32)
1128#define VIDIOC_STREAMOFF32      _IOW ('V', 19, s32)
1129#define VIDIOC_G_INPUT32        _IOR ('V', 38, s32)
1130#define VIDIOC_S_INPUT32        _IOWR('V', 39, s32)
1131#define VIDIOC_G_OUTPUT32       _IOR ('V', 46, s32)
1132#define VIDIOC_S_OUTPUT32       _IOWR('V', 47, s32)
1133
1134/**
1135 * alloc_userspace() - Allocates a 64-bits userspace pointer compatible
1136 *      for calling the native 64-bits version of an ioctl.
1137 *
1138 * @size:       size of the structure itself to be allocated.
1139 * @aux_space:  extra size needed to store "extra" data, e.g. space for
1140 *              other __user data that is pointed to fields inside the
1141 *              structure.
1142 * @new_p64:    pointer to a pointer to be filled with the allocated struct.
1143 *
1144 * Return:
1145 *
1146 * if it can't allocate memory, either -ENOMEM or -EFAULT will be returned.
1147 * Zero otherwise.
1148 */
1149static int alloc_userspace(unsigned int size, u32 aux_space,
1150                           void __user **new_p64)
1151{
1152        *new_p64 = compat_alloc_user_space(size + aux_space);
1153        if (!*new_p64)
1154                return -ENOMEM;
1155        if (clear_user(*new_p64, size))
1156                return -EFAULT;
1157        return 0;
1158}
1159
1160/**
1161 * do_video_ioctl() - Ancillary function with handles a compat32 ioctl call
1162 *
1163 * @file: pointer to &struct file with the file handler
1164 * @cmd: ioctl to be called
1165 * @arg: arguments passed from/to the ioctl handler
1166 *
1167 * This function is called when a 32 bits application calls a V4L2 ioctl
1168 * and the Kernel is compiled with 64 bits.
1169 *
1170 * This function is called by v4l2_compat_ioctl32() when the function is
1171 * not private to some specific driver.
1172 *
1173 * It converts a 32-bits struct into a 64 bits one, calls the native 64-bits
1174 * ioctl handler and fills back the 32-bits struct with the results of the
1175 * native call.
1176 */
1177static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1178{
1179        void __user *p32 = compat_ptr(arg);
1180        void __user *new_p64 = NULL;
1181        void __user *aux_buf;
1182        u32 aux_space;
1183        int compatible_arg = 1;
1184        long err = 0;
1185
1186        /*
1187         * 1. When struct size is different, converts the command.
1188         */
1189        switch (cmd) {
1190        case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
1191        case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
1192        case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
1193        case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
1194        case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
1195        case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
1196        case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
1197        case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
1198        case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
1199        case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
1200        case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
1201        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
1202        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
1203        case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
1204        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
1205        case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
1206        case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
1207        case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
1208        case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
1209        case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
1210        case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
1211        case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
1212        case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
1213        case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break;
1214        case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break;
1215        }
1216
1217        /*
1218         * 2. Allocates a 64-bits userspace pointer to store the
1219         * values of the ioctl and copy data from the 32-bits __user
1220         * argument into it.
1221         */
1222        switch (cmd) {
1223        case VIDIOC_OVERLAY:
1224        case VIDIOC_STREAMON:
1225        case VIDIOC_STREAMOFF:
1226        case VIDIOC_S_INPUT:
1227        case VIDIOC_S_OUTPUT:
1228                err = alloc_userspace(sizeof(unsigned int), 0, &new_p64);
1229                if (!err && assign_in_user((unsigned int __user *)new_p64,
1230                                           (compat_uint_t __user *)p32))
1231                        err = -EFAULT;
1232                compatible_arg = 0;
1233                break;
1234
1235        case VIDIOC_G_INPUT:
1236        case VIDIOC_G_OUTPUT:
1237                err = alloc_userspace(sizeof(unsigned int), 0, &new_p64);
1238                compatible_arg = 0;
1239                break;
1240
1241        case VIDIOC_G_EDID:
1242        case VIDIOC_S_EDID:
1243                err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64);
1244                if (!err)
1245                        err = get_v4l2_edid32(new_p64, p32);
1246                compatible_arg = 0;
1247                break;
1248
1249        case VIDIOC_G_FMT:
1250        case VIDIOC_S_FMT:
1251        case VIDIOC_TRY_FMT:
1252                err = bufsize_v4l2_format(p32, &aux_space);
1253                if (!err)
1254                        err = alloc_userspace(sizeof(struct v4l2_format),
1255                                              aux_space, &new_p64);
1256                if (!err) {
1257                        aux_buf = new_p64 + sizeof(struct v4l2_format);
1258                        err = get_v4l2_format32(new_p64, p32,
1259                                                aux_buf, aux_space);
1260                }
1261                compatible_arg = 0;
1262                break;
1263
1264        case VIDIOC_CREATE_BUFS:
1265                err = bufsize_v4l2_create(p32, &aux_space);
1266                if (!err)
1267                        err = alloc_userspace(sizeof(struct v4l2_create_buffers),
1268                                              aux_space, &new_p64);
1269                if (!err) {
1270                        aux_buf = new_p64 + sizeof(struct v4l2_create_buffers);
1271                        err = get_v4l2_create32(new_p64, p32,
1272                                                aux_buf, aux_space);
1273                }
1274                compatible_arg = 0;
1275                break;
1276
1277        case VIDIOC_PREPARE_BUF:
1278        case VIDIOC_QUERYBUF:
1279        case VIDIOC_QBUF:
1280        case VIDIOC_DQBUF:
1281                err = bufsize_v4l2_buffer(p32, &aux_space);
1282                if (!err)
1283                        err = alloc_userspace(sizeof(struct v4l2_buffer),
1284                                              aux_space, &new_p64);
1285                if (!err) {
1286                        aux_buf = new_p64 + sizeof(struct v4l2_buffer);
1287                        err = get_v4l2_buffer32(new_p64, p32,
1288                                                aux_buf, aux_space);
1289                }
1290                compatible_arg = 0;
1291                break;
1292
1293        case VIDIOC_S_FBUF:
1294                err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1295                                      &new_p64);
1296                if (!err)
1297                        err = get_v4l2_framebuffer32(new_p64, p32);
1298                compatible_arg = 0;
1299                break;
1300
1301        case VIDIOC_G_FBUF:
1302                err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1303                                      &new_p64);
1304                compatible_arg = 0;
1305                break;
1306
1307        case VIDIOC_ENUMSTD:
1308                err = alloc_userspace(sizeof(struct v4l2_standard), 0,
1309                                      &new_p64);
1310                if (!err)
1311                        err = get_v4l2_standard32(new_p64, p32);
1312                compatible_arg = 0;
1313                break;
1314
1315        case VIDIOC_ENUMINPUT:
1316                err = alloc_userspace(sizeof(struct v4l2_input), 0, &new_p64);
1317                if (!err)
1318                        err = get_v4l2_input32(new_p64, p32);
1319                compatible_arg = 0;
1320                break;
1321
1322        case VIDIOC_G_EXT_CTRLS:
1323        case VIDIOC_S_EXT_CTRLS:
1324        case VIDIOC_TRY_EXT_CTRLS:
1325                err = bufsize_v4l2_ext_controls(p32, &aux_space);
1326                if (!err)
1327                        err = alloc_userspace(sizeof(struct v4l2_ext_controls),
1328                                              aux_space, &new_p64);
1329                if (!err) {
1330                        aux_buf = new_p64 + sizeof(struct v4l2_ext_controls);
1331                        err = get_v4l2_ext_controls32(file, new_p64, p32,
1332                                                      aux_buf, aux_space);
1333                }
1334                compatible_arg = 0;
1335                break;
1336        case VIDIOC_DQEVENT:
1337                err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64);
1338                compatible_arg = 0;
1339                break;
1340        }
1341        if (err)
1342                return err;
1343
1344        /*
1345         * 3. Calls the native 64-bits ioctl handler.
1346         *
1347         * For the functions where a conversion was not needed,
1348         * compatible_arg is true, and it will call it with the arguments
1349         * provided by userspace and stored at @p32 var.
1350         *
1351         * Otherwise, it will pass the newly allocated @new_p64 argument.
1352         */
1353        if (compatible_arg)
1354                err = native_ioctl(file, cmd, (unsigned long)p32);
1355        else
1356                err = native_ioctl(file, cmd, (unsigned long)new_p64);
1357
1358        if (err == -ENOTTY)
1359                return err;
1360
1361        /*
1362         * 4. Special case: even after an error we need to put the
1363         * results back for some ioctls.
1364         *
1365         * In the case of EXT_CTRLS, the error_idx will contain information
1366         * on which control failed.
1367         *
1368         * In the case of S_EDID, the driver can return E2BIG and set
1369         * the blocks to maximum allowed value.
1370         */
1371        switch (cmd) {
1372        case VIDIOC_G_EXT_CTRLS:
1373        case VIDIOC_S_EXT_CTRLS:
1374        case VIDIOC_TRY_EXT_CTRLS:
1375                if (put_v4l2_ext_controls32(file, new_p64, p32))
1376                        err = -EFAULT;
1377                break;
1378        case VIDIOC_S_EDID:
1379                if (put_v4l2_edid32(new_p64, p32))
1380                        err = -EFAULT;
1381                break;
1382        }
1383        if (err)
1384                return err;
1385
1386        /*
1387         * 5. Copy the data returned at the 64 bits userspace pointer to
1388         * the original 32 bits structure.
1389         */
1390        switch (cmd) {
1391        case VIDIOC_S_INPUT:
1392        case VIDIOC_S_OUTPUT:
1393        case VIDIOC_G_INPUT:
1394        case VIDIOC_G_OUTPUT:
1395                if (assign_in_user((compat_uint_t __user *)p32,
1396                                   ((unsigned int __user *)new_p64)))
1397                        err = -EFAULT;
1398                break;
1399
1400        case VIDIOC_G_FBUF:
1401                err = put_v4l2_framebuffer32(new_p64, p32);
1402                break;
1403
1404        case VIDIOC_DQEVENT:
1405                err = put_v4l2_event32(new_p64, p32);
1406                break;
1407
1408        case VIDIOC_G_EDID:
1409                err = put_v4l2_edid32(new_p64, p32);
1410                break;
1411
1412        case VIDIOC_G_FMT:
1413        case VIDIOC_S_FMT:
1414        case VIDIOC_TRY_FMT:
1415                err = put_v4l2_format32(new_p64, p32);
1416                break;
1417
1418        case VIDIOC_CREATE_BUFS:
1419                err = put_v4l2_create32(new_p64, p32);
1420                break;
1421
1422        case VIDIOC_PREPARE_BUF:
1423        case VIDIOC_QUERYBUF:
1424        case VIDIOC_QBUF:
1425        case VIDIOC_DQBUF:
1426                err = put_v4l2_buffer32(new_p64, p32);
1427                break;
1428
1429        case VIDIOC_ENUMSTD:
1430                err = put_v4l2_standard32(new_p64, p32);
1431                break;
1432
1433        case VIDIOC_ENUMINPUT:
1434                err = put_v4l2_input32(new_p64, p32);
1435                break;
1436        }
1437        return err;
1438}
1439
1440/**
1441 * v4l2_compat_ioctl32() - Handles a compat32 ioctl call
1442 *
1443 * @file: pointer to &struct file with the file handler
1444 * @cmd: ioctl to be called
1445 * @arg: arguments passed from/to the ioctl handler
1446 *
1447 * This function is meant to be used as .compat_ioctl fops at v4l2-dev.c
1448 * in order to deal with 32-bit calls on a 64-bits Kernel.
1449 *
1450 * This function calls do_video_ioctl() for non-private V4L2 ioctls.
1451 * If the function is a private one it calls vdev->fops->compat_ioctl32
1452 * instead.
1453 */
1454long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1455{
1456        struct video_device *vdev = video_devdata(file);
1457        long ret = -ENOIOCTLCMD;
1458
1459        if (!file->f_op->unlocked_ioctl)
1460                return ret;
1461
1462        if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1463                ret = do_video_ioctl(file, cmd, arg);
1464        else if (vdev->fops->compat_ioctl32)
1465                ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1466
1467        if (ret == -ENOIOCTLCMD)
1468                pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1469                         _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1470        return ret;
1471}
1472EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
1473