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
  ...
This commit is contained in:
Linus Torvalds 2017-11-17 11:54:55 -08:00
commit 93f30c73ec
32 changed files with 506 additions and 819 deletions

View file

@ -14,45 +14,16 @@
static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d, static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d,
const sigset_t *s) 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)); return put_compat_sigset(d, s, sizeof(*d));
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;
} }
static inline int __copy_conv_sigset_from_user(sigset_t *d, static inline int __copy_conv_sigset_from_user(sigset_t *d,
const compat_sigset_t __user *s) const compat_sigset_t __user *s)
{ {
int err; return get_compat_sigset(d, s);
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;
} }
#endif /* __ASM_COMPAT_SIGNAL_H */ #endif /* __ASM_COMPAT_SIGNAL_H */

View file

@ -93,7 +93,6 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long usp = (regs->gr[30] & ~(0x01UL));
unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
compat_sigset_t compat_set;
struct compat_rt_sigframe __user * compat_frame; struct compat_rt_sigframe __user * compat_frame;
if (is_compat_task()) if (is_compat_task())
@ -114,9 +113,8 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
if (is_compat_task()) { if (is_compat_task()) {
DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); 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; goto give_sigsegv;
sigset_32to64(&set,&compat_set);
} else } else
#endif #endif
{ {
@ -238,7 +236,6 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
int err = 0; int err = 0;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
struct compat_rt_sigframe __user * compat_frame; struct compat_rt_sigframe __user * compat_frame;
compat_sigset_t compat_set;
#endif #endif
usp = (regs->gr[30] & ~(0x01UL)); 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); 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, err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext,
&compat_frame->regs, regs, in_syscall); &compat_frame->regs, regs, in_syscall);
sigset_64to32(&compat_set,set); err |= put_compat_sigset(&compat_frame->uc.uc_sigmask, set,
err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set)); sizeof(compat_sigset_t));
} else } else
#endif #endif
{ {

View file

@ -46,19 +46,6 @@
#define DBG(LEVEL, ...) #define DBG(LEVEL, ...)
#endif #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 long
restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
struct pt_regs *regs) struct pt_regs *regs)

View file

@ -79,8 +79,6 @@ struct compat_rt_sigframe {
#define FUNCTIONCALLFRAME32 48 #define FUNCTIONCALLFRAME32 48
#define PARISC_RT_SIGFRAME_SIZE32 (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32) #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, long restore_sigcontext32(struct compat_sigcontext __user *sc,
struct compat_regfile __user *rf, struct compat_regfile __user *rf,
struct pt_regs *regs); struct pt_regs *regs);

View file

@ -94,40 +94,13 @@
*/ */
static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
{ {
compat_sigset_t cset; return put_compat_sigset(uset, set, sizeof(*uset));
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));
} }
static inline int get_sigset_t(sigset_t *set, static inline int get_sigset_t(sigset_t *set,
const compat_sigset_t __user *uset) const compat_sigset_t __user *uset)
{ {
compat_sigset_t s32; return get_compat_sigset(set, uset);
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;
} }
#define to_user_ptr(p) ptr_to_compat(p) #define to_user_ptr(p) ptr_to_compat(p)

View file

@ -50,19 +50,6 @@ typedef struct
struct ucontext32 uc; struct ucontext32 uc;
} rt_sigframe32; } 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 copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
{ {
int err; int err;
@ -294,12 +281,10 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
{ {
struct pt_regs *regs = task_pt_regs(current); struct pt_regs *regs = task_pt_regs(current);
sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
compat_sigset_t cset;
sigset_t set; 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; goto badframe;
sigset32_to_sigset(cset.sig, set.sig);
set_current_blocked(&set); set_current_blocked(&set);
save_fpu_regs(); save_fpu_regs();
if (restore_sigregs32(regs, &frame->sregs)) if (restore_sigregs32(regs, &frame->sregs))
@ -317,12 +302,10 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
{ {
struct pt_regs *regs = task_pt_regs(current); struct pt_regs *regs = task_pt_regs(current);
rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
compat_sigset_t cset;
sigset_t set; 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; goto badframe;
sigset32_to_sigset(cset.sig, set.sig);
set_current_blocked(&set); set_current_blocked(&set);
if (compat_restore_altstack(&frame->uc.uc_stack)) if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe; goto badframe;
@ -372,7 +355,6 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
{ {
int sig = ksig->sig; int sig = ksig->sig;
sigframe32 __user *frame; sigframe32 __user *frame;
struct sigcontext32 sc;
unsigned long restorer; unsigned long restorer;
size_t frame_size; size_t frame_size;
@ -394,9 +376,10 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set,
return -EFAULT; return -EFAULT;
/* Create struct sigcontext32 on the signal stack */ /* Create struct sigcontext32 on the signal stack */
sigset_to_sigset32(set->sig, sc.oldmask); if (put_compat_sigset((compat_sigset_t __user *)frame->sc.oldmask,
sc.sregs = (__u32)(unsigned long __force) &frame->sregs; set, sizeof(compat_sigset_t)))
if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) return -EFAULT;
if (__put_user(ptr_to_compat(&frame->sc), &frame->sc.sregs))
return -EFAULT; return -EFAULT;
/* Store registers needed to create the signal frame */ /* 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, static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs) struct pt_regs *regs)
{ {
compat_sigset_t cset;
rt_sigframe32 __user *frame; rt_sigframe32 __user *frame;
unsigned long restorer; unsigned long restorer;
size_t frame_size; size_t frame_size;
@ -502,12 +484,11 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
store_sigregs(); store_sigregs();
/* Create ucontext on the signal stack. */ /* Create ucontext on the signal stack. */
sigset_to_sigset32(set->sig, cset.sig);
if (__put_user(uc_flags, &frame->uc.uc_flags) || if (__put_user(uc_flags, &frame->uc.uc_flags) ||
__put_user(0, &frame->uc.uc_link) || __put_user(0, &frame->uc.uc_link) ||
__compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) || __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
save_sigregs32(regs, &frame->uc.uc_mcontext) || 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)) save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
return -EFAULT; return -EFAULT;

View file

@ -249,7 +249,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
compat_uptr_t fpu_save; compat_uptr_t fpu_save;
compat_uptr_t rwin_save; compat_uptr_t rwin_save;
sigset_t set; sigset_t set;
compat_sigset_t seta;
int err, i; int err, i;
/* Always make any pending restarted system calls return -EINTR */ /* 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); err |= __get_user(fpu_save, &sf->fpu_save);
if (!err && fpu_save) if (!err && fpu_save)
err |= restore_fpu_state(regs, compat_ptr(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); err |= compat_restore_altstack(&sf->stack);
if (err) if (err)
goto segv; goto segv;
@ -323,7 +322,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
goto segv; goto segv;
} }
set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
set_current_blocked(&set); set_current_blocked(&set);
return; return;
segv: segv:
@ -555,7 +553,6 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
void __user *tail; void __user *tail;
int sigframe_size; int sigframe_size;
u32 psr; u32 psr;
compat_sigset_t seta;
/* 1. Make sure everything is clean */ /* 1. Make sure everything is clean */
synchronize_user_stack(); synchronize_user_stack();
@ -625,9 +622,7 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
/* Setup sigaltstack */ /* Setup sigaltstack */
err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]); err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
seta.sig[1] = (oldset->sig[0] >> 32); err |= put_compat_sigset(&sf->mask, oldset, sizeof(compat_sigset_t));
seta.sig[0] = oldset->sig[0];
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
if (!wsaved) { if (!wsaved) {
err |= copy_in_user((u32 __user *)sf, err |= copy_in_user((u32 __user *)sf,

View file

@ -160,7 +160,6 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig,
{ {
struct k_sigaction new_ka, old_ka; struct k_sigaction new_ka, old_ka;
int ret; int ret;
compat_sigset_t set32;
/* XXX: Don't preclude handling different sized sigset_t's. */ /* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(compat_sigset_t)) if (sigsetsize != sizeof(compat_sigset_t))
@ -172,8 +171,7 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig,
new_ka.ka_restorer = restorer; new_ka.ka_restorer = restorer;
ret = get_user(u_handler, &act->sa_handler); ret = get_user(u_handler, &act->sa_handler);
new_ka.sa.sa_handler = compat_ptr(u_handler); new_ka.sa.sa_handler = compat_ptr(u_handler);
ret |= copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); ret |= get_compat_sigset(&new_ka.sa.sa_mask, &act->sa_mask);
sigset_from_compat(&new_ka.sa.sa_mask, &set32);
ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
ret |= get_user(u_restorer, &act->sa_restorer); ret |= get_user(u_restorer, &act->sa_restorer);
new_ka.sa.sa_restorer = compat_ptr(u_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); ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) { 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 = 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(old_ka.sa.sa_flags, &oact->sa_flags);
ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer); ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
if (ret) if (ret)

View file

@ -204,9 +204,6 @@ static ssize_t bt_bmc_read(struct file *file, char __user *buf,
ssize_t ret = 0; ssize_t ret = 0;
ssize_t nread; ssize_t nread;
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
WARN_ON(*ppos); WARN_ON(*ppos);
if (wait_event_interruptible(bt_bmc->queue, 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) if (count < 5)
return -EINVAL; return -EINVAL;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
WARN_ON(*ppos); WARN_ON(*ppos);
/* /*

View file

@ -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_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_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 void r128_freelist_reset(struct drm_device *dev);
extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n); extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n);

View file

@ -63,39 +63,36 @@ static int compat_r128_init(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
drm_r128_init32_t init32; 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))) if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
return -EFAULT; return -EFAULT;
init = compat_alloc_user_space(sizeof(*init)); init.func = init32.func;
if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) init.sarea_priv_offset = init32.sarea_priv_offset;
|| __put_user(init32.func, &init->func) init.is_pci = init32.is_pci;
|| __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) init.cce_mode = init32.cce_mode;
|| __put_user(init32.is_pci, &init->is_pci) init.cce_secure = init32.cce_secure;
|| __put_user(init32.cce_mode, &init->cce_mode) init.ring_size = init32.ring_size;
|| __put_user(init32.cce_secure, &init->cce_secure) init.usec_timeout = init32.usec_timeout;
|| __put_user(init32.ring_size, &init->ring_size) init.fb_bpp = init32.fb_bpp;
|| __put_user(init32.usec_timeout, &init->usec_timeout) init.front_offset = init32.front_offset;
|| __put_user(init32.fb_bpp, &init->fb_bpp) init.front_pitch = init32.front_pitch;
|| __put_user(init32.front_offset, &init->front_offset) init.back_offset = init32.back_offset;
|| __put_user(init32.front_pitch, &init->front_pitch) init.back_pitch = init32.back_pitch;
|| __put_user(init32.back_offset, &init->back_offset) init.depth_bpp = init32.depth_bpp;
|| __put_user(init32.back_pitch, &init->back_pitch) init.depth_offset = init32.depth_offset;
|| __put_user(init32.depth_bpp, &init->depth_bpp) init.depth_pitch = init32.depth_pitch;
|| __put_user(init32.depth_offset, &init->depth_offset) init.span_offset = init32.span_offset;
|| __put_user(init32.depth_pitch, &init->depth_pitch) init.fb_offset = init32.fb_offset;
|| __put_user(init32.span_offset, &init->span_offset) init.mmio_offset = init32.mmio_offset;
|| __put_user(init32.fb_offset, &init->fb_offset) init.ring_offset = init32.ring_offset;
|| __put_user(init32.mmio_offset, &init->mmio_offset) init.ring_rptr_offset = init32.ring_rptr_offset;
|| __put_user(init32.ring_offset, &init->ring_offset) init.buffers_offset = init32.buffers_offset;
|| __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) init.agp_textures_offset = init32.agp_textures_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); return drm_ioctl_kernel(file, r128_cce_init, &init,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
} }
typedef struct drm_r128_depth32 { typedef struct drm_r128_depth32 {
@ -111,25 +108,19 @@ static int compat_r128_depth(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
drm_r128_depth32_t depth32; 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))) if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
return -EFAULT; return -EFAULT;
depth = compat_alloc_user_space(sizeof(*depth)); depth.func = depth32.func;
if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth)) depth.n = depth32.n;
|| __put_user(depth32.func, &depth->func) depth.x = compat_ptr(depth32.x);
|| __put_user(depth32.n, &depth->n) depth.y = compat_ptr(depth32.y);
|| __put_user((int __user *)(unsigned long)depth32.x, &depth->x) depth.buffer = compat_ptr(depth32.buffer);
|| __put_user((int __user *)(unsigned long)depth32.y, &depth->y) depth.mask = compat_ptr(depth32.mask);
|| __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);
return drm_ioctl_kernel(file, r128_cce_depth, &depth, DRM_AUTH);
} }
typedef struct drm_r128_stipple32 { typedef struct drm_r128_stipple32 {
@ -140,18 +131,14 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
drm_r128_stipple32_t stipple32; 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))) if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
return -EFAULT; return -EFAULT;
stipple = compat_alloc_user_space(sizeof(*stipple)); stipple.mask = compat_ptr(stipple32.mask);
if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
|| __put_user((unsigned int __user *)(unsigned long)stipple32.mask,
&stipple->mask))
return -EFAULT;
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 { typedef struct drm_r128_getparam32 {
@ -163,19 +150,15 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
drm_r128_getparam32_t getparam32; 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))) if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
return -EFAULT; return -EFAULT;
getparam = compat_alloc_user_space(sizeof(*getparam)); getparam.param = getparam32.param;
if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam)) getparam.value = compat_ptr(getparam32.value);
|| __put_user(getparam32.param, &getparam->param)
|| __put_user((void __user *)(unsigned long)getparam32.value,
&getparam->value))
return -EFAULT;
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[] = { drm_ioctl_compat_t *r128_compat_ioctls[] = {

View file

@ -1460,7 +1460,7 @@ static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *fi
return ret; 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_private_t *dev_priv = dev->dev_private;
drm_r128_depth_t *depth = data; 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; 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_private_t *dev_priv = dev->dev_private;
drm_r128_stipple_t *stipple = data; 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; 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_private_t *dev_priv = dev->dev_private;
drm_r128_getparam_t *param = data; drm_r128_getparam_t *param = data;

View file

@ -35,6 +35,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/compat.h>
/* /*
* An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a * 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, 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; u8 __user **data_ptrs;
int i, res; int i, res;
if (copy_from_user(&rdwr_arg, data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL);
(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);
if (data_ptrs == NULL) { if (data_ptrs == NULL) {
kfree(rdwr_pa); kfree(msgs);
return -ENOMEM; return -ENOMEM;
} }
res = 0; 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 */ /* Limit the size of the message to a sane amount */
if (rdwr_pa[i].len > 8192) { if (msgs[i].len > 8192) {
res = -EINVAL; res = -EINVAL;
break; break;
} }
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; data_ptrs[i] = (u8 __user *)msgs[i].buf;
rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len);
if (IS_ERR(rdwr_pa[i].buf)) { if (IS_ERR(msgs[i].buf)) {
res = PTR_ERR(rdwr_pa[i].buf); res = PTR_ERR(msgs[i].buf);
break; 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 * greater (for example to account for a checksum byte at
* the end of the message.) * the end of the message.)
*/ */
if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { if (msgs[i].flags & I2C_M_RECV_LEN) {
if (!(rdwr_pa[i].flags & I2C_M_RD) || if (!(msgs[i].flags & I2C_M_RD) ||
rdwr_pa[i].buf[0] < 1 || msgs[i].buf[0] < 1 ||
rdwr_pa[i].len < rdwr_pa[i].buf[0] + msgs[i].len < msgs[i].buf[0] +
I2C_SMBUS_BLOCK_MAX) { I2C_SMBUS_BLOCK_MAX) {
res = -EINVAL; res = -EINVAL;
break; break;
} }
rdwr_pa[i].len = rdwr_pa[i].buf[0]; msgs[i].len = msgs[i].buf[0];
} }
} }
if (res < 0) { if (res < 0) {
int j; int j;
for (j = 0; j < i; ++j) for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf); kfree(msgs[j].buf);
kfree(data_ptrs); kfree(data_ptrs);
kfree(rdwr_pa); kfree(msgs);
return res; return res;
} }
res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); res = i2c_transfer(client->adapter, msgs, nmsgs);
while (i-- > 0) { while (i-- > 0) {
if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { if (res >= 0 && (msgs[i].flags & I2C_M_RD)) {
if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, if (copy_to_user(data_ptrs[i], msgs[i].buf,
rdwr_pa[i].len)) msgs[i].len))
res = -EFAULT; res = -EFAULT;
} }
kfree(rdwr_pa[i].buf); kfree(msgs[i].buf);
} }
kfree(data_ptrs); kfree(data_ptrs);
kfree(rdwr_pa); kfree(msgs);
return res; return res;
} }
static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, 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 = {}; union i2c_smbus_data temp = {};
int datasize, res; int datasize, res;
if (copy_from_user(&data_arg, if ((size != I2C_SMBUS_BYTE) &&
(struct i2c_smbus_ioctl_data __user *) arg, (size != I2C_SMBUS_QUICK) &&
sizeof(struct i2c_smbus_ioctl_data))) (size != I2C_SMBUS_BYTE_DATA) &&
return -EFAULT; (size != I2C_SMBUS_WORD_DATA) &&
if ((data_arg.size != I2C_SMBUS_BYTE) && (size != I2C_SMBUS_PROC_CALL) &&
(data_arg.size != I2C_SMBUS_QUICK) && (size != I2C_SMBUS_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_BYTE_DATA) && (size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
(data_arg.size != I2C_SMBUS_WORD_DATA) && (size != I2C_SMBUS_I2C_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) && (size != I2C_SMBUS_BLOCK_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)) {
dev_dbg(&client->adapter->dev, dev_dbg(&client->adapter->dev,
"size out of range (%x) in ioctl I2C_SMBUS.\n", "size out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.size); size);
return -EINVAL; return -EINVAL;
} }
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size==I2C_SMBUS_QUICK too. */ so the check is valid if size==I2C_SMBUS_QUICK too. */
if ((data_arg.read_write != I2C_SMBUS_READ) && if ((read_write != I2C_SMBUS_READ) &&
(data_arg.read_write != I2C_SMBUS_WRITE)) { (read_write != I2C_SMBUS_WRITE)) {
dev_dbg(&client->adapter->dev, dev_dbg(&client->adapter->dev,
"read_write out of range (%x) in ioctl I2C_SMBUS.\n", "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.read_write); read_write);
return -EINVAL; return -EINVAL;
} }
/* Note that command values are always valid! */ /* Note that command values are always valid! */
if ((data_arg.size == I2C_SMBUS_QUICK) || if ((size == I2C_SMBUS_QUICK) ||
((data_arg.size == I2C_SMBUS_BYTE) && ((size == I2C_SMBUS_BYTE) &&
(data_arg.read_write == I2C_SMBUS_WRITE))) (read_write == I2C_SMBUS_WRITE)))
/* These are special: we do not use data */ /* These are special: we do not use data */
return i2c_smbus_xfer(client->adapter, client->addr, return i2c_smbus_xfer(client->adapter, client->addr,
client->flags, data_arg.read_write, client->flags, read_write,
data_arg.command, data_arg.size, NULL); command, size, NULL);
if (data_arg.data == NULL) { if (data == NULL) {
dev_dbg(&client->adapter->dev, dev_dbg(&client->adapter->dev,
"data is NULL pointer in ioctl I2C_SMBUS.\n"); "data is NULL pointer in ioctl I2C_SMBUS.\n");
return -EINVAL; return -EINVAL;
} }
if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || if ((size == I2C_SMBUS_BYTE_DATA) ||
(data_arg.size == I2C_SMBUS_BYTE)) (size == I2C_SMBUS_BYTE))
datasize = sizeof(data_arg.data->byte); datasize = sizeof(data->byte);
else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || else if ((size == I2C_SMBUS_WORD_DATA) ||
(data_arg.size == I2C_SMBUS_PROC_CALL)) (size == I2C_SMBUS_PROC_CALL))
datasize = sizeof(data_arg.data->word); datasize = sizeof(data->word);
else /* size == smbus block, i2c block, or block proc. call */ 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) || if ((size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || (size == I2C_SMBUS_I2C_BLOCK_DATA) ||
(data_arg.read_write == I2C_SMBUS_WRITE)) { (read_write == I2C_SMBUS_WRITE)) {
if (copy_from_user(&temp, data_arg.data, datasize)) if (copy_from_user(&temp, data, datasize))
return -EFAULT; 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 /* Convert old I2C block commands to the new
convention. This preserves binary compatibility. */ convention. This preserves binary compatibility. */
data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; size = I2C_SMBUS_I2C_BLOCK_DATA;
if (data_arg.read_write == I2C_SMBUS_READ) if (read_write == I2C_SMBUS_READ)
temp.block[0] = I2C_SMBUS_BLOCK_MAX; temp.block[0] = I2C_SMBUS_BLOCK_MAX;
} }
res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
data_arg.read_write, data_arg.command, data_arg.size, &temp); read_write, command, size, &temp);
if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || if (!res && ((size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || (size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.read_write == I2C_SMBUS_READ))) { (read_write == I2C_SMBUS_READ))) {
if (copy_to_user(data_arg.data, &temp, datasize)) if (copy_to_user(data, &temp, datasize))
return -EFAULT; return -EFAULT;
} }
return res; 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); funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg); return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR: case I2C_RDWR: {
return i2cdev_ioctl_rdwr(client, arg); struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_msg *rdwr_pa;
case I2C_SMBUS: if (copy_from_user(&rdwr_arg,
return i2cdev_ioctl_smbus(client, 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);
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: case I2C_RETRIES:
client->adapter->retries = arg; client->adapter->retries = arg;
break; break;
@ -480,6 +487,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0; 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) static int i2cdev_open(struct inode *inode, struct file *file)
{ {
unsigned int minor = iminor(inode); unsigned int minor = iminor(inode);
@ -527,6 +618,7 @@ static const struct file_operations i2cdev_fops = {
.read = i2cdev_read, .read = i2cdev_read,
.write = i2cdev_write, .write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl, .unlocked_ioctl = i2cdev_ioctl,
.compat_ioctl = compat_i2cdev_ioctl,
.open = i2cdev_open, .open = i2cdev_open,
.release = i2cdev_release, .release = i2cdev_release,
}; };

View file

@ -375,12 +375,7 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
return -EINVAL; return -EINVAL;
if (!mtd->_write_oob) if (!mtd->_write_oob)
ret = -EOPNOTSUPP; return -EOPNOTSUPP;
else
ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
if (ret)
return ret;
ops.ooblen = length; ops.ooblen = length;
ops.ooboffs = start & (mtd->writesize - 1); ops.ooboffs = start & (mtd->writesize - 1);
@ -419,9 +414,6 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
if (length > 4096) if (length > 4096)
return -EINVAL; return -EINVAL;
if (!access_ok(VERIFY_WRITE, ptr, length))
return -EFAULT;
ops.ooblen = length; ops.ooblen = length;
ops.ooboffs = start & (mtd->writesize - 1); ops.ooboffs = start & (mtd->writesize - 1);
ops.datbuf = NULL; 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_data = (const void __user *)(uintptr_t)req.usr_data;
usr_oob = (const void __user *)(uintptr_t)req.usr_oob; 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) if (!mtd->_write_oob)
return -EOPNOTSUPP; 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; struct mtd_info *mtd = mfi->mtd;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int ret = 0; int ret = 0;
u_long size;
struct mtd_info_user info; struct mtd_info_user info;
pr_debug("MTD_ioctl\n"); 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) { switch (cmd) {
case MEMGETREGIONCOUNT: case MEMGETREGIONCOUNT:
if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))

View file

@ -3393,12 +3393,6 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg,
goto out; 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); buf = kmalloc(ulen + cache_line_size() - 1, GFP_KERNEL);
if (unlikely(!buf)) { if (unlikely(!buf)) {
rc = -ENOMEM; rc = -ENOMEM;

View file

@ -762,32 +762,15 @@ abort:
static long static long
pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ {
int err = 0;
int retval = 0; int retval = 0;
struct pi433_instance *instance; struct pi433_instance *instance;
struct pi433_device *device; struct pi433_device *device;
u32 tmp; void __user *argp = (void __user *)arg;
/* Check type and command number */ /* Check type and command number */
if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC) if (_IOC_TYPE(cmd) != PI433_IOC_MAGIC)
return -ENOTTY; 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, /* TODO? guard against device removal before, or while,
* we issue this ioctl. --> device_get() * we issue this ioctl. --> device_get()
*/ */
@ -799,78 +782,33 @@ pi433_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
switch (cmd) { switch (cmd) {
case PI433_IOC_RD_TX_CFG: case PI433_IOC_RD_TX_CFG:
tmp = _IOC_SIZE(cmd); if (copy_to_user(argp, &instance->tx_cfg,
if ((tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0)) { sizeof(struct pi433_tx_cfg)))
retval = -EINVAL; return -EFAULT;
break;
}
if (__copy_to_user((void __user *)arg,
&instance->tx_cfg,
tmp))
{
retval = -EFAULT;
break;
}
break; break;
case PI433_IOC_WR_TX_CFG: case PI433_IOC_WR_TX_CFG:
tmp = _IOC_SIZE(cmd); if (copy_from_user(&instance->tx_cfg, argp,
if ((tmp == 0) || ((tmp % sizeof(struct pi433_tx_cfg)) != 0)) { sizeof(struct pi433_tx_cfg)))
retval = -EINVAL; return -EFAULT;
break; break;
}
if (__copy_from_user(&instance->tx_cfg,
(void __user *)arg,
tmp))
{
retval = -EFAULT;
break;
}
break;
case PI433_IOC_RD_RX_CFG: case PI433_IOC_RD_RX_CFG:
tmp = _IOC_SIZE(cmd); if (copy_to_user(argp, &device->rx_cfg,
if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { sizeof(struct pi433_rx_cfg)))
retval = -EINVAL; return -EFAULT;
break;
}
if (__copy_to_user((void __user *)arg,
&device->rx_cfg,
tmp))
{
retval = -EFAULT;
break;
}
break; break;
case PI433_IOC_WR_RX_CFG: case PI433_IOC_WR_RX_CFG:
tmp = _IOC_SIZE(cmd);
mutex_lock(&device->rx_lock); mutex_lock(&device->rx_lock);
/* during pendig read request, change of config not allowed */ /* during pendig read request, change of config not allowed */
if (device->rx_active) { if (device->rx_active) {
retval = -EAGAIN;
mutex_unlock(&device->rx_lock); mutex_unlock(&device->rx_lock);
break; return -EAGAIN;
} }
if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) { if (copy_from_user(&device->rx_cfg, argp,
retval = -EINVAL; sizeof(struct pi433_rx_cfg))) {
mutex_unlock(&device->rx_lock); mutex_unlock(&device->rx_lock);
break; return -EFAULT;
}
if (__copy_from_user(&device->rx_cfg,
(void __user *)arg,
tmp))
{
retval = -EFAULT;
mutex_unlock(&device->rx_lock);
break;
} }
mutex_unlock(&device->rx_lock); mutex_unlock(&device->rx_lock);

View file

@ -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) int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
{ {
struct vc_data *vc = vc_cons[fg_console].d; 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; char *bp, *obp;
int i, ps, pe, multiplier; int i, ps, pe, multiplier;
u16 c; u16 c;
int mode; int mode;
poke_blanked_console(); poke_blanked_console();
if (copy_from_user(&v, sel, sizeof(*sel)))
{ unsigned short xs, ys, xe, ye;
if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
return -EFAULT; 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) { 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 (v.sel_mode == TIOCL_SELCLEAR) {
/* useful for screendump without selection highlights */ /* useful for screendump without selection highlights */
clear_selection(); clear_selection();
return 0; return 0;
} }
if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) { if (mouse_reporting() && (v.sel_mode & TIOCL_SELMOUSEREPORT)) {
mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys); mouse_report(tty, v.sel_mode & TIOCL_SELBUTTONMASK, v.xs, v.ys);
return 0; return 0;
} }
}
if (ps > pe) /* make sel_start <= sel_end */ 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 else
use_unicode = 0; use_unicode = 0;
switch (sel_mode) switch (v.sel_mode)
{ {
case TIOCL_SELCHAR: /* character-by-character selection */ case TIOCL_SELCHAR: /* character-by-character selection */
new_sel_start = ps; new_sel_start = ps;

View file

@ -843,58 +843,44 @@ int vt_ioctl(struct tty_struct *tty,
case VT_RESIZEX: case VT_RESIZEX:
{ {
struct vt_consize __user *vtconsize = up; struct vt_consize v;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm) if (!perm)
return -EPERM; return -EPERM;
if (!access_ok(VERIFY_READ, vtconsize, if (copy_from_user(&v, up, sizeof(struct vt_consize)))
sizeof(struct vt_consize))) { return -EFAULT;
ret = -EFAULT;
break;
}
/* FIXME: Should check the copies properly */ /* FIXME: Should check the copies properly */
__get_user(ll, &vtconsize->v_rows); if (!v.v_vlin)
__get_user(cc, &vtconsize->v_cols); v.v_vlin = vc->vc_scan_lines;
__get_user(vlin, &vtconsize->v_vlin); if (v.v_clin) {
__get_user(clin, &vtconsize->v_clin); int rows = v.v_vlin/v.v_clin;
__get_user(vcol, &vtconsize->v_vcol); if (v.v_rows != rows) {
__get_user(ccol, &vtconsize->v_ccol); if (v.v_rows) /* Parameters don't add up */
vlin = vlin ? vlin : vc->vc_scan_lines; return -EINVAL;
if (clin) { v.v_rows = rows;
if (ll) {
if (ll != vlin/clin) {
/* Parameters don't add up */
ret = -EINVAL;
break;
} }
} else
ll = vlin/clin;
} }
if (vcol && ccol) { if (v.v_vcol && v.v_ccol) {
if (cc) { int cols = v.v_vcol/v.v_ccol;
if (cc != vcol/ccol) { if (v.v_cols != cols) {
ret = -EINVAL; if (v.v_cols)
break; return -EINVAL;
v.v_cols = cols;
} }
} else
cc = vcol/ccol;
} }
if (clin > 32) { if (v.v_clin > 32)
ret = -EINVAL; return -EINVAL;
break;
}
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons[i].d) if (!vc_cons[i].d)
continue; continue;
console_lock(); console_lock();
if (vlin) if (v.v_vlin)
vc_cons[i].d->vc_scan_lines = vlin; vc_cons[i].d->vc_scan_lines = v.v_vlin;
if (clin) if (v.v_clin)
vc_cons[i].d->vc_font.height = clin; vc_cons[i].d->vc_font.height = v.v_clin;
vc_cons[i].d->vc_resize_user = 1; 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(); console_unlock();
} }
break; break;

View file

@ -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, static long read_events(struct kioctx *ctx, long min_nr, long nr,
struct io_event __user *event, struct io_event __user *event,
struct timespec __user *timeout) ktime_t until)
{ {
ktime_t until = KTIME_MAX;
long ret = 0; 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. * 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 * 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; 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: /* io_getevents:
* Attempts to read at least min_nr events and up to nr events from * 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 * 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 io_event __user *, events,
struct timespec __user *, timeout) struct timespec __user *, timeout)
{ {
struct kioctx *ioctx = lookup_ioctx(ctx_id); struct timespec64 ts;
long ret = -EINVAL;
if (likely(ioctx)) { if (timeout) {
if (likely(min_nr <= nr && min_nr >= 0)) if (unlikely(get_timespec64(&ts, timeout)))
ret = read_events(ioctx, min_nr, nr, events, timeout); return -EFAULT;
percpu_ref_put(&ioctx->users);
} }
return ret;
return do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &ts : NULL);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
@ -1862,17 +1870,14 @@ COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
struct io_event __user *, events, struct io_event __user *, events,
struct compat_timespec __user *, timeout) struct compat_timespec __user *, timeout)
{ {
struct timespec t; struct timespec64 t;
struct timespec __user *ut = NULL;
if (timeout) { if (timeout) {
if (compat_get_timespec(&t, timeout)) if (compat_get_timespec64(&t, timeout))
return -EFAULT; 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 #endif

View file

@ -54,8 +54,6 @@
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/atalk.h> #include <linux/atalk.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/cec.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); 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 { struct compat_video_event {
int32_t type; int32_t type;
compat_time_t timestamp; compat_time_t timestamp;
@ -671,96 +653,6 @@ static int serial_struct_ioctl(struct file *file,
return err; 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_READ32 _IOR('p', 0x0b, compat_ulong_t)
#define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t) #define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t)
#define RTC_EPOCH_READ32 _IOR('p', 0x0d, 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_IO)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM) COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE) 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 */ /* hiddev */
COMPATIBLE_IOCTL(HIDIOCGVERSION) COMPATIBLE_IOCTL(HIDIOCGVERSION)
COMPATIBLE_IOCTL(HIDIOCAPPLICATION) COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@ -1464,13 +1349,6 @@ static long do_ioctl_trans(unsigned int cmd,
case TIOCGSERIAL: case TIOCGSERIAL:
case TIOCSSERIAL: case TIOCSSERIAL:
return serial_struct_ioctl(file, cmd, argp); 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 */ /* Not implemented in the native kernel */
case RTC_IRQP_READ32: case RTC_IRQP_READ32:
case RTC_IRQP_SET32: case RTC_IRQP_SET32:

View file

@ -680,16 +680,11 @@ void do_coredump(const siginfo_t *siginfo)
* privs and don't want to unlink another user's coredump. * privs and don't want to unlink another user's coredump.
*/ */
if (!need_suid_safe) { 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 * If it doesn't exist, that's fine. If there's some
* other problem, we'll catch it at the filp_open(). * other problem, we'll catch it at the filp_open().
*/ */
(void) sys_unlink((const char __user *)cn.corename); do_unlinkat(AT_FDCWD, getname_kernel(cn.corename));
set_fs(old_fs);
} }
/* /*

View file

@ -2259,7 +2259,6 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
compat_size_t, sigsetsize) compat_size_t, sigsetsize)
{ {
long err; long err;
compat_sigset_t csigmask;
sigset_t ksigmask, sigsaved; sigset_t ksigmask, sigsaved;
/* /*
@ -2269,9 +2268,8 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
if (sigmask) { if (sigmask) {
if (sigsetsize != sizeof(compat_sigset_t)) if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) if (get_compat_sigset(&ksigmask, sigmask))
return -EFAULT; return -EFAULT;
sigset_from_compat(&ksigmask, &csigmask);
sigsaved = current->blocked; sigsaved = current->blocked;
set_current_blocked(&ksigmask); set_current_blocked(&ksigmask);
} }

View file

@ -592,6 +592,44 @@ static int ext4_ioc_getfsmap(struct super_block *sb,
return 0; 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) long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
@ -776,44 +814,12 @@ mext_out:
case EXT4_IOC_GROUP_ADD: { case EXT4_IOC_GROUP_ADD: {
struct ext4_new_group_data input; 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, if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
sizeof(input))) { sizeof(input)))
err = -EFAULT; return -EFAULT;
goto group_add_out;
}
if (ext4_has_feature_bigalloc(sb)) { return ext4_ioctl_group_add(filp, &input);
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;
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;
} }
case EXT4_IOC_MIGRATE: case EXT4_IOC_MIGRATE:
@ -1078,8 +1084,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
case EXT4_IOC32_GROUP_ADD: { case EXT4_IOC32_GROUP_ADD: {
struct compat_ext4_new_group_input __user *uinput; struct compat_ext4_new_group_input __user *uinput;
struct ext4_new_group_input input; struct ext4_new_group_data input;
mm_segment_t old_fs;
int err; int err;
uinput = compat_ptr(arg); uinput = compat_ptr(arg);
@ -1092,12 +1097,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
&uinput->reserved_blocks); &uinput->reserved_blocks);
if (err) if (err)
return -EFAULT; return -EFAULT;
old_fs = get_fs(); return ext4_ioctl_group_add(file, &input);
set_fs(KERNEL_DS);
err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
(unsigned long) &input);
set_fs(old_fs);
return err;
} }
case EXT4_IOC_MOVE_EXT: case EXT4_IOC_MOVE_EXT:
case EXT4_IOC_RESIZE_FS: case EXT4_IOC_RESIZE_FS:

View file

@ -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 user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *, extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct path *); const char *, unsigned int, struct path *);
long do_unlinkat(int dfd, struct filename *name);
/* /*
* namespace.c * namespace.c

View file

@ -4010,10 +4010,9 @@ EXPORT_SYMBOL(vfs_unlink);
* writeout happening, and we don't want to prevent access to the directory * writeout happening, and we don't want to prevent access to the directory
* while waiting on the I/O. * 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; int error;
struct filename *name;
struct dentry *dentry; struct dentry *dentry;
struct path path; struct path path;
struct qstr last; struct qstr last;
@ -4022,8 +4021,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
struct inode *delegated_inode = NULL; struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0; unsigned int lookup_flags = 0;
retry: retry:
name = filename_parentat(dfd, getname(pathname), lookup_flags, name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
&path, &last, &type);
if (IS_ERR(name)) if (IS_ERR(name))
return PTR_ERR(name); return PTR_ERR(name);
@ -4065,12 +4063,12 @@ exit2:
mnt_drop_write(path.mnt); mnt_drop_write(path.mnt);
exit1: exit1:
path_put(&path); path_put(&path);
putname(name);
if (retry_estale(error, lookup_flags)) { if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL; lookup_flags |= LOOKUP_REVAL;
inode = NULL; inode = NULL;
goto retry; goto retry;
} }
putname(name);
return error; return error;
slashes: slashes:
@ -4091,12 +4089,12 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
if (flag & AT_REMOVEDIR) if (flag & AT_REMOVEDIR)
return do_rmdir(dfd, pathname); return do_rmdir(dfd, pathname);
return do_unlinkat(dfd, pathname); return do_unlinkat(dfd, getname(pathname));
} }
SYSCALL_DEFINE1(unlink, const char __user *, 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) int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)

View file

@ -292,8 +292,7 @@ static int poll_select_copy_remaining(struct timespec64 *end_time,
void __user *p, void __user *p,
int timeval, int ret) int timeval, int ret)
{ {
struct timespec64 rts64; struct timespec64 rts;
struct timespec rts;
struct timeval rtv; struct timeval rtv;
if (!p) 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) if (!end_time->tv_sec && !end_time->tv_nsec)
return ret; return ret;
ktime_get_ts64(&rts64); ktime_get_ts64(&rts);
rts64 = timespec64_sub(*end_time, rts64); rts = timespec64_sub(*end_time, rts);
if (rts64.tv_sec < 0) if (rts.tv_sec < 0)
rts64.tv_sec = rts64.tv_nsec = 0; rts.tv_sec = rts.tv_nsec = 0;
rts = timespec64_to_timespec(rts64);
if (timeval) { if (timeval) {
if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec))
memset(&rtv, 0, sizeof(rtv)); memset(&rtv, 0, sizeof(rtv));
rtv.tv_sec = rts64.tv_sec; rtv.tv_sec = rts.tv_sec;
rtv.tv_usec = rts64.tv_nsec / NSEC_PER_USEC; rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
if (!copy_to_user(p, &rtv, sizeof(rtv))) if (!copy_to_user(p, &rtv, sizeof(rtv)))
return ret; return ret;
} else if (!copy_to_user(p, &rts, sizeof(rts))) } else if (!put_timespec64(&rts, p))
return ret; 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) const sigset_t __user *sigmask, size_t sigsetsize)
{ {
sigset_t ksigmask, sigsaved; sigset_t ksigmask, sigsaved;
struct timespec ts; struct timespec64 ts, end_time, *to = NULL;
struct timespec64 ts64, end_time, *to = NULL;
int ret; int ret;
if (tsp) { if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts))) if (get_timespec64(&ts, tsp))
return -EFAULT; return -EFAULT;
ts64 = timespec_to_timespec64(ts);
to = &end_time; 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; return -EINVAL;
} }
@ -1052,12 +1048,11 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
size_t, sigsetsize) size_t, sigsetsize)
{ {
sigset_t ksigmask, sigsaved; sigset_t ksigmask, sigsaved;
struct timespec ts; struct timespec64 ts, end_time, *to = NULL;
struct timespec64 end_time, *to = NULL;
int ret; int ret;
if (tsp) { if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts))) if (get_timespec64(&ts, tsp))
return -EFAULT; return -EFAULT;
to = &end_time; 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)) #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
static 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) int timeval, int ret)
{ {
struct timespec ts; struct timespec64 ts;
if (!p) if (!p)
return ret; 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) if (!end_time->tv_sec && !end_time->tv_nsec)
return ret; return ret;
ktime_get_ts(&ts); ktime_get_ts64(&ts);
ts = timespec_sub(*end_time, ts); ts = timespec64_sub(*end_time, ts);
if (ts.tv_sec < 0) if (ts.tv_sec < 0)
ts.tv_sec = ts.tv_nsec = 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))) if (!copy_to_user(p, &rtv, sizeof(rtv)))
return ret; return ret;
} else { } else {
struct compat_timespec rts; if (!compat_put_timespec64(&ts, p))
rts.tv_sec = ts.tv_sec;
rts.tv_nsec = ts.tv_nsec;
if (!copy_to_user(p, &rts, sizeof(rts)))
return ret; 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, static int compat_core_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp, compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct timespec *end_time) struct timespec64 *end_time)
{ {
fd_set_bits fds; fd_set_bits fds;
void *bits; 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, compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
struct compat_timeval __user *, tvp) struct compat_timeval __user *, tvp)
{ {
struct timespec end_time, *to = NULL; struct timespec64 end_time, *to = NULL;
struct compat_timeval tv; struct compat_timeval tv;
int ret; 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, struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
compat_size_t sigsetsize) compat_size_t sigsetsize)
{ {
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved; sigset_t ksigmask, sigsaved;
struct compat_timespec ts; struct timespec64 ts, end_time, *to = NULL;
struct timespec end_time, *to = NULL;
int ret; int ret;
if (tsp) { if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts))) if (compat_get_timespec64(&ts, tsp))
return -EFAULT; return -EFAULT;
to = &end_time; to = &end_time;
@ -1330,9 +1318,8 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
if (sigmask) { if (sigmask) {
if (sigsetsize != sizeof(compat_sigset_t)) if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&ss32, sigmask, sizeof(ss32))) if (get_compat_sigset(&ksigmask, sigmask))
return -EFAULT; return -EFAULT;
sigset_from_compat(&ksigmask, &ss32);
sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); 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, unsigned int, nfds, struct compat_timespec __user *, tsp,
const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
{ {
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved; sigset_t ksigmask, sigsaved;
struct compat_timespec ts; struct timespec64 ts, end_time, *to = NULL;
struct timespec end_time, *to = NULL;
int ret; int ret;
if (tsp) { if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts))) if (compat_get_timespec64(&ts, tsp))
return -EFAULT; return -EFAULT;
to = &end_time; to = &end_time;
@ -1399,9 +1384,8 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
if (sigmask) { if (sigmask) {
if (sigsetsize != sizeof(compat_sigset_t)) if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&ss32, sigmask, sizeof(ss32))) if (get_compat_sigset(&ksigmask, sigmask))
return -EFAULT; return -EFAULT;
sigset_from_compat(&ksigmask, &ss32);
sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);

View file

@ -313,15 +313,13 @@ COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd,
compat_size_t, sigsetsize, compat_size_t, sigsetsize,
int, flags) int, flags)
{ {
compat_sigset_t ss32;
sigset_t tmp; sigset_t tmp;
sigset_t __user *ksigmask; sigset_t __user *ksigmask;
if (sigsetsize != sizeof(compat_sigset_t)) if (sigsetsize != sizeof(compat_sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&ss32, sigmask, sizeof(ss32))) if (get_compat_sigset(&tmp, sigmask))
return -EFAULT; return -EFAULT;
sigset_from_compat(&tmp, &ss32);
ksigmask = compat_alloc_user_space(sizeof(sigset_t)); ksigmask = compat_alloc_user_space(sizeof(sigset_t));
if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t))) if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
return -EFAULT; return -EFAULT;

View file

@ -444,11 +444,6 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs,
return lhs->tv_nsec - rhs->tv_nsec; 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, asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
struct timezone __user *tz); struct timezone __user *tz);
asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, 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); asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat); extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat);
extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set); 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, asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes,

View file

@ -367,24 +367,6 @@ COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t, pid, unsigned int, len,
return ret; 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, int get_compat_itimerspec64(struct itimerspec64 *its,
const struct compat_itimerspec __user *uits) const struct compat_itimerspec __user *uits)
{ {
@ -485,27 +467,44 @@ Efault:
return -EFAULT; return -EFAULT;
} }
void int
sigset_from_compat(sigset_t *set, const compat_sigset_t *compat) 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) { switch (_NSIG_WORDS) {
case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 );
case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 ); case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 );
case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 ); case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 );
case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 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 int
sigset_to_compat(compat_sigset_t *compat, const sigset_t *set) 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) { switch (_NSIG_WORDS) {
case 4: compat->sig[7] = (set->sig[3] >> 32); compat->sig[6] = set->sig[3]; case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3];
case 3: compat->sig[5] = (set->sig[2] >> 32); compat->sig[4] = set->sig[2]; case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2];
case 2: compat->sig[3] = (set->sig[1] >> 32); compat->sig[2] = set->sig[1]; case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1];
case 1: compat->sig[1] = (set->sig[0] >> 32); compat->sig[0] = set->sig[0]; 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 #ifdef CONFIG_NUMA
@ -563,22 +562,6 @@ COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid,
} }
#endif #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, * Allocate user-space memory for the duration of a single system call,
* in order to marshall parameters inside a compat thunk. * in order to marshall parameters inside a compat thunk.

View file

@ -16,6 +16,7 @@
#include <linux/init_task.h> #include <linux/init_task.h>
#include <linux/context_tracking.h> #include <linux/context_tracking.h>
#include <linux/rcupdate_wait.h> #include <linux/rcupdate_wait.h>
#include <linux/compat.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/kprobes.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, * Return: On success, 0 and the timeslice is in @interval. Otherwise,
* an error code. * an error code.
*/ */
SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, static int sched_rr_get_interval(pid_t pid, struct timespec64 *t)
struct timespec __user *, interval)
{ {
struct task_struct *p; struct task_struct *p;
unsigned int time_slice; unsigned int time_slice;
struct rq_flags rf; struct rq_flags rf;
struct timespec t;
struct rq *rq; struct rq *rq;
int retval; int retval;
@ -5137,15 +5136,40 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
task_rq_unlock(rq, p, &rf); task_rq_unlock(rq, p, &rf);
rcu_read_unlock(); rcu_read_unlock();
jiffies_to_timespec(time_slice, &t); jiffies_to_timespec64(time_slice, t);
retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; return 0;
return retval;
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
return retval; 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) void sched_show_task(struct task_struct *p)
{ {
unsigned long free = 0; unsigned long free = 0;

View file

@ -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_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset,
compat_sigset_t __user *, oset, compat_size_t, sigsetsize) compat_sigset_t __user *, oset, compat_size_t, sigsetsize)
{ {
#ifdef __BIG_ENDIAN
sigset_t old_set = current->blocked; sigset_t old_set = current->blocked;
/* XXX: Don't preclude handling different sized sigset_t's. */ /* 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; return -EINVAL;
if (nset) { if (nset) {
compat_sigset_t new32;
sigset_t new_set; sigset_t new_set;
int error; int error;
if (copy_from_user(&new32, nset, sizeof(compat_sigset_t))) if (get_compat_sigset(&new_set, nset))
return -EFAULT; return -EFAULT;
sigset_from_compat(&new_set, &new32);
sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
error = sigprocmask(how, &new_set, NULL); error = sigprocmask(how, &new_set, NULL);
if (error) if (error)
return error; return error;
} }
if (oset) { return oset ? put_compat_sigset(oset, &old_set, sizeof(*oset)) : 0;
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
} }
#endif #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(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
sigorsets(set, &current->pending.signal, sigorsets(set, &current->pending.signal,
&current->signal->shared_pending.signal); &current->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) SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize)
{ {
sigset_t set; 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)) if (!err && copy_to_user(uset, &set, sigsetsize))
err = -EFAULT; err = -EFAULT;
return err; 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_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
compat_size_t, sigsetsize) compat_size_t, sigsetsize)
{ {
#ifdef __BIG_ENDIAN
sigset_t set; sigset_t set;
int err = do_sigpending(&set, sigsetsize); int err;
if (!err) {
compat_sigset_t set32; if (sigsetsize > sizeof(*uset))
sigset_to_compat(&set32, &set); return -EINVAL;
/* we can get here only if sigsetsize <= sizeof(set) */
if (copy_to_user(uset, &set32, sigsetsize)) err = do_sigpending(&set);
err = -EFAULT; if (!err)
} err = put_compat_sigset(uset, &set, sigsetsize);
return err; return err;
#else
return sys_rt_sigpending((sigset_t __user *)uset, sigsetsize);
#endif
} }
#endif #endif
@ -2915,7 +2899,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
struct compat_siginfo __user *, uinfo, struct compat_siginfo __user *, uinfo,
struct compat_timespec __user *, uts, compat_size_t, sigsetsize) struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
{ {
compat_sigset_t s32;
sigset_t s; sigset_t s;
struct timespec t; struct timespec t;
siginfo_t info; siginfo_t info;
@ -2924,9 +2907,8 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
if (sigsetsize != sizeof(sigset_t)) if (sigsetsize != sizeof(sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) if (get_compat_sigset(&s, uthese))
return -EFAULT; return -EFAULT;
sigset_from_compat(&s, &s32);
if (uts) { if (uts) {
if (compat_get_timespec(&t, uts)) if (compat_get_timespec(&t, uts))
@ -3344,15 +3326,11 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32) COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32)
{ {
#ifdef __BIG_ENDIAN
sigset_t set; sigset_t set;
int err = do_sigpending(&set, sizeof(set.sig[0])); int err = do_sigpending(&set);
if (!err) if (!err)
err = put_user(set.sig[0], set32); err = put_user(set.sig[0], set32);
return err; return err;
#else
return sys_rt_sigpending((sigset_t __user *)set32, sizeof(*set32));
#endif
} }
#endif #endif
@ -3450,7 +3428,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
compat_size_t, sigsetsize) compat_size_t, sigsetsize)
{ {
struct k_sigaction new_ka, old_ka; struct k_sigaction new_ka, old_ka;
compat_sigset_t mask;
#ifdef __ARCH_HAS_SA_RESTORER #ifdef __ARCH_HAS_SA_RESTORER
compat_uptr_t restorer; compat_uptr_t restorer;
#endif #endif
@ -3468,19 +3445,18 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
ret |= get_user(restorer, &act->sa_restorer); ret |= get_user(restorer, &act->sa_restorer);
new_ka.sa.sa_restorer = compat_ptr(restorer); new_ka.sa.sa_restorer = compat_ptr(restorer);
#endif #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); ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
if (ret) if (ret)
return -EFAULT; return -EFAULT;
sigset_from_compat(&new_ka.sa.sa_mask, &mask);
} }
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) { if (!ret && oact) {
sigset_to_compat(&mask, &old_ka.sa.sa_mask);
ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), ret = put_user(ptr_to_compat(old_ka.sa.sa_handler),
&oact->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); ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
#ifdef __ARCH_HAS_SA_RESTORER #ifdef __ARCH_HAS_SA_RESTORER
ret |= put_user(ptr_to_compat(old_ka.sa.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 #ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_size_t, sigsetsize) COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_size_t, sigsetsize)
{ {
#ifdef __BIG_ENDIAN
sigset_t newset; sigset_t newset;
compat_sigset_t newset32;
/* XXX: Don't preclude handling different sized sigset_t's. */ /* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t)) if (sigsetsize != sizeof(sigset_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) if (get_compat_sigset(&newset, unewset))
return -EFAULT; return -EFAULT;
sigset_from_compat(&newset, &newset32);
return sigsuspend(&newset); return sigsuspend(&newset);
#else
/* on little-endian bitmaps don't care about granularity */
return sys_rt_sigsuspend((sigset_t __user *)unewset, sigsetsize);
#endif
} }
#endif #endif

View file

@ -2724,7 +2724,6 @@ static long kvm_vcpu_compat_ioctl(struct file *filp,
case KVM_SET_SIGNAL_MASK: { case KVM_SET_SIGNAL_MASK: {
struct kvm_signal_mask __user *sigmask_arg = argp; struct kvm_signal_mask __user *sigmask_arg = argp;
struct kvm_signal_mask kvm_sigmask; struct kvm_signal_mask kvm_sigmask;
compat_sigset_t csigset;
sigset_t sigset; sigset_t sigset;
if (argp) { if (argp) {
@ -2733,13 +2732,11 @@ static long kvm_vcpu_compat_ioctl(struct file *filp,
sizeof(kvm_sigmask))) sizeof(kvm_sigmask)))
goto out; goto out;
r = -EINVAL; r = -EINVAL;
if (kvm_sigmask.len != sizeof(csigset)) if (kvm_sigmask.len != sizeof(compat_sigset_t))
goto out; goto out;
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&csigset, sigmask_arg->sigset, if (get_compat_sigset(&sigset, (void *)sigmask_arg->sigset))
sizeof(csigset)))
goto out; goto out;
sigset_from_compat(&sigset, &csigset);
r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
} else } else
r = kvm_vcpu_ioctl_set_sigmask(vcpu, NULL); r = kvm_vcpu_ioctl_set_sigmask(vcpu, NULL);