diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 11:54:55 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 11:54:55 -0800 |
commit | 93f30c73ecd0281cf3685ef0e4e384980a176176 (patch) | |
tree | bd272334a0dbd258c08b5b2237e8bf5e17ce7255 | |
parent | 06ede5f6086757f746b7be860ae76137f4e95032 (diff) | |
parent | 96271654f55c74ff7325fbdfc535466c9deb0ce6 (diff) | |
download | lwn-93f30c73ecd0281cf3685ef0e4e384980a176176.tar.gz lwn-93f30c73ecd0281cf3685ef0e4e384980a176176.zip |
Merge branch 'misc.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull compat and uaccess updates from Al Viro:
- {get,put}_compat_sigset() series
- assorted compat ioctl stuff
- more set_fs() elimination
- a few more timespec64 conversions
- several removals of pointless access_ok() in places where it was
followed only by non-__ variants of primitives
* 'misc.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (24 commits)
coredump: call do_unlinkat directly instead of sys_unlink
fs: expose do_unlinkat for built-in callers
ext4: take handling of EXT4_IOC_GROUP_ADD into a helper, get rid of set_fs()
ipmi: get rid of pointless access_ok()
pi433: sanitize ioctl
cxlflash: get rid of pointless access_ok()
mtdchar: get rid of pointless access_ok()
r128: switch compat ioctls to drm_ioctl_kernel()
selection: get rid of field-by-field copyin
VT_RESIZEX: get rid of field-by-field copyin
i2c compat ioctls: move to ->compat_ioctl()
sched_rr_get_interval(): move compat to native, get rid of set_fs()
mips: switch to {get,put}_compat_sigset()
sparc: switch to {get,put}_compat_sigset()
s390: switch to {get,put}_compat_sigset()
ppc: switch to {get,put}_compat_sigset()
parisc: switch to {get,put}_compat_sigset()
get_compat_sigset()
get rid of {get,put}_compat_itimerspec()
io_getevents: Use timespec64 to represent timeouts
...
32 files changed, 508 insertions, 821 deletions
diff --git a/arch/mips/include/asm/compat-signal.h b/arch/mips/include/asm/compat-signal.h index e87cd243b0f4..c3b7a2550d1d 100644 --- a/arch/mips/include/asm/compat-signal.h +++ b/arch/mips/include/asm/compat-signal.h @@ -14,45 +14,16 @@ static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d, const sigset_t *s) { - int err; + BUILD_BUG_ON(sizeof(*d) != sizeof(*s)); + BUILD_BUG_ON(_NSIG_WORDS != 2); - BUG_ON(sizeof(*d) != sizeof(*s)); - BUG_ON(_NSIG_WORDS != 2); - - err = __put_user(s->sig[0], &d->sig[0]); - err |= __put_user(s->sig[0] >> 32, &d->sig[1]); - err |= __put_user(s->sig[1], &d->sig[2]); - err |= __put_user(s->sig[1] >> 32, &d->sig[3]); - - return err; + return put_compat_sigset(d, s, sizeof(*d)); } static inline int __copy_conv_sigset_from_user(sigset_t *d, const compat_sigset_t __user *s) { - int err; - union sigset_u { - sigset_t s; - compat_sigset_t c; - } *u = (union sigset_u *) d; - - BUG_ON(sizeof(*d) != sizeof(*s)); - BUG_ON(_NSIG_WORDS != 2); - -#ifdef CONFIG_CPU_BIG_ENDIAN - err = __get_user(u->c.sig[1], &s->sig[0]); - err |= __get_user(u->c.sig[0], &s->sig[1]); - err |= __get_user(u->c.sig[3], &s->sig[2]); - err |= __get_user(u->c.sig[2], &s->sig[3]); -#endif -#ifdef CONFIG_CPU_LITTLE_ENDIAN - err = __get_user(u->c.sig[0], &s->sig[0]); - err |= __get_user(u->c.sig[1], &s->sig[1]); - err |= __get_user(u->c.sig[2], &s->sig[2]); - err |= __get_user(u->c.sig[3], &s->sig[3]); -#endif - - return err; + return get_compat_sigset(d, s); } #endif /* __ASM_COMPAT_SIGNAL_H */ diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index f2a4038e275b..342073f44d3f 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -93,7 +93,6 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; #ifdef CONFIG_64BIT - compat_sigset_t compat_set; struct compat_rt_sigframe __user * compat_frame; if (is_compat_task()) @@ -114,9 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) if (is_compat_task()) { DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); - if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set))) + if (get_compat_sigset(&set, &compat_frame->uc.uc_sigmask)) goto give_sigsegv; - sigset_32to64(&set,&compat_set); } else #endif { @@ -238,7 +236,6 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs, int err = 0; #ifdef CONFIG_64BIT struct compat_rt_sigframe __user * compat_frame; - compat_sigset_t compat_set; #endif usp = (regs->gr[30] & ~(0x01UL)); @@ -261,8 +258,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs, DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, &compat_frame->regs, regs, in_syscall); - sigset_64to32(&compat_set,set); - err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set)); + err |= put_compat_sigset(&compat_frame->uc.uc_sigmask, set, + sizeof(compat_sigset_t)); } else #endif { diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 9e0cb6a577d6..41afa9cd1f55 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -46,19 +46,6 @@ #define DBG(LEVEL, ...) #endif -inline void -sigset_32to64(sigset_t *s64, compat_sigset_t *s32) -{ - s64->sig[0] = s32->sig[0] | ((unsigned long)s32->sig[1] << 32); -} - -inline void -sigset_64to32(compat_sigset_t *s32, sigset_t *s64) -{ - s32->sig[0] = s64->sig[0] & 0xffffffffUL; - s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL; -} - long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, struct pt_regs *regs) diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index af51d4ccee42..719e7417732c 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -79,8 +79,6 @@ struct compat_rt_sigframe { #define FUNCTIONCALLFRAME32 48 #define PARISC_RT_SIGFRAME_SIZE32 (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32) -void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); -void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user *rf, struct pt_regs *regs); diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 16d16583cf11..9ffd73296f64 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -94,40 +94,13 @@ */ static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) { - compat_sigset_t cset; - - switch (_NSIG_WORDS) { - case 4: cset.sig[6] = set->sig[3] & 0xffffffffull; - cset.sig[7] = set->sig[3] >> 32; - case 3: cset.sig[4] = set->sig[2] & 0xffffffffull; - cset.sig[5] = set->sig[2] >> 32; - case 2: cset.sig[2] = set->sig[1] & 0xffffffffull; - cset.sig[3] = set->sig[1] >> 32; - case 1: cset.sig[0] = set->sig[0] & 0xffffffffull; - cset.sig[1] = set->sig[0] >> 32; - } - return copy_to_user(uset, &cset, sizeof(*uset)); + return put_compat_sigset(uset, set, sizeof(*uset)); } static inline int get_sigset_t(sigset_t *set, const compat_sigset_t __user *uset) { - compat_sigset_t s32; - - if (copy_from_user(&s32, uset, sizeof(*uset))) - return -EFAULT; - - /* - * Swap the 2 words of the 64-bit sigset_t (they are stored - * in the "wrong" endian in 32-bit user storage). - */ - switch (_NSIG_WORDS) { - case 4: set->sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: set->sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: set->sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - return 0; + return get_compat_sigset(set, uset); } #define to_user_ptr(p) ptr_to_compat(p) diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index a4a1208e3df3..ef246940b44c 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -50,19 +50,6 @@ typedef struct struct ucontext32 uc; } rt_sigframe32; -static inline void sigset_to_sigset32(unsigned long *set64, - compat_sigset_word *set32) -{ - set32[0] = (compat_sigset_word) set64[0]; - set32[1] = (compat_sigset_word)(set64[0] >> 32); -} - -static inline void sigset32_to_sigset(compat_sigset_word *set32, - unsigned long *set64) -{ - set64[0] = (unsigned long) set32[0] | ((unsigned long) set32[1] << 32); -} - int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) { int err; @@ -294,12 +281,10 @@ COMPAT_SYSCALL_DEFINE0(sigreturn) { struct pt_regs *regs = task_pt_regs(current); sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; - compat_sigset_t cset; sigset_t set; - if (__copy_from_user(&cset.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) + if (get_compat_sigset(&set, (compat_sigset_t __user *)frame->sc.oldmask)) goto badframe; - sigset32_to_sigset(cset.sig, set.sig); set_current_blocked(&set); save_fpu_regs(); if (restore_sigregs32(regs, &frame->sregs)) @@ -317,12 +302,10 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn) { struct pt_regs *regs = task_pt_regs(current); rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; - compat_sigset_t cset; sigset_t set; - if (__copy_from_user(&cset, &frame->uc.uc_sigmask, sizeof(cset))) + if (get_compat_sigset(&set, &frame->uc.uc_sigmask)) goto badframe; - sigset32_to_sigset(cset.sig, set.sig); set_current_blocked(&set); if (compat_restore_altstack(&frame->uc.uc_stack)) goto badframe; @@ -372,7 +355,6 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, { int sig = ksig->sig; sigframe32 __user *frame; - struct sigcontext32 sc; unsigned long restorer; size_t frame_size; @@ -394,9 +376,10 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, return -EFAULT; /* Create struct sigcontext32 on the signal stack */ - sigset_to_sigset32(set->sig, sc.oldmask); - sc.sregs = (__u32)(unsigned long __force) &frame->sregs; - if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) + if (put_compat_sigset((compat_sigset_t __user *)frame->sc.oldmask, + set, sizeof(compat_sigset_t))) + return -EFAULT; + if (__put_user(ptr_to_compat(&frame->sc), &frame->sc.sregs)) return -EFAULT; /* Store registers needed to create the signal frame */ @@ -455,7 +438,6 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - compat_sigset_t cset; rt_sigframe32 __user *frame; unsigned long restorer; size_t frame_size; @@ -502,12 +484,11 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, store_sigregs(); /* Create ucontext on the signal stack. */ - sigset_to_sigset32(set->sig, cset.sig); if (__put_user(uc_flags, &frame->uc.uc_flags) || __put_user(0, &frame->uc.uc_link) || __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) || save_sigregs32(regs, &frame->uc.uc_mcontext) || - __copy_to_user(&frame->uc.uc_sigmask, &cset, sizeof(cset)) || + put_compat_sigset(&frame->uc.uc_sigmask, set, sizeof(compat_sigset_t)) || save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext)) return -EFAULT; diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 5c572de64c74..54a6159b9cd8 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -249,7 +249,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) compat_uptr_t fpu_save; compat_uptr_t rwin_save; sigset_t set; - compat_sigset_t seta; int err, i; /* Always make any pending restarted system calls return -EINTR */ @@ -312,7 +311,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) err |= __get_user(fpu_save, &sf->fpu_save); if (!err && fpu_save) err |= restore_fpu_state(regs, compat_ptr(fpu_save)); - err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t)); + err |= get_compat_sigset(&set, &sf->mask); err |= compat_restore_altstack(&sf->stack); if (err) goto segv; @@ -323,7 +322,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) goto segv; } - set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); set_current_blocked(&set); return; segv: @@ -555,7 +553,6 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs, void __user *tail; int sigframe_size; u32 psr; - compat_sigset_t seta; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -625,9 +622,7 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs, /* Setup sigaltstack */ err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]); - seta.sig[1] = (oldset->sig[0] >> 32); - seta.sig[0] = oldset->sig[0]; - err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t)); + err |= put_compat_sigset(&sf->mask, oldset, sizeof(compat_sigset_t)); if (!wsaved) { err |= copy_in_user((u32 __user *)sf, diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index b4e1478413a1..6d964bdefbaa 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -160,7 +160,6 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig, { struct k_sigaction new_ka, old_ka; int ret; - compat_sigset_t set32; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(compat_sigset_t)) @@ -172,8 +171,7 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig, new_ka.ka_restorer = restorer; ret = get_user(u_handler, &act->sa_handler); new_ka.sa.sa_handler = compat_ptr(u_handler); - ret |= copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); - sigset_from_compat(&new_ka.sa.sa_mask, &set32); + ret |= get_compat_sigset(&new_ka.sa.sa_mask, &act->sa_mask); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= get_user(u_restorer, &act->sa_restorer); new_ka.sa.sa_restorer = compat_ptr(u_restorer); @@ -184,9 +182,9 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - sigset_to_compat(&set32, &old_ka.sa.sa_mask); ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); - ret |= copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t)); + ret |= put_compat_sigset(&oact->sa_mask, &old_ka.sa.sa_mask, + sizeof(oact->sa_mask)); ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer); if (ret) diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index 70d434bc1cbf..c4ef73c6f455 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -204,9 +204,6 @@ static ssize_t bt_bmc_read(struct file *file, char __user *buf, ssize_t ret = 0; ssize_t nread; - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - WARN_ON(*ppos); if (wait_event_interruptible(bt_bmc->queue, @@ -277,9 +274,6 @@ static ssize_t bt_bmc_write(struct file *file, const char __user *buf, if (count < 5) return -EINVAL; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - WARN_ON(*ppos); /* diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 09143b840482..2de40d276116 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h @@ -147,6 +147,10 @@ extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv); + extern void r128_freelist_reset(struct drm_device *dev); extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n); diff --git a/drivers/gpu/drm/r128/r128_ioc32.c b/drivers/gpu/drm/r128/r128_ioc32.c index 663f38c63ba6..6589f9e0310e 100644 --- a/drivers/gpu/drm/r128/r128_ioc32.c +++ b/drivers/gpu/drm/r128/r128_ioc32.c @@ -63,39 +63,36 @@ static int compat_r128_init(struct file *file, unsigned int cmd, unsigned long arg) { drm_r128_init32_t init32; - drm_r128_init_t __user *init; + drm_r128_init_t init; if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) return -EFAULT; - init = compat_alloc_user_space(sizeof(*init)); - if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) - || __put_user(init32.func, &init->func) - || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) - || __put_user(init32.is_pci, &init->is_pci) - || __put_user(init32.cce_mode, &init->cce_mode) - || __put_user(init32.cce_secure, &init->cce_secure) - || __put_user(init32.ring_size, &init->ring_size) - || __put_user(init32.usec_timeout, &init->usec_timeout) - || __put_user(init32.fb_bpp, &init->fb_bpp) - || __put_user(init32.front_offset, &init->front_offset) - || __put_user(init32.front_pitch, &init->front_pitch) - || __put_user(init32.back_offset, &init->back_offset) - || __put_user(init32.back_pitch, &init->back_pitch) - || __put_user(init32.depth_bpp, &init->depth_bpp) - || __put_user(init32.depth_offset, &init->depth_offset) - || __put_user(init32.depth_pitch, &init->depth_pitch) - || __put_user(init32.span_offset, &init->span_offset) - || __put_user(init32.fb_offset, &init->fb_offset) - || __put_user(init32.mmio_offset, &init->mmio_offset) - || __put_user(init32.ring_offset, &init->ring_offset) - || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) - || __put_user(init32.buffers_offset, &init->buffers_offset) - || __put_user(init32.agp_textures_offset, - &init->agp_textures_offset)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_R128_INIT, (unsigned long)init); + init.func = init32.func; + init.sarea_priv_offset = init32.sarea_priv_offset; + init.is_pci = init32.is_pci; + init.cce_mode = init32.cce_mode; + init.cce_secure = init32.cce_secure; + init.ring_size = init32.ring_size; + init.usec_timeout = init32.usec_timeout; + init.fb_bpp = init32.fb_bpp; + init.front_offset = init32.front_offset; + init.front_pitch = init32.front_pitch; + init.back_offset = init32.back_offset; + init.back_pitch = init32.back_pitch; + init.depth_bpp = init32.depth_bpp; + init.depth_offset = init32.depth_offset; + init.depth_pitch = init32.depth_pitch; + init.span_offset = init32.span_offset; + init.fb_offset = init32.fb_offset; + init.mmio_offset = init32.mmio_offset; + init.ring_offset = init32.ring_offset; + init.ring_rptr_offset = init32.ring_rptr_offset; + init.buffers_offset = init32.buffers_offset; + init.agp_textures_offset = init32.agp_textures_offset; + + return drm_ioctl_kernel(file, r128_cce_init, &init, + DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); } typedef struct drm_r128_depth32 { @@ -111,25 +108,19 @@ static int compat_r128_depth(struct file *file, unsigned int cmd, unsigned long arg) { drm_r128_depth32_t depth32; - drm_r128_depth_t __user *depth; + drm_r128_depth_t depth; if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32))) return -EFAULT; - depth = compat_alloc_user_space(sizeof(*depth)); - if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth)) - || __put_user(depth32.func, &depth->func) - || __put_user(depth32.n, &depth->n) - || __put_user((int __user *)(unsigned long)depth32.x, &depth->x) - || __put_user((int __user *)(unsigned long)depth32.y, &depth->y) - || __put_user((unsigned int __user *)(unsigned long)depth32.buffer, - &depth->buffer) - || __put_user((unsigned char __user *)(unsigned long)depth32.mask, - &depth->mask)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_R128_DEPTH, (unsigned long)depth); + depth.func = depth32.func; + depth.n = depth32.n; + depth.x = compat_ptr(depth32.x); + depth.y = compat_ptr(depth32.y); + depth.buffer = compat_ptr(depth32.buffer); + depth.mask = compat_ptr(depth32.mask); + return drm_ioctl_kernel(file, r128_cce_depth, &depth, DRM_AUTH); } typedef struct drm_r128_stipple32 { @@ -140,18 +131,14 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd, unsigned long arg) { drm_r128_stipple32_t stipple32; - drm_r128_stipple_t __user *stipple; + drm_r128_stipple_t stipple; if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32))) return -EFAULT; - stipple = compat_alloc_user_space(sizeof(*stipple)); - if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple)) - || __put_user((unsigned int __user *)(unsigned long)stipple32.mask, - &stipple->mask)) - return -EFAULT; + stipple.mask = compat_ptr(stipple32.mask); - return drm_ioctl(file, DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple); + return drm_ioctl_kernel(file, r128_cce_stipple, &stipple, DRM_AUTH); } typedef struct drm_r128_getparam32 { @@ -163,19 +150,15 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd, unsigned long arg) { drm_r128_getparam32_t getparam32; - drm_r128_getparam_t __user *getparam; + drm_r128_getparam_t getparam; if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32))) return -EFAULT; - getparam = compat_alloc_user_space(sizeof(*getparam)); - if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam)) - || __put_user(getparam32.param, &getparam->param) - || __put_user((void __user *)(unsigned long)getparam32.value, - &getparam->value)) - return -EFAULT; + getparam.param = getparam32.param; + getparam.value = compat_ptr(getparam32.value); - return drm_ioctl(file, DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam); + return drm_ioctl_kernel(file, r128_getparam, &getparam, DRM_AUTH); } drm_ioctl_compat_t *r128_compat_ioctls[] = { diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 8fd2d9f58f77..8fdc56c1c953 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1460,7 +1460,7 @@ static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *fi return ret; } -static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv) +int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_depth_t *depth = data; @@ -1492,7 +1492,7 @@ static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *f return ret; } -static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) +int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_stipple_t *stipple = data; @@ -1582,7 +1582,7 @@ static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file return 0; } -static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) +int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_getparam_t *param = data; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6f638bbc922d..2cab27a68479 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -35,6 +35,7 @@ #include <linux/notifier.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/compat.h> /* * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a @@ -238,46 +239,29 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) } static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, - unsigned long arg) + unsigned nmsgs, struct i2c_msg *msgs) { - struct i2c_rdwr_ioctl_data rdwr_arg; - struct i2c_msg *rdwr_pa; u8 __user **data_ptrs; int i, res; - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __user *)arg, - sizeof(rdwr_arg))) - return -EFAULT; - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) - return -EINVAL; - - rdwr_pa = memdup_user(rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg)); - if (IS_ERR(rdwr_pa)) - return PTR_ERR(rdwr_pa); - - data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); + data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { - kfree(rdwr_pa); + kfree(msgs); return -ENOMEM; } res = 0; - for (i = 0; i < rdwr_arg.nmsgs; i++) { + for (i = 0; i < nmsgs; i++) { /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + if (msgs[i].len > 8192) { res = -EINVAL; break; } - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; - rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); - if (IS_ERR(rdwr_pa[i].buf)) { - res = PTR_ERR(rdwr_pa[i].buf); + data_ptrs[i] = (u8 __user *)msgs[i].buf; + msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len); + if (IS_ERR(msgs[i].buf)) { + res = PTR_ERR(msgs[i].buf); break; } @@ -292,121 +276,117 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, * greater (for example to account for a checksum byte at * the end of the message.) */ - if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { - if (!(rdwr_pa[i].flags & I2C_M_RD) || - rdwr_pa[i].buf[0] < 1 || - rdwr_pa[i].len < rdwr_pa[i].buf[0] + + if (msgs[i].flags & I2C_M_RECV_LEN) { + if (!(msgs[i].flags & I2C_M_RD) || + msgs[i].buf[0] < 1 || + msgs[i].len < msgs[i].buf[0] + I2C_SMBUS_BLOCK_MAX) { res = -EINVAL; break; } - rdwr_pa[i].len = rdwr_pa[i].buf[0]; + msgs[i].len = msgs[i].buf[0]; } } if (res < 0) { int j; for (j = 0; j < i; ++j) - kfree(rdwr_pa[j].buf); + kfree(msgs[j].buf); kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } - res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); + res = i2c_transfer(client->adapter, msgs, nmsgs); while (i-- > 0) { - if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { - if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, - rdwr_pa[i].len)) + if (res >= 0 && (msgs[i].flags & I2C_M_RD)) { + if (copy_to_user(data_ptrs[i], msgs[i].buf, + msgs[i].len)) res = -EFAULT; } - kfree(rdwr_pa[i].buf); + kfree(msgs[i].buf); } kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, - unsigned long arg) + u8 read_write, u8 command, u32 size, + union i2c_smbus_data __user *data) { - struct i2c_smbus_ioctl_data data_arg; union i2c_smbus_data temp = {}; int datasize, res; - if (copy_from_user(&data_arg, - (struct i2c_smbus_ioctl_data __user *) arg, - sizeof(struct i2c_smbus_ioctl_data))) - return -EFAULT; - if ((data_arg.size != I2C_SMBUS_BYTE) && - (data_arg.size != I2C_SMBUS_QUICK) && - (data_arg.size != I2C_SMBUS_BYTE_DATA) && - (data_arg.size != I2C_SMBUS_WORD_DATA) && - (data_arg.size != I2C_SMBUS_PROC_CALL) && - (data_arg.size != I2C_SMBUS_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { + if ((size != I2C_SMBUS_BYTE) && + (size != I2C_SMBUS_QUICK) && + (size != I2C_SMBUS_BYTE_DATA) && + (size != I2C_SMBUS_WORD_DATA) && + (size != I2C_SMBUS_PROC_CALL) && + (size != I2C_SMBUS_BLOCK_DATA) && + (size != I2C_SMBUS_I2C_BLOCK_BROKEN) && + (size != I2C_SMBUS_I2C_BLOCK_DATA) && + (size != I2C_SMBUS_BLOCK_PROC_CALL)) { dev_dbg(&client->adapter->dev, "size out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.size); + size); return -EINVAL; } /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, so the check is valid if size==I2C_SMBUS_QUICK too. */ - if ((data_arg.read_write != I2C_SMBUS_READ) && - (data_arg.read_write != I2C_SMBUS_WRITE)) { + if ((read_write != I2C_SMBUS_READ) && + (read_write != I2C_SMBUS_WRITE)) { dev_dbg(&client->adapter->dev, "read_write out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.read_write); + read_write); return -EINVAL; } /* Note that command values are always valid! */ - if ((data_arg.size == I2C_SMBUS_QUICK) || - ((data_arg.size == I2C_SMBUS_BYTE) && - (data_arg.read_write == I2C_SMBUS_WRITE))) + if ((size == I2C_SMBUS_QUICK) || + ((size == I2C_SMBUS_BYTE) && + (read_write == I2C_SMBUS_WRITE))) /* These are special: we do not use data */ return i2c_smbus_xfer(client->adapter, client->addr, - client->flags, data_arg.read_write, - data_arg.command, data_arg.size, NULL); + client->flags, read_write, + command, size, NULL); - if (data_arg.data == NULL) { + if (data == NULL) { dev_dbg(&client->adapter->dev, "data is NULL pointer in ioctl I2C_SMBUS.\n"); return -EINVAL; } - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || - (data_arg.size == I2C_SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || - (data_arg.size == I2C_SMBUS_PROC_CALL)) - datasize = sizeof(data_arg.data->word); + if ((size == I2C_SMBUS_BYTE_DATA) || + (size == I2C_SMBUS_BYTE)) + datasize = sizeof(data->byte); + else if ((size == I2C_SMBUS_WORD_DATA) || + (size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data->word); else /* size == smbus block, i2c block, or block proc. call */ - datasize = sizeof(data_arg.data->block); + datasize = sizeof(data->block); - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || - (data_arg.read_write == I2C_SMBUS_WRITE)) { - if (copy_from_user(&temp, data_arg.data, datasize)) + if ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (size == I2C_SMBUS_I2C_BLOCK_DATA) || + (read_write == I2C_SMBUS_WRITE)) { + if (copy_from_user(&temp, data, datasize)) return -EFAULT; } - if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { + if (size == I2C_SMBUS_I2C_BLOCK_BROKEN) { /* Convert old I2C block commands to the new convention. This preserves binary compatibility. */ - data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; - if (data_arg.read_write == I2C_SMBUS_READ) + size = I2C_SMBUS_I2C_BLOCK_DATA; + if (read_write == I2C_SMBUS_READ) temp.block[0] = I2C_SMBUS_BLOCK_MAX; } res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - data_arg.read_write, data_arg.command, data_arg.size, &temp); - if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) { - if (copy_to_user(data_arg.data, &temp, datasize)) + read_write, command, size, &temp); + if (!res && ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (read_write == I2C_SMBUS_READ))) { + if (copy_to_user(data, &temp, datasize)) return -EFAULT; } return res; @@ -454,12 +434,39 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) funcs = i2c_get_functionality(client->adapter); return put_user(funcs, (unsigned long __user *)arg); - case I2C_RDWR: - return i2cdev_ioctl_rdwr(client, arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data rdwr_arg; + struct i2c_msg *rdwr_pa; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; - case I2C_SMBUS: - return i2cdev_ioctl_smbus(client, arg); + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data data_arg; + if (copy_from_user(&data_arg, + (struct i2c_smbus_ioctl_data __user *) arg, + sizeof(struct i2c_smbus_ioctl_data))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data_arg.read_write, + data_arg.command, + data_arg.size, + data_arg.data); + } case I2C_RETRIES: client->adapter->retries = arg; break; @@ -480,6 +487,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +#ifdef CONFIG_COMPAT + +struct i2c_smbus_ioctl_data32 { + u8 read_write; + u8 command; + u32 size; + compat_caddr_t data; /* union i2c_smbus_data *data */ +}; + +struct i2c_msg32 { + u16 addr; + u16 flags; + u16 len; + compat_caddr_t buf; +}; + +struct i2c_rdwr_ioctl_data32 { + compat_caddr_t msgs; /* struct i2c_msg __user *msgs */ + u32 nmsgs; +}; + +static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = file->private_data; + unsigned long funcs; + switch (cmd) { + case I2C_FUNCS: + funcs = i2c_get_functionality(client->adapter); + return put_user(funcs, (compat_ulong_t __user *)arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data32 rdwr_arg; + struct i2c_msg32 *p; + struct i2c_msg *rdwr_pa; + int i; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data32 __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; + + rdwr_pa = kmalloc_array(rdwr_arg.nmsgs, sizeof(struct i2c_msg), + GFP_KERNEL); + if (!rdwr_pa) + return -ENOMEM; + + p = compat_ptr(rdwr_arg.msgs); + for (i = 0; i < rdwr_arg.nmsgs; i++) { + struct i2c_msg32 umsg; + if (copy_from_user(&umsg, p + i, sizeof(umsg))) { + kfree(rdwr_pa); + return -EFAULT; + } + rdwr_pa[i] = (struct i2c_msg) { + .addr = umsg.addr, + .flags = umsg.flags, + .len = umsg.len, + .buf = compat_ptr(umsg.buf) + }; + } + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data32 data32; + if (copy_from_user(&data32, + (void __user *) arg, + sizeof(data32))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data32.read_write, + data32.command, + data32.size, + compat_ptr(data32.data)); + } + default: + return i2cdev_ioctl(file, cmd, arg); + } +} +#else +#define compat_i2cdev_ioctl NULL +#endif + static int i2cdev_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); @@ -527,6 +618,7 @@ static const struct file_operations i2cdev_fops = { .read = i2cdev_read, .write = i2cdev_write, .unlocked_ioctl = i2cdev_ioctl, + .compat_ioctl = compat_i2cdev_ioctl, .open = i2cdev_open, .release = i2cdev_release, }; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 3568294d4854..de8c902059b8 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -375,12 +375,7 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd, return -EINVAL; if (!mtd->_write_oob) - ret = -EOPNOTSUPP; - else - ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT; - - if (ret) - return ret; + return -EOPNOTSUPP; ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); @@ -419,9 +414,6 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd, if (length > 4096) return -EINVAL; - if (!access_ok(VERIFY_WRITE, ptr, length)) - return -EFAULT; - ops.ooblen = length; ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; @@ -618,9 +610,6 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd, usr_data = (const void __user *)(uintptr_t)req.usr_data; usr_oob = (const void __user *)(uintptr_t)req.usr_oob; - if (!access_ok(VERIFY_READ, usr_data, req.len) || - !access_ok(VERIFY_READ, usr_oob, req.ooblen)) - return -EFAULT; if (!mtd->_write_oob) return -EOPNOTSUPP; @@ -662,21 +651,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) struct mtd_info *mtd = mfi->mtd; void __user *argp = (void __user *)arg; int ret = 0; - u_long size; struct mtd_info_user info; pr_debug("MTD_ioctl\n"); - size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; - if (cmd & IOC_IN) { - if (!access_ok(VERIFY_READ, argp, size)) - return -EFAULT; - } - if (cmd & IOC_OUT) { - if (!access_ok(VERIFY_WRITE, argp, size)) - return -EFAULT; - } - switch (cmd) { case MEMGETREGIONCOUNT: if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 617802855233..38b3a9c84fd1 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -3393,12 +3393,6 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg, goto out; } - if (unlikely(!access_ok(is_write ? VERIFY_READ : VERIFY_WRITE, - ubuf, ulen))) { - rc = -EFAULT; - goto out; - } - buf = kmalloc(ulen + cache_line_size() - 1, GFP_KERNEL); if (unlikely(!buf)) { rc = -ENOMEM; diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index d946838450d4..2a205c6173dc 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -762,32 +762,15 @@ abort: static long pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - int err = 0; int retval = 0; struct pi433_instance *instance; struct pi433_device *device; - u32 tmp; + void __user *argp = (void __user *)arg; /* Check type and command number */ if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC) return -ENOTTY; - /* Check access direction once here; don't repeat below. - * IOC_DIR is from the user perspective, while access_ok is - * from the kernel perspective; so they look reversed. - */ - if (_IOC_DIR(cmd) & _IOC_READ) - err = !access_ok(VERIFY_WRITE, - (void __user *)arg, - _IOC_SIZE(cmd)); - - if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) - err = !access_ok(VERIFY_READ, - (void __user *)arg, - _IOC_SIZE(cmd)); - if (err) - return -EFAULT; - /* TODO? guard against device removal before, or while, * we issue this ioctl. --> device_get() */ @@ -799,78 +782,33 @@ pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case PI433_IOC_RD_TX_CFG: - tmp = _IOC_SIZE(cmd); - if ((tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0)) { - retval = -EINVAL; - break; - } - - if (__copy_to_user((void __user *)arg, - &instance->tx_cfg, - tmp)) - { - retval = -EFAULT; - break; - } - + if (copy_to_user(argp, &instance->tx_cfg, + sizeof(struct pi433_tx_cfg))) + return -EFAULT; break; case PI433_IOC_WR_TX_CFG: - tmp = _IOC_SIZE(cmd); - if ((tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0)) { - retval = -EINVAL; - break; - } - - if (__copy_from_user(&instance->tx_cfg, - (void __user *)arg, - tmp)) - { - retval = -EFAULT; - break; - } - + if (copy_from_user(&instance->tx_cfg, argp, + sizeof(struct pi433_tx_cfg))) + return -EFAULT; break; - case PI433_IOC_RD_RX_CFG: - tmp = _IOC_SIZE(cmd); - if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { - retval = -EINVAL; - break; - } - - if (__copy_to_user((void __user *)arg, - &device->rx_cfg, - tmp)) - { - retval = -EFAULT; - break; - } - + if (copy_to_user(argp, &device->rx_cfg, + sizeof(struct pi433_rx_cfg))) + return -EFAULT; break; case PI433_IOC_WR_RX_CFG: - tmp = _IOC_SIZE(cmd); mutex_lock(&device->rx_lock); /* during pendig read request, change of config not allowed */ if (device->rx_active) { - retval = -EAGAIN; - mutex_unlock(&device->rx_lock); - break; - } - - if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { - retval = -EINVAL; mutex_unlock(&device->rx_lock); - break; + return -EAGAIN; } - if (__copy_from_user(&device->rx_cfg, - (void __user *)arg, - tmp)) - { - retval = -EFAULT; + if (copy_from_user(&device->rx_cfg, argp, + sizeof(struct pi433_rx_cfg))) { mutex_unlock(&device->rx_lock); - break; + return -EFAULT; } mutex_unlock(&device->rx_lock); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 7a4c8022c023..af4da9507180 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -156,42 +156,34 @@ static int store_utf8(u16 c, char *p) int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; - int sel_mode, new_sel_start, new_sel_end, spc; + int new_sel_start, new_sel_end, spc; + struct tiocl_selection v; char *bp, *obp; int i, ps, pe, multiplier; u16 c; int mode; poke_blanked_console(); + if (copy_from_user(&v, sel, sizeof(*sel))) + return -EFAULT; - { unsigned short xs, ys, xe, ye; + v.xs = limit(v.xs - 1, vc->vc_cols - 1); + v.ys = limit(v.ys - 1, vc->vc_rows - 1); + v.xe = limit(v.xe - 1, vc->vc_cols - 1); + v.ye = limit(v.ye - 1, vc->vc_rows - 1); + ps = v.ys * vc->vc_size_row + (v.xs << 1); + pe = v.ye * vc->vc_size_row + (v.xe << 1); - if (!access_ok(VERIFY_READ, sel, sizeof(*sel))) - return -EFAULT; - __get_user(xs, &sel->xs); - __get_user(ys, &sel->ys); - __get_user(xe, &sel->xe); - __get_user(ye, &sel->ye); - __get_user(sel_mode, &sel->sel_mode); - xs--; ys--; xe--; ye--; - xs = limit(xs, vc->vc_cols - 1); - ys = limit(ys, vc->vc_rows - 1); - xe = limit(xe, vc->vc_cols - 1); - ye = limit(ye, vc->vc_rows - 1); - ps = ys * vc->vc_size_row + (xs << 1); - pe = ye * vc->vc_size_row + (xe << 1); - - if (sel_mode == TIOCL_SELCLEAR) { - /* useful for screendump without selection highlights */ - clear_selection(); - return 0; - } - - if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) { - mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys); - return 0; - } - } + if (v.sel_mode == TIOCL_SELCLEAR) { + /* useful for screendump without selection highlights */ + clear_selection(); + return 0; + } + + if (mouse_reporting() && (v.sel_mode & TIOCL_SELMOUSEREPORT)) { + mouse_report(tty, v.sel_mode & TIOCL_SELBUTTONMASK, v.xs, v.ys); + return 0; + } if (ps > pe) /* make sel_start <= sel_end */ { @@ -210,7 +202,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t else use_unicode = 0; - switch (sel_mode) + switch (v.sel_mode) { case TIOCL_SELCHAR: /* character-by-character selection */ new_sel_start = ps; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 2d2b420598b2..d61be307256a 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -843,58 +843,44 @@ int vt_ioctl(struct tty_struct *tty, case VT_RESIZEX: { - struct vt_consize __user *vtconsize = up; - ushort ll,cc,vlin,clin,vcol,ccol; + struct vt_consize v; if (!perm) return -EPERM; - if (!access_ok(VERIFY_READ, vtconsize, - sizeof(struct vt_consize))) { - ret = -EFAULT; - break; - } + if (copy_from_user(&v, up, sizeof(struct vt_consize))) + return -EFAULT; /* FIXME: Should check the copies properly */ - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : vc->vc_scan_lines; - if (clin) { - if (ll) { - if (ll != vlin/clin) { - /* Parameters don't add up */ - ret = -EINVAL; - break; - } - } else - ll = vlin/clin; + if (!v.v_vlin) + v.v_vlin = vc->vc_scan_lines; + if (v.v_clin) { + int rows = v.v_vlin/v.v_clin; + if (v.v_rows != rows) { + if (v.v_rows) /* Parameters don't add up */ + return -EINVAL; + v.v_rows = rows; + } } - if (vcol && ccol) { - if (cc) { - if (cc != vcol/ccol) { - ret = -EINVAL; - break; - } - } else - cc = vcol/ccol; + if (v.v_vcol && v.v_ccol) { + int cols = v.v_vcol/v.v_ccol; + if (v.v_cols != cols) { + if (v.v_cols) + return -EINVAL; + v.v_cols = cols; + } } - if (clin > 32) { - ret = -EINVAL; - break; - } - + if (v.v_clin > 32) + return -EINVAL; + for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons[i].d) continue; console_lock(); - if (vlin) - vc_cons[i].d->vc_scan_lines = vlin; - if (clin) - vc_cons[i].d->vc_font.height = clin; + if (v.v_vlin) + vc_cons[i].d->vc_scan_lines = v.v_vlin; + if (v.v_clin) + vc_cons[i].d->vc_font.height = v.v_clin; vc_cons[i].d->vc_resize_user = 1; - vc_resize(vc_cons[i].d, cc, ll); + vc_resize(vc_cons[i].d, v.v_cols, v.v_rows); console_unlock(); } break; @@ -1297,20 +1297,10 @@ static bool aio_read_events(struct kioctx *ctx, long min_nr, long nr, static long read_events(struct kioctx *ctx, long min_nr, long nr, struct io_event __user *event, - struct timespec __user *timeout) + ktime_t until) { - ktime_t until = KTIME_MAX; long ret = 0; - if (timeout) { - struct timespec ts; - - if (unlikely(copy_from_user(&ts, timeout, sizeof(ts)))) - return -EFAULT; - - until = timespec_to_ktime(ts); - } - /* * Note that aio_read_events() is being called as the conditional - i.e. * we're calling it after prepare_to_wait() has set task state to @@ -1826,6 +1816,25 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, return ret; } +static long do_io_getevents(aio_context_t ctx_id, + long min_nr, + long nr, + struct io_event __user *events, + struct timespec64 *ts) +{ + ktime_t until = ts ? timespec64_to_ktime(*ts) : KTIME_MAX; + struct kioctx *ioctx = lookup_ioctx(ctx_id); + long ret = -EINVAL; + + if (likely(ioctx)) { + if (likely(min_nr <= nr && min_nr >= 0)) + ret = read_events(ioctx, min_nr, nr, events, until); + percpu_ref_put(&ioctx->users); + } + + return ret; +} + /* io_getevents: * Attempts to read at least min_nr events and up to nr events from * the completion queue for the aio_context specified by ctx_id. If @@ -1844,15 +1853,14 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, struct io_event __user *, events, struct timespec __user *, timeout) { - struct kioctx *ioctx = lookup_ioctx(ctx_id); - long ret = -EINVAL; + struct timespec64 ts; - if (likely(ioctx)) { - if (likely(min_nr <= nr && min_nr >= 0)) - ret = read_events(ioctx, min_nr, nr, events, timeout); - percpu_ref_put(&ioctx->users); + if (timeout) { + if (unlikely(get_timespec64(&ts, timeout))) + return -EFAULT; } - return ret; + + return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL); } #ifdef CONFIG_COMPAT @@ -1862,17 +1870,14 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id, struct io_event __user *, events, struct compat_timespec __user *, timeout) { - struct timespec t; - struct timespec __user *ut = NULL; + struct timespec64 t; if (timeout) { - if (compat_get_timespec(&t, timeout)) + if (compat_get_timespec64(&t, timeout)) return -EFAULT; - ut = compat_alloc_user_space(sizeof(*ut)); - if (copy_to_user(ut, &t, sizeof(t))) - return -EFAULT; } - return sys_io_getevents(ctx_id, min_nr, nr, events, ut); + + return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL); } #endif diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index bd5d91e119ca..f95aa0b2e9c0 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -54,8 +54,6 @@ #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> @@ -137,22 +135,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return vfs_ioctl(file, cmd, arg); } -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; -} - struct compat_video_event { int32_t type; compat_time_t timestamp; @@ -671,96 +653,6 @@ static int serial_struct_ioctl(struct file *file, return err; } -/* - * I2C layer ioctls - */ - -struct i2c_msg32 { - u16 addr; - u16 flags; - u16 len; - compat_caddr_t buf; -}; - -struct i2c_rdwr_ioctl_data32 { - compat_caddr_t msgs; /* struct i2c_msg __user *msgs */ - u32 nmsgs; -}; - -struct i2c_smbus_ioctl_data32 { - u8 read_write; - u8 command; - u32 size; - compat_caddr_t data; /* union i2c_smbus_data *data */ -}; - -struct i2c_rdwr_aligned { - struct i2c_rdwr_ioctl_data cmd; - struct i2c_msg msgs[0]; -}; - -static int do_i2c_rdwr_ioctl(struct file *file, - unsigned int cmd, struct i2c_rdwr_ioctl_data32 __user *udata) -{ - struct i2c_rdwr_aligned __user *tdata; - struct i2c_msg __user *tmsgs; - struct i2c_msg32 __user *umsgs; - compat_caddr_t datap; - u32 nmsgs; - int i; - - if (get_user(nmsgs, &udata->nmsgs)) - return -EFAULT; - if (nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) - return -EINVAL; - - if (get_user(datap, &udata->msgs)) - return -EFAULT; - umsgs = compat_ptr(datap); - - tdata = compat_alloc_user_space(sizeof(*tdata) + - nmsgs * sizeof(struct i2c_msg)); - tmsgs = &tdata->msgs[0]; - - if (put_user(nmsgs, &tdata->cmd.nmsgs) || - put_user(tmsgs, &tdata->cmd.msgs)) - return -EFAULT; - - for (i = 0; i < nmsgs; i++) { - if (copy_in_user(&tmsgs[i].addr, &umsgs[i].addr, 3*sizeof(u16))) - return -EFAULT; - if (get_user(datap, &umsgs[i].buf) || - put_user(compat_ptr(datap), &tmsgs[i].buf)) - return -EFAULT; - } - return do_ioctl(file, cmd, (unsigned long)tdata); -} - -static int do_i2c_smbus_ioctl(struct file *file, - unsigned int cmd, struct i2c_smbus_ioctl_data32 __user *udata) -{ - struct i2c_smbus_ioctl_data __user *tdata; - union { - /* beginnings of those have identical layouts */ - struct i2c_smbus_ioctl_data32 data32; - struct i2c_smbus_ioctl_data data; - } v; - - tdata = compat_alloc_user_space(sizeof(*tdata)); - if (tdata == NULL) - return -ENOMEM; - - memset(&v, 0, sizeof(v)); - if (copy_from_user(&v.data32, udata, sizeof(v.data32))) - return -EFAULT; - v.data.data = compat_ptr(v.data32.data); - - if (copy_to_user(tdata, &v.data, sizeof(v.data))) - return -EFAULT; - - return do_ioctl(file, cmd, (unsigned long)tdata); -} - #define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t) #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) #define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t) @@ -1283,13 +1175,6 @@ COMPATIBLE_IOCTL(PCIIOC_CONTROLLER) COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO) COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM) COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE) -/* i2c */ -COMPATIBLE_IOCTL(I2C_SLAVE) -COMPATIBLE_IOCTL(I2C_SLAVE_FORCE) -COMPATIBLE_IOCTL(I2C_TENBIT) -COMPATIBLE_IOCTL(I2C_PEC) -COMPATIBLE_IOCTL(I2C_RETRIES) -COMPATIBLE_IOCTL(I2C_TIMEOUT) /* hiddev */ COMPATIBLE_IOCTL(HIDIOCGVERSION) COMPATIBLE_IOCTL(HIDIOCAPPLICATION) @@ -1464,13 +1349,6 @@ static long do_ioctl_trans(unsigned int cmd, case TIOCGSERIAL: case TIOCSSERIAL: return serial_struct_ioctl(file, cmd, argp); - /* i2c */ - case I2C_FUNCS: - return w_long(file, cmd, argp); - case I2C_RDWR: - return do_i2c_rdwr_ioctl(file, cmd, argp); - case I2C_SMBUS: - return do_i2c_smbus_ioctl(file, cmd, argp); /* Not implemented in the native kernel */ case RTC_IRQP_READ32: case RTC_IRQP_SET32: diff --git a/fs/coredump.c b/fs/coredump.c index 52c63d6c9143..1e2c87acac9b 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -680,16 +680,11 @@ void do_coredump(const siginfo_t *siginfo) * privs and don't want to unlink another user's coredump. */ if (!need_suid_safe) { - mm_segment_t old_fs; - - old_fs = get_fs(); - set_fs(KERNEL_DS); /* * If it doesn't exist, that's fine. If there's some * other problem, we'll catch it at the filp_open(). */ - (void) sys_unlink((const char __user *)cn.corename); - set_fs(old_fs); + do_unlinkat(AT_FDCWD, getname_kernel(cn.corename)); } /* diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 2fabd19cdeea..396a3c075fd4 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -2259,7 +2259,6 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, compat_size_t, sigsetsize) { long err; - compat_sigset_t csigmask; sigset_t ksigmask, sigsaved; /* @@ -2269,9 +2268,8 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, if (sigmask) { if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) + if (get_compat_sigset(&ksigmask, sigmask)) return -EFAULT; - sigset_from_compat(&ksigmask, &csigmask); sigsaved = current->blocked; set_current_blocked(&ksigmask); } diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index b7558f292420..1eec25014f62 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -592,6 +592,44 @@ static int ext4_ioc_getfsmap(struct super_block *sb, return 0; } +static long ext4_ioctl_group_add(struct file *file, + struct ext4_new_group_data *input) +{ + struct super_block *sb = file_inode(file)->i_sb; + int err, err2=0; + + err = ext4_resize_begin(sb); + if (err) + return err; + + if (ext4_has_feature_bigalloc(sb)) { + ext4_msg(sb, KERN_ERR, + "Online resizing not supported with bigalloc"); + err = -EOPNOTSUPP; + goto group_add_out; + } + + err = mnt_want_write_file(file); + if (err) + goto group_add_out; + + err = ext4_group_add(sb, input); + if (EXT4_SB(sb)->s_journal) { + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); + } + if (err == 0) + err = err2; + mnt_drop_write_file(file); + if (!err && ext4_has_group_desc_csum(sb) && + test_opt(sb, INIT_INODE_TABLE)) + err = ext4_register_li_request(sb, input->group); +group_add_out: + ext4_resize_end(sb); + return err; +} + long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); @@ -776,44 +814,12 @@ mext_out: case EXT4_IOC_GROUP_ADD: { struct ext4_new_group_data input; - int err, err2=0; - - err = ext4_resize_begin(sb); - if (err) - return err; if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, - sizeof(input))) { - err = -EFAULT; - goto group_add_out; - } - - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, - "Online resizing not supported with bigalloc"); - err = -EOPNOTSUPP; - goto group_add_out; - } - - err = mnt_want_write_file(filp); - if (err) - goto group_add_out; + sizeof(input))) + return -EFAULT; - err = ext4_group_add(sb, &input); - if (EXT4_SB(sb)->s_journal) { - jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); - err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); - jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - } - if (err == 0) - err = err2; - mnt_drop_write_file(filp); - if (!err && ext4_has_group_desc_csum(sb) && - test_opt(sb, INIT_INODE_TABLE)) - err = ext4_register_li_request(sb, input.group); -group_add_out: - ext4_resize_end(sb); - return err; + return ext4_ioctl_group_add(filp, &input); } case EXT4_IOC_MIGRATE: @@ -1078,8 +1084,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case EXT4_IOC32_GROUP_ADD: { struct compat_ext4_new_group_input __user *uinput; - struct ext4_new_group_input input; - mm_segment_t old_fs; + struct ext4_new_group_data input; int err; uinput = compat_ptr(arg); @@ -1092,12 +1097,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) &uinput->reserved_blocks); if (err) return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD, - (unsigned long) &input); - set_fs(old_fs); - return err; + return ext4_ioctl_group_add(file, &input); } case EXT4_IOC_MOVE_EXT: case EXT4_IOC_RESIZE_FS: diff --git a/fs/internal.h b/fs/internal.h index 48cee21b4f14..df262f41a0ef 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -55,6 +55,7 @@ extern void __init chrdev_init(void); extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); +long do_unlinkat(int dfd, struct filename *name); /* * namespace.c diff --git a/fs/namei.c b/fs/namei.c index 5424b10cfdc4..287781363763 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4010,10 +4010,9 @@ EXPORT_SYMBOL(vfs_unlink); * writeout happening, and we don't want to prevent access to the directory * while waiting on the I/O. */ -static long do_unlinkat(int dfd, const char __user *pathname) +long do_unlinkat(int dfd, struct filename *name) { int error; - struct filename *name; struct dentry *dentry; struct path path; struct qstr last; @@ -4022,8 +4021,7 @@ static long do_unlinkat(int dfd, const char __user *pathname) struct inode *delegated_inode = NULL; unsigned int lookup_flags = 0; retry: - name = filename_parentat(dfd, getname(pathname), lookup_flags, - &path, &last, &type); + name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); if (IS_ERR(name)) return PTR_ERR(name); @@ -4065,12 +4063,12 @@ exit2: mnt_drop_write(path.mnt); exit1: path_put(&path); - putname(name); if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; inode = NULL; goto retry; } + putname(name); return error; slashes: @@ -4091,12 +4089,12 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) if (flag & AT_REMOVEDIR) return do_rmdir(dfd, pathname); - return do_unlinkat(dfd, pathname); + return do_unlinkat(dfd, getname(pathname)); } SYSCALL_DEFINE1(unlink, const char __user *, pathname) { - return do_unlinkat(AT_FDCWD, pathname); + return do_unlinkat(AT_FDCWD, getname(pathname)); } int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) diff --git a/fs/select.c b/fs/select.c index 063067e606ca..6de493bb42a4 100644 --- a/fs/select.c +++ b/fs/select.c @@ -292,8 +292,7 @@ static int poll_select_copy_remaining(struct timespec64 *end_time, void __user *p, int timeval, int ret) { - struct timespec64 rts64; - struct timespec rts; + struct timespec64 rts; struct timeval rtv; if (!p) @@ -306,23 +305,22 @@ static int poll_select_copy_remaining(struct timespec64 *end_time, if (!end_time->tv_sec && !end_time->tv_nsec) return ret; - ktime_get_ts64(&rts64); - rts64 = timespec64_sub(*end_time, rts64); - if (rts64.tv_sec < 0) - rts64.tv_sec = rts64.tv_nsec = 0; + ktime_get_ts64(&rts); + rts = timespec64_sub(*end_time, rts); + if (rts.tv_sec < 0) + rts.tv_sec = rts.tv_nsec = 0; - rts = timespec64_to_timespec(rts64); if (timeval) { if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) memset(&rtv, 0, sizeof(rtv)); - rtv.tv_sec = rts64.tv_sec; - rtv.tv_usec = rts64.tv_nsec / NSEC_PER_USEC; + rtv.tv_sec = rts.tv_sec; + rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; if (!copy_to_user(p, &rtv, sizeof(rtv))) return ret; - } else if (!copy_to_user(p, &rts, sizeof(rts))) + } else if (!put_timespec64(&rts, p)) return ret; /* @@ -705,17 +703,15 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, const sigset_t __user *sigmask, size_t sigsetsize) { sigset_t ksigmask, sigsaved; - struct timespec ts; - struct timespec64 ts64, end_time, *to = NULL; + struct timespec64 ts, end_time, *to = NULL; int ret; if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) + if (get_timespec64(&ts, tsp)) return -EFAULT; - ts64 = timespec_to_timespec64(ts); to = &end_time; - if (poll_select_set_timeout(to, ts64.tv_sec, ts64.tv_nsec)) + if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) return -EINVAL; } @@ -1052,12 +1048,11 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, size_t, sigsetsize) { sigset_t ksigmask, sigsaved; - struct timespec ts; - struct timespec64 end_time, *to = NULL; + struct timespec64 ts, end_time, *to = NULL; int ret; if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) + if (get_timespec64(&ts, tsp)) return -EFAULT; to = &end_time; @@ -1103,10 +1098,10 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) static -int compat_poll_select_copy_remaining(struct timespec *end_time, void __user *p, +int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user *p, int timeval, int ret) { - struct timespec ts; + struct timespec64 ts; if (!p) return ret; @@ -1118,8 +1113,8 @@ int compat_poll_select_copy_remaining(struct timespec *end_time, void __user *p, if (!end_time->tv_sec && !end_time->tv_nsec) return ret; - ktime_get_ts(&ts); - ts = timespec_sub(*end_time, ts); + ktime_get_ts64(&ts); + ts = timespec64_sub(*end_time, ts); if (ts.tv_sec < 0) ts.tv_sec = ts.tv_nsec = 0; @@ -1132,12 +1127,7 @@ int compat_poll_select_copy_remaining(struct timespec *end_time, void __user *p, if (!copy_to_user(p, &rtv, sizeof(rtv))) return ret; } else { - struct compat_timespec rts; - - rts.tv_sec = ts.tv_sec; - rts.tv_nsec = ts.tv_nsec; - - if (!copy_to_user(p, &rts, sizeof(rts))) + if (!compat_put_timespec64(&ts, p)) return ret; } /* @@ -1195,7 +1185,7 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset, */ static int compat_core_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct timespec *end_time) + struct timespec64 *end_time) { fd_set_bits fds; void *bits; @@ -1268,7 +1258,7 @@ COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, struct compat_timeval __user *, tvp) { - struct timespec end_time, *to = NULL; + struct timespec64 end_time, *to = NULL; struct compat_timeval tv; int ret; @@ -1312,14 +1302,12 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, compat_size_t sigsetsize) { - compat_sigset_t ss32; sigset_t ksigmask, sigsaved; - struct compat_timespec ts; - struct timespec end_time, *to = NULL; + struct timespec64 ts, end_time, *to = NULL; int ret; if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) + if (compat_get_timespec64(&ts, tsp)) return -EFAULT; to = &end_time; @@ -1330,9 +1318,8 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp, if (sigmask) { if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - if (copy_from_user(&ss32, sigmask, sizeof(ss32))) + if (get_compat_sigset(&ksigmask, sigmask)) return -EFAULT; - sigset_from_compat(&ksigmask, &ss32); sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); @@ -1381,14 +1368,12 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, struct compat_timespec __user *, tsp, const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) { - compat_sigset_t ss32; sigset_t ksigmask, sigsaved; - struct compat_timespec ts; - struct timespec end_time, *to = NULL; + struct timespec64 ts, end_time, *to = NULL; int ret; if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) + if (compat_get_timespec64(&ts, tsp)) return -EFAULT; to = &end_time; @@ -1399,9 +1384,8 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, if (sigmask) { if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - if (copy_from_user(&ss32, sigmask, sizeof(ss32))) + if (get_compat_sigset(&ksigmask, sigmask)) return -EFAULT; - sigset_from_compat(&ksigmask, &ss32); sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); diff --git a/fs/signalfd.c b/fs/signalfd.c index 1c667af86da5..5f1ff8756595 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -313,15 +313,13 @@ COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd, compat_size_t, sigsetsize, int, flags) { - compat_sigset_t ss32; sigset_t tmp; sigset_t __user *ksigmask; if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; - if (copy_from_user(&ss32, sigmask, sizeof(ss32))) + if (get_compat_sigset(&tmp, sigmask)) return -EFAULT; - sigset_from_compat(&tmp, &ss32); ksigmask = compat_alloc_user_space(sizeof(sigset_t)); if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t))) return -EFAULT; diff --git a/include/linux/compat.h b/include/linux/compat.h index 3e838a828459..0fc36406f32c 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -444,11 +444,6 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs, return lhs->tv_nsec - rhs->tv_nsec; } -extern int get_compat_itimerspec(struct itimerspec *dst, - const struct compat_itimerspec __user *src); -extern int put_compat_itimerspec(struct compat_itimerspec __user *dst, - const struct itimerspec *src); - asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz); asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, @@ -456,8 +451,9 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); -extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat); -extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set); +extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat); +extern int put_compat_sigset(compat_sigset_t __user *compat, + const sigset_t *set, unsigned int size); asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, diff --git a/kernel/compat.c b/kernel/compat.c index 772e038d04d9..d1cee656a7ed 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -367,24 +367,6 @@ COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t, pid, unsigned int, len, return ret; } -int get_compat_itimerspec(struct itimerspec *dst, - const struct compat_itimerspec __user *src) -{ - if (__compat_get_timespec(&dst->it_interval, &src->it_interval) || - __compat_get_timespec(&dst->it_value, &src->it_value)) - return -EFAULT; - return 0; -} - -int put_compat_itimerspec(struct compat_itimerspec __user *dst, - const struct itimerspec *src) -{ - if (__compat_put_timespec(&src->it_interval, &dst->it_interval) || - __compat_put_timespec(&src->it_value, &dst->it_value)) - return -EFAULT; - return 0; -} - int get_compat_itimerspec64(struct itimerspec64 *its, const struct compat_itimerspec __user *uits) { @@ -485,27 +467,44 @@ Efault: return -EFAULT; } -void -sigset_from_compat(sigset_t *set, const compat_sigset_t *compat) +int +get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat) { +#ifdef __BIG_ENDIAN + compat_sigset_t v; + if (copy_from_user(&v, compat, sizeof(compat_sigset_t))) + return -EFAULT; switch (_NSIG_WORDS) { - case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); - case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 ); - case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 ); - case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 ); + case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 ); + case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 ); + case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 ); + case 1: set->sig[0] = v.sig[0] | (((long)v.sig[1]) << 32 ); } +#else + if (copy_from_user(set, compat, sizeof(compat_sigset_t))) + return -EFAULT; +#endif + return 0; } -EXPORT_SYMBOL_GPL(sigset_from_compat); +EXPORT_SYMBOL_GPL(get_compat_sigset); -void -sigset_to_compat(compat_sigset_t *compat, const sigset_t *set) +int +put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, + unsigned int size) { + /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */ +#ifdef __BIG_ENDIAN + compat_sigset_t v; switch (_NSIG_WORDS) { - case 4: compat->sig[7] = (set->sig[3] >> 32); compat->sig[6] = set->sig[3]; - case 3: compat->sig[5] = (set->sig[2] >> 32); compat->sig[4] = set->sig[2]; - case 2: compat->sig[3] = (set->sig[1] >> 32); compat->sig[2] = set->sig[1]; - case 1: compat->sig[1] = (set->sig[0] >> 32); compat->sig[0] = set->sig[0]; + case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3]; + case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2]; + case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1]; + case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0]; } + return copy_to_user(compat, &v, size) ? -EFAULT : 0; +#else + return copy_to_user(compat, set, size) ? -EFAULT : 0; +#endif } #ifdef CONFIG_NUMA @@ -563,22 +562,6 @@ COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid, } #endif -COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, - compat_pid_t, pid, - struct compat_timespec __user *, interval) -{ - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); - set_fs(old_fs); - if (compat_put_timespec(&t, interval)) - return -EFAULT; - return ret; -} - /* * Allocate user-space memory for the duration of a single system call, * in order to marshall parameters inside a compat thunk. diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a092f350f3a2..75554f366fd3 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -16,6 +16,7 @@ #include <linux/init_task.h> #include <linux/context_tracking.h> #include <linux/rcupdate_wait.h> +#include <linux/compat.h> #include <linux/blkdev.h> #include <linux/kprobes.h> @@ -5107,13 +5108,11 @@ SYSCALL_DEFINE1(sched_get_priority_min, int, policy) * Return: On success, 0 and the timeslice is in @interval. Otherwise, * an error code. */ -SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, - struct timespec __user *, interval) +static int sched_rr_get_interval(pid_t pid, struct timespec64 *t) { struct task_struct *p; unsigned int time_slice; struct rq_flags rf; - struct timespec t; struct rq *rq; int retval; @@ -5137,15 +5136,40 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, task_rq_unlock(rq, p, &rf); rcu_read_unlock(); - jiffies_to_timespec(time_slice, &t); - retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; - return retval; + jiffies_to_timespec64(time_slice, t); + return 0; out_unlock: rcu_read_unlock(); return retval; } +SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, + struct timespec __user *, interval) +{ + struct timespec64 t; + int retval = sched_rr_get_interval(pid, &t); + + if (retval == 0) + retval = put_timespec64(&t, interval); + + return retval; +} + +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, + compat_pid_t, pid, + struct compat_timespec __user *, interval) +{ + struct timespec64 t; + int retval = sched_rr_get_interval(pid, &t); + + if (retval == 0) + retval = compat_put_timespec64(&t, interval); + return retval; +} +#endif + void sched_show_task(struct task_struct *p) { unsigned long free = 0; diff --git a/kernel/signal.c b/kernel/signal.c index aa1fb9f905db..babb36d3d039 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2599,7 +2599,6 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, compat_sigset_t __user *, oset, compat_size_t, sigsetsize) { -#ifdef __BIG_ENDIAN sigset_t old_set = current->blocked; /* XXX: Don't preclude handling different sized sigset_t's. */ @@ -2607,38 +2606,22 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, return -EINVAL; if (nset) { - compat_sigset_t new32; sigset_t new_set; int error; - if (copy_from_user(&new32, nset, sizeof(compat_sigset_t))) + if (get_compat_sigset(&new_set, nset)) return -EFAULT; - - sigset_from_compat(&new_set, &new32); sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); error = sigprocmask(how, &new_set, NULL); if (error) return error; } - if (oset) { - compat_sigset_t old32; - sigset_to_compat(&old32, &old_set); - if (copy_to_user(oset, &old32, sizeof(compat_sigset_t))) - return -EFAULT; - } - return 0; -#else - return sys_rt_sigprocmask(how, (sigset_t __user *)nset, - (sigset_t __user *)oset, sigsetsize); -#endif + return oset ? put_compat_sigset(oset, &old_set, sizeof(*oset)) : 0; } #endif -static int do_sigpending(void *set, unsigned long sigsetsize) +static int do_sigpending(sigset_t *set) { - if (sigsetsize > sizeof(sigset_t)) - return -EINVAL; - spin_lock_irq(¤t->sighand->siglock); sigorsets(set, ¤t->pending.signal, ¤t->signal->shared_pending.signal); @@ -2658,7 +2641,12 @@ static int do_sigpending(void *set, unsigned long sigsetsize) SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize) { sigset_t set; - int err = do_sigpending(&set, sigsetsize); + int err; + + if (sigsetsize > sizeof(*uset)) + return -EINVAL; + + err = do_sigpending(&set); if (!err && copy_to_user(uset, &set, sigsetsize)) err = -EFAULT; return err; @@ -2668,20 +2656,16 @@ SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize) COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset, compat_size_t, sigsetsize) { -#ifdef __BIG_ENDIAN sigset_t set; - int err = do_sigpending(&set, sigsetsize); - if (!err) { - compat_sigset_t set32; - sigset_to_compat(&set32, &set); - /* we can get here only if sigsetsize <= sizeof(set) */ - if (copy_to_user(uset, &set32, sigsetsize)) - err = -EFAULT; - } + int err; + + if (sigsetsize > sizeof(*uset)) + return -EINVAL; + + err = do_sigpending(&set); + if (!err) + err = put_compat_sigset(uset, &set, sigsetsize); return err; -#else - return sys_rt_sigpending((sigset_t __user *)uset, sigsetsize); -#endif } #endif @@ -2915,7 +2899,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, struct compat_siginfo __user *, uinfo, struct compat_timespec __user *, uts, compat_size_t, sigsetsize) { - compat_sigset_t s32; sigset_t s; struct timespec t; siginfo_t info; @@ -2924,9 +2907,8 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, if (sigsetsize != sizeof(sigset_t)) return -EINVAL; - if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) + if (get_compat_sigset(&s, uthese)) return -EFAULT; - sigset_from_compat(&s, &s32); if (uts) { if (compat_get_timespec(&t, uts)) @@ -3344,15 +3326,11 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32) { -#ifdef __BIG_ENDIAN sigset_t set; - int err = do_sigpending(&set, sizeof(set.sig[0])); + int err = do_sigpending(&set); if (!err) err = put_user(set.sig[0], set32); return err; -#else - return sys_rt_sigpending((sigset_t __user *)set32, sizeof(*set32)); -#endif } #endif @@ -3450,7 +3428,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, compat_size_t, sigsetsize) { struct k_sigaction new_ka, old_ka; - compat_sigset_t mask; #ifdef __ARCH_HAS_SA_RESTORER compat_uptr_t restorer; #endif @@ -3468,19 +3445,18 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, ret |= get_user(restorer, &act->sa_restorer); new_ka.sa.sa_restorer = compat_ptr(restorer); #endif - ret |= copy_from_user(&mask, &act->sa_mask, sizeof(mask)); + ret |= get_compat_sigset(&new_ka.sa.sa_mask, &act->sa_mask); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); if (ret) return -EFAULT; - sigset_from_compat(&new_ka.sa.sa_mask, &mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - sigset_to_compat(&mask, &old_ka.sa.sa_mask); ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); - ret |= copy_to_user(&oact->sa_mask, &mask, sizeof(mask)); + ret |= put_compat_sigset(&oact->sa_mask, &old_ka.sa.sa_mask, + sizeof(oact->sa_mask)); ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); #ifdef __ARCH_HAS_SA_RESTORER ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), @@ -3660,22 +3636,15 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize) #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_size_t, sigsetsize) { -#ifdef __BIG_ENDIAN sigset_t newset; - compat_sigset_t newset32; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; - if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) + if (get_compat_sigset(&newset, unewset)) return -EFAULT; - sigset_from_compat(&newset, &newset32); return sigsuspend(&newset); -#else - /* on little-endian bitmaps don't care about granularity */ - return sys_rt_sigsuspend((sigset_t __user *)unewset, sigsetsize); -#endif } #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2dd1a9ca4599..f169ecc4f2e8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2724,7 +2724,6 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, case KVM_SET_SIGNAL_MASK: { struct kvm_signal_mask __user *sigmask_arg = argp; struct kvm_signal_mask kvm_sigmask; - compat_sigset_t csigset; sigset_t sigset; if (argp) { @@ -2733,13 +2732,11 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, sizeof(kvm_sigmask))) goto out; r = -EINVAL; - if (kvm_sigmask.len != sizeof(csigset)) + if (kvm_sigmask.len != sizeof(compat_sigset_t)) goto out; r = -EFAULT; - if (copy_from_user(&csigset, sigmask_arg->sigset, - sizeof(csigset))) + if (get_compat_sigset(&sigset, (void *)sigmask_arg->sigset)) goto out; - sigset_from_compat(&sigset, &csigset); r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); } else r = kvm_vcpu_ioctl_set_sigmask(vcpu, NULL); |