long compat_sys_semctl(int first, int second, int third, void __user *uptr) { union semun fourth; u32 pad; int err, err2; struct semid64_ds s64; struct semid64_ds __user *up64; int version = compat_ipc_parse_version(&third); if (!uptr) return -EINVAL; if (get_user(pad, (u32 __user *) uptr)) return -EFAULT; if ((third & (~IPC_64)) == SETVAL) fourth.val = (int) pad; else fourth.__pad = compat_ptr(pad); switch (third & (~IPC_64)) { case IPC_INFO: case IPC_RMID: case SEM_INFO: case GETVAL: case GETPID: case GETNCNT: case GETZCNT: case GETALL: case SETVAL: case SETALL: err = sys_semctl(first, second, third, fourth); break; case IPC_STAT: case SEM_STAT: up64 = compat_alloc_user_space(sizeof(s64)); fourth.__pad = up64; err = sys_semctl(first, second, third, fourth); if (err < 0) break; if (copy_from_user(&s64, up64, sizeof(s64))) err2 = -EFAULT; else if (version == IPC_64) err2 = put_compat_semid64_ds(&s64, compat_ptr(pad)); else err2 = put_compat_semid_ds(&s64, compat_ptr(pad)); if (err2) err = -EFAULT; break; case IPC_SET: if (version == IPC_64) { err = get_compat_semid64_ds(&s64, compat_ptr(pad)); } else { err = get_compat_semid_ds(&s64, compat_ptr(pad)); } up64 = compat_alloc_user_space(sizeof(s64)); if (copy_to_user(up64, &s64, sizeof(s64))) err = -EFAULT; if (err) break; fourth.__pad = up64; err = sys_semctl(first, second, third, fourth); break; default: err = -EINVAL; break; } return err; }
int compat_mc_getsockopt(struct sock *sock, int level, int optname, char __user *optval, int __user *optlen, int (*getsockopt)(struct sock *, int, int, char __user *, int __user *)) { struct compat_group_filter __user *gf32 = (void *)optval; struct group_filter __user *kgf; int __user *koptlen; u32 interface, fmode, numsrc; int klen, ulen, err; if (optname != MCAST_MSFILTER) return getsockopt(sock, level, optname, optval, optlen); koptlen = compat_alloc_user_space(sizeof(*koptlen)); if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) || __get_user(ulen, optlen)) return -EFAULT; /* adjust len for pad */ klen = ulen + sizeof(*kgf) - sizeof(*gf32); if (klen < GROUP_FILTER_SIZE(0)) return -EINVAL; if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) || __put_user(klen, koptlen)) return -EFAULT; /* have to allow space for previous compat_alloc_user_space, too */ kgf = compat_alloc_user_space(klen+sizeof(*optlen)); if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || __get_user(interface, &gf32->gf_interface) || __get_user(fmode, &gf32->gf_fmode) || __get_user(numsrc, &gf32->gf_numsrc) || __put_user(interface, &kgf->gf_interface) || __put_user(fmode, &kgf->gf_fmode) || __put_user(numsrc, &kgf->gf_numsrc) || copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group))) return -EFAULT; err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen); if (err) return err; if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) || __get_user(klen, koptlen)) return -EFAULT; ulen = klen - (sizeof(*kgf)-sizeof(*gf32)); if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) || __put_user(ulen, optlen)) return -EFAULT; if (!access_ok(VERIFY_READ, kgf, klen) || !access_ok(VERIFY_WRITE, gf32, ulen) || __get_user(interface, &kgf->gf_interface) || __get_user(fmode, &kgf->gf_fmode) || __get_user(numsrc, &kgf->gf_numsrc) || __put_user(interface, &gf32->gf_interface) || __put_user(fmode, &gf32->gf_fmode) || __put_user(numsrc, &gf32->gf_numsrc)) return -EFAULT; if (numsrc) { int copylen; klen -= GROUP_FILTER_SIZE(0); copylen = numsrc * sizeof(gf32->gf_slist[0]); if (copylen > klen) copylen = klen; if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen)) return -EFAULT; } return err; }
int compat_mc_setsockopt(struct sock *sock, int level, int optname, char __user *optval, unsigned int optlen, int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int)) { char __user *koptval = optval; int koptlen = optlen; switch (optname) { case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: { struct compat_group_req __user *gr32 = (void *)optval; struct group_req __user *kgr = compat_alloc_user_space(sizeof(struct group_req)); u32 interface; if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) || !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) || __get_user(interface, &gr32->gr_interface) || __put_user(interface, &kgr->gr_interface) || copy_in_user(&kgr->gr_group, &gr32->gr_group, sizeof(kgr->gr_group))) return -EFAULT; koptval = (char __user *)kgr; koptlen = sizeof(struct group_req); break; } case MCAST_JOIN_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP: case MCAST_BLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE: { struct compat_group_source_req __user *gsr32 = (void *)optval; struct group_source_req __user *kgsr = compat_alloc_user_space( sizeof(struct group_source_req)); u32 interface; if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) || !access_ok(VERIFY_WRITE, kgsr, sizeof(struct group_source_req)) || __get_user(interface, &gsr32->gsr_interface) || __put_user(interface, &kgsr->gsr_interface) || copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group, sizeof(kgsr->gsr_group)) || copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source, sizeof(kgsr->gsr_source))) return -EFAULT; koptval = (char __user *)kgsr; koptlen = sizeof(struct group_source_req); break; } case MCAST_MSFILTER: { struct compat_group_filter __user *gf32 = (void *)optval; struct group_filter __user *kgf; u32 interface, fmode, numsrc; if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || __get_user(interface, &gf32->gf_interface) || __get_user(fmode, &gf32->gf_fmode) || __get_user(numsrc, &gf32->gf_numsrc)) return -EFAULT; koptlen = optlen + sizeof(struct group_filter) - sizeof(struct compat_group_filter); if (koptlen < GROUP_FILTER_SIZE(numsrc)) return -EINVAL; kgf = compat_alloc_user_space(koptlen); if (!access_ok(VERIFY_WRITE, kgf, koptlen) || __put_user(interface, &kgf->gf_interface) || __put_user(fmode, &kgf->gf_fmode) || __put_user(numsrc, &kgf->gf_numsrc) || copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)) || (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist, numsrc * sizeof(kgf->gf_slist[0])))) return -EFAULT; koptval = (char __user *)kgf; break; } default: break; } return setsockopt(sock, level, optname, koptval, koptlen); }
long compat_sys_shmctl(int first, int second, void __user *uptr) { void __user *p; struct shmid64_ds s64; struct shminfo64 smi; int err, err2; int version = compat_ipc_parse_version(&second); switch (second & (~IPC_64)) { case IPC_RMID: case SHM_LOCK: case SHM_UNLOCK: err = sys_shmctl(first, second, uptr); break; case IPC_INFO: p = compat_alloc_user_space(sizeof(smi)); err = sys_shmctl(first, second, p); if (err < 0) break; if (copy_from_user(&smi, p, sizeof(smi))) err2 = -EFAULT; else if (version == IPC_64) err2 = put_compat_shminfo64(&smi, uptr); else err2 = put_compat_shminfo(&smi, uptr); if (err2) err = -EFAULT; break; case IPC_SET: if (version == IPC_64) { err = get_compat_shmid64_ds(&s64, uptr); } else { err = get_compat_shmid_ds(&s64, uptr); } if (err) break; p = compat_alloc_user_space(sizeof(s64)); if (copy_to_user(p, &s64, sizeof(s64))) err = -EFAULT; else err = sys_shmctl(first, second, p); break; case IPC_STAT: case SHM_STAT: p = compat_alloc_user_space(sizeof(s64)); err = sys_shmctl(first, second, p); if (err < 0) break; if (copy_from_user(&s64, p, sizeof(s64))) err2 = -EFAULT; else if (version == IPC_64) err2 = put_compat_shmid64_ds(&s64, uptr); else err2 = put_compat_shmid_ds(&s64, uptr); if (err2) err = -EFAULT; break; case SHM_INFO: p = compat_alloc_user_space(sizeof(struct shm_info)); err = sys_shmctl(first, second, p); if (err < 0) break; err2 = put_compat_shm_info(p, uptr); if (err2) err = -EFAULT; break; default: err = -EINVAL; break; } return err; }
static long compat_fimg2d_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case COMPAT_FIMG2D_BITBLT_BLIT: { struct compat_fimg2d_blit __user *data32; struct fimg2d_blit __user *data; struct mm_struct *mm; enum blit_op op; enum blit_sync sync; enum fimg2d_qos_level qos_lv; compat_uint_t seq_no; unsigned long stack_cursor = 0; int err; mm = get_task_mm(current); if (!mm) { fimg2d_err("no mm for ctx\n"); return -ENXIO; } data32 = compat_ptr(arg); data = compat_alloc_user_space(sizeof(*data)); if (!data) { fimg2d_err("failed to allocate user compat space\n"); mmput(mm); return -ENOMEM; } stack_cursor += sizeof(*data); if (clear_user(data, sizeof(*data))) { fimg2d_err("failed to access to userspace\n"); mmput(mm); return -EPERM; } err = get_user(op, &data32->op); err |= put_user(op, &data->op); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } err = compat_get_fimg2d_param(&data->param, &data32->param); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } if (data32->src) { data->src = compat_alloc_user_space(sizeof(*data->src) + stack_cursor); if (!data->src) { fimg2d_err("failed to allocate user compat space\n"); mmput(mm); return -ENOMEM; } stack_cursor += sizeof(*data->src); err = compat_get_fimg2d_image(data->src, data32->src); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } } if (data32->msk) { data->msk = compat_alloc_user_space(sizeof(*data->msk) + stack_cursor); if (!data->msk) { fimg2d_err("failed to allocate user compat space\n"); mmput(mm); return -ENOMEM; } stack_cursor += sizeof(*data->msk); err = compat_get_fimg2d_image(data->msk, data32->msk); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } } if (data32->tmp) { data->tmp = compat_alloc_user_space(sizeof(*data->tmp) + stack_cursor); if (!data->tmp) { fimg2d_err("failed to allocate user compat space\n"); mmput(mm); return -ENOMEM; } stack_cursor += sizeof(*data->tmp); err = compat_get_fimg2d_image(data->tmp, data32->tmp); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } } if (data32->dst) { data->dst = compat_alloc_user_space(sizeof(*data->dst) + stack_cursor); if (!data->dst) { fimg2d_err("failed to allocate user compat space\n"); mmput(mm); return -ENOMEM; } stack_cursor += sizeof(*data->dst); err = compat_get_fimg2d_image(data->dst, data32->dst); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } } err = get_user(sync, &data32->sync); err |= put_user(sync, &data->sync); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } err = get_user(seq_no, &data32->seq_no); err |= put_user(seq_no, &data->seq_no); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } err = get_user(qos_lv, &data32->qos_lv); err |= put_user(qos_lv, &data->qos_lv); if (err) { fimg2d_err("failed to get compat data\n"); mmput(mm); return err; } err = file->f_op->unlocked_ioctl(file, FIMG2D_BITBLT_BLIT, (unsigned long)data); mmput(mm); return err; } case COMPAT_FIMG2D_BITBLT_VERSION: { struct compat_fimg2d_version __user *data32; struct fimg2d_version __user *data; compat_uint_t i; int err; data32 = compat_ptr(arg); data = compat_alloc_user_space(sizeof(*data)); if (!data) { fimg2d_err("failed to allocate user compat space\n"); return -ENOMEM; } err = get_user(i, &data32->hw); err |= put_user(i, &data->hw); err |= get_user(i, &data32->sw); err |= put_user(i, &data->sw); if (err) return err; return file->f_op->unlocked_ioctl(file, FIMG2D_BITBLT_VERSION, (unsigned long)data); } case FIMG2D_BITBLT_ACTIVATE: { return file->f_op->unlocked_ioctl(file, FIMG2D_BITBLT_ACTIVATE, arg); } default: fimg2d_err("unknown ioctl\n"); return -EINVAL; } }
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) { struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; int num_planes; int ret; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || get_user(kp->memory, &up->memory) || get_user(kp->input, &up->input)) return -EFAULT; if (V4L2_TYPE_IS_OUTPUT(kp->type)) if (get_user(kp->bytesused, &up->bytesused) || get_user(kp->field, &up->field) || get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || get_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec)) return -EFAULT; if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { if (get_user(kp->length, &up->length)) return -EFAULT; num_planes = kp->length; if (num_planes == 0) { kp->m.planes = NULL; /* num_planes == 0 is legal, e.g. when userspace doesn't * need planes array on DQBUF*/ return 0; } if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, num_planes * sizeof(struct v4l2_plane32))) return -EFAULT; /* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * sizeof(struct v4l2_plane)); kp->m.planes = uplane; while (--num_planes >= 0) { ret = get_v4l2_plane32(uplane, uplane32, kp->memory); if (ret) return ret; ++uplane; ++uplane32; } } else { switch (kp->memory) { case V4L2_MEMORY_MMAP: if (get_user(kp->length, &up->length) || get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; case V4L2_MEMORY_USERPTR: { compat_long_t tmp; if (get_user(kp->length, &up->length) || get_user(tmp, &up->m.userptr)) return -EFAULT; kp->m.userptr = (unsigned long)compat_ptr(tmp); } break; case V4L2_MEMORY_OVERLAY: if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; } } return 0; }