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:
commit
93f30c73ec
32 changed files with 506 additions and 819 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
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(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 {
|
||||
|
@ -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[] = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
case I2C_SMBUS:
|
||||
return i2cdev_ioctl_smbus(client, arg);
|
||||
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);
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -762,32 +762,15 @@ pi433_write(struct file *filp, const char __user *buf,
|
|||
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;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if ( (tmp == 0) || ((tmp % sizeof(struct pi433_rx_cfg)) != 0) ) {
|
||||
retval = -EINVAL;
|
||||
if (copy_from_user(&device->rx_cfg, argp,
|
||||
sizeof(struct pi433_rx_cfg))) {
|
||||
mutex_unlock(&device->rx_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (__copy_from_user(&device->rx_cfg,
|
||||
(void __user *)arg,
|
||||
tmp))
|
||||
{
|
||||
retval = -EFAULT;
|
||||
mutex_unlock(&device->rx_lock);
|
||||
break;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mutex_unlock(&device->rx_lock);
|
||||
|
|
|
@ -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();
|
||||
|
||||
{ unsigned short xs, ys, xe, ye;
|
||||
|
||||
if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
|
||||
if (copy_from_user(&v, 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;
|
||||
}
|
||||
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 (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;
|
||||
|
|
|
@ -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;
|
||||
|
|
55
fs/aio.c
55
fs/aio.c
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
|
||||
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;
|
||||
}
|
||||
sizeof(input)))
|
||||
return -EFAULT;
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
|
|
|
@ -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
|
||||
|
|
12
fs/namei.c
12
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 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
|||
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)
|
||||
|
|
68
fs/select.c
68
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
|
|||
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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue