Commit a7a905fa authored by David S. Miller's avatar David S. Miller

[NET]: Fix sock_fprog setsockopt compat handling. Based upon patch from Andi Kleen.

parent 13d6a99c
...@@ -672,21 +672,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) ...@@ -672,21 +672,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
return err; return err;
} }
static inline void *alloc_user_space(long len)
{
struct pt_regs *regs = current->thread.regs;
unsigned long usp = regs->gpr[1];
/*
* We cant access below the stack pointer in the 32bit ABI and
* can access 288 bytes in the 64bit ABI
*/
if (!(test_thread_flag(TIF_32BIT)))
usp -= 288;
return (void *) (usp - len);
}
int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct ifreq *u_ifreq64; struct ifreq *u_ifreq64;
...@@ -702,7 +687,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -702,7 +687,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return -EFAULT; return -EFAULT;
data64 = A(data32); data64 = A(data32);
u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64)); u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
/* Don't check these user accesses, just let that get trapped /* Don't check these user accesses, just let that get trapped
* in the ioctl handler instead. * in the ioctl handler instead.
......
...@@ -659,17 +659,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) ...@@ -659,17 +659,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
return err; return err;
} }
static __inline__ void *alloc_user_space(long len)
{
struct pt_regs *regs = current_thread_info()->kregs;
unsigned long usp = regs->u_regs[UREG_I6];
if (!(test_thread_flag(TIF_32BIT)))
usp += STACK_BIAS;
return (void *) (usp - len);
}
int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct ifreq *u_ifreq64; struct ifreq *u_ifreq64;
...@@ -685,7 +674,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -685,7 +674,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return -EFAULT; return -EFAULT;
data64 = A(data32); data64 = A(data32);
u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64)); u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
/* Don't check these user accesses, just let that get trapped /* Don't check these user accesses, just let that get trapped
* in the ioctl handler instead. * in the ioctl handler instead.
...@@ -1701,7 +1690,7 @@ struct sock_fprog32 { ...@@ -1701,7 +1690,7 @@ struct sock_fprog32 {
static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg; struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog)); struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
void __user *fptr64; void __user *fptr64;
u32 fptr32; u32 fptr32;
u16 flen; u16 flen;
......
...@@ -671,12 +671,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) ...@@ -671,12 +671,6 @@ static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
return err; return err;
} }
static __inline__ void *alloc_user_space(long len)
{
struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs);
return (void *)regs->rsp - len;
}
int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct ifreq *u_ifreq64; struct ifreq *u_ifreq64;
...@@ -692,7 +686,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) ...@@ -692,7 +686,7 @@ int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return -EFAULT; return -EFAULT;
data64 = (void *) A(data32); data64 = (void *) A(data32);
u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64)); u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
/* Don't check these user accesses, just let that get trapped /* Don't check these user accesses, just let that get trapped
* in the ioctl handler instead. * in the ioctl handler instead.
...@@ -1573,7 +1567,7 @@ struct sock_fprog32 { ...@@ -1573,7 +1567,7 @@ struct sock_fprog32 {
static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg; struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog)); struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
void *fptr64; void *fptr64;
u32 fptr32; u32 fptr32;
u16 flen; u16 flen;
......
...@@ -119,4 +119,19 @@ static inline void *compat_ptr(compat_uptr_t uptr) ...@@ -119,4 +119,19 @@ static inline void *compat_ptr(compat_uptr_t uptr)
return (void *)(unsigned long)uptr; return (void *)(unsigned long)uptr;
} }
static inline void *compat_alloc_user_space(long len)
{
struct pt_regs *regs = current->thread.regs;
unsigned long usp = regs->gpr[1];
/*
* We cant access below the stack pointer in the 32bit ABI and
* can access 288 bytes in the 64bit ABI
*/
if (!(test_thread_flag(TIF_32BIT)))
usp -= 288;
return (void *) (usp - len);
}
#endif /* _ASM_PPC64_COMPAT_H */ #endif /* _ASM_PPC64_COMPAT_H */
...@@ -120,4 +120,15 @@ static inline void *compat_ptr(compat_uptr_t uptr) ...@@ -120,4 +120,15 @@ static inline void *compat_ptr(compat_uptr_t uptr)
return (void *)(unsigned long)uptr; return (void *)(unsigned long)uptr;
} }
static __inline__ void *compat_alloc_user_space(long len)
{
struct pt_regs *regs = current_thread_info()->kregs;
unsigned long usp = regs->u_regs[UREG_I6];
if (!(test_thread_flag(TIF_32BIT)))
usp += STACK_BIAS;
return (void *) (usp - len);
}
#endif /* _ASM_SPARC64_COMPAT_H */ #endif /* _ASM_SPARC64_COMPAT_H */
...@@ -128,4 +128,10 @@ static inline void *compat_ptr(compat_uptr_t uptr) ...@@ -128,4 +128,10 @@ static inline void *compat_ptr(compat_uptr_t uptr)
return (void *)(unsigned long)uptr; return (void *)(unsigned long)uptr;
} }
static __inline__ void *compat_alloc_user_space(long len)
{
struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs);
return (void *)regs->rsp - len;
}
#endif /* _ASM_X86_64_COMPAT_H */ #endif /* _ASM_X86_64_COMPAT_H */
...@@ -389,30 +389,20 @@ static int do_set_attach_filter(int fd, int level, int optname, ...@@ -389,30 +389,20 @@ static int do_set_attach_filter(int fd, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval; struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval;
struct sock_fprog kfprog; struct sock_fprog *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
mm_segment_t old_fs;
int ret;
compat_uptr_t ptr; compat_uptr_t ptr;
u16 len;
if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) || if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
__get_user(kfprog.len, &fprog32->len) || !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
__get_user(ptr, &fprog32->filter)) __get_user(len, &fprog32->len) ||
return -EFAULT; __get_user(ptr, &fprog32->filter) ||
kfprog.filter = compat_ptr(ptr); __put_user(len, &kfprog->len) ||
__put_user(compat_ptr(ptr), &kfprog->filter))
if (kfprog.len * sizeof(struct sock_filter) < kfprog.len)
return -EINVAL;
if (verify_area(VERIFY_READ, kfprog.filter,
kfprog.len * sizeof(struct sock_filter)))
return -EFAULT; return -EFAULT;
old_fs = get_fs(); return sys_setsockopt(fd, level, optname, (char *)kfprog,
set_fs(KERNEL_DS); sizeof(struct sock_fprog));
ret = sys_setsockopt(fd, level, optname,
(char *)&kfprog, sizeof(kfprog));
set_fs(old_fs);
return ret;
} }
static int do_set_icmpv6_filter(int fd, int level, int optname, static int do_set_icmpv6_filter(int fd, int level, int optname,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment