Commit 82c1f12a authored by Stephen Rothwell's avatar Stephen Rothwell Committed by David S. Miller

[COMPAT] cleanups in net/compat.c and related files

parent 83a0e2be
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <net/compat.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/delay.h> #include <asm/delay.h>
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
/* For SOCKET_I */ /* For SOCKET_I */
#include <linux/socket.h> #include <linux/socket.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/compat.h>
/* Use this to get at 32-bit user passed pointers. */ /* Use this to get at 32-bit user passed pointers. */
#define A(__x) \ #define A(__x) \
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <net/compat.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/string.h> #include <asm/string.h>
......
...@@ -43,11 +43,9 @@ extern int get_compat_timespec(struct timespec *, struct compat_timespec *); ...@@ -43,11 +43,9 @@ extern int get_compat_timespec(struct timespec *, struct compat_timespec *);
extern int put_compat_timespec(struct timespec *, struct compat_timespec *); extern int put_compat_timespec(struct timespec *, struct compat_timespec *);
struct compat_iovec { struct compat_iovec {
u32 iov_base; compat_uptr_t iov_base;
compat_size_t iov_len; compat_size_t iov_len;
}; };
#else /* no CONFIG_COMPAT */
#define compat_size_t size_t
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */ #endif /* _LINUX_COMPAT_H */
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
#include <linux/config.h> /* for CONFIG_COMPAT */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/socket.h> /* arch-dependent defines */ #include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */ #include <linux/sockios.h> /* the SIOCxxx I/O controls */
...@@ -239,18 +240,10 @@ struct ucred { ...@@ -239,18 +240,10 @@ struct ucred {
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ #define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
#else #else
#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
#define compat_msghdr msghdr /* Needed to avoid compiler hoops */
#endif #endif
struct compat_msghdr;
extern int msghdr_from_user_compat_to_kern(struct msghdr *, struct compat_msghdr *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags); extern asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned flags); extern asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned flags);
extern asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char *optval, int *optlen);
...@@ -295,10 +288,6 @@ extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int le ...@@ -295,10 +288,6 @@ extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int le
extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen); extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr); extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
extern int put_cmsg_compat(struct msghdr*, int level, int type, int len, void *data);
extern void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr);
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
unsigned char *stackbuf, int stackbuf_size);
#endif #endif
#endif /* not kernel and not glibc */ #endif /* not kernel and not glibc */
......
#ifndef NET_COMPAT_H
#define NET_COMPAT_H
#include <linux/config.h>
#if defined(CONFIG_COMPAT)
#include <linux/compat.h>
struct compat_msghdr {
compat_uptr_t msg_name;
s32 msg_namelen;
compat_uptr_t msg_iov;
compat_size_t msg_iovlen;
compat_uptr_t msg_control;
compat_size_t msg_controllen;
u32 msg_flags;
};
struct compat_cmsghdr {
compat_size_t cmsg_len;
s32 cmsg_level;
s32 cmsg_type;
};
#else /* defined(CONFIG_COMPAT) */
#define compat_msghdr msghdr /* to avoid compiler warnings */
#endif /* defined(CONFIG_COMPAT) */
extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned);
extern asmlinkage long compat_sys_getsockopt(int, int, int, char *, int *);
extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
extern int put_compat_msg_controllen(struct msghdr *, struct compat_msghdr *,
unsigned long);
extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, unsigned char *,
int);
#endif /* NET_COMPAT_H */
#ifndef NET_COMPAT_SOCKET_H
#define NET_COMPAT_SOCKET_H 1
#include <linux/compat.h>
#if defined(CONFIG_COMPAT)
/* XXX This really belongs in some header file... -DaveM */
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
16 for IP, 16 for IPX,
24 for IPv6,
about 80 for AX.25 */
struct compat_msghdr {
u32 msg_name;
int msg_namelen;
u32 msg_iov;
compat_size_t msg_iovlen;
u32 msg_control;
compat_size_t msg_controllen;
unsigned msg_flags;
};
struct compat_cmsghdr {
compat_size_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
/* Bleech... */
#define __CMSG_COMPAT_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg_compat_nxthdr((ctl),(len),(cmsg),(cmsglen))
#define CMSG_COMPAT_NXTHDR(mhdr, cmsg, cmsglen) cmsg_compat_nxthdr((mhdr), (cmsg), (cmsglen))
#define CMSG_COMPAT_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
#define CMSG_COMPAT_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
#define CMSG_COMPAT_SPACE(len) (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
#define CMSG_COMPAT_LEN(len) (CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
#define __CMSG_COMPAT_FIRSTHDR(ctl,len) ((len) >= sizeof(struct compat_cmsghdr) ? \
(struct compat_cmsghdr *)(ctl) : \
(struct compat_cmsghdr *)NULL)
#define CMSG_COMPAT_FIRSTHDR(msg) __CMSG_COMPAT_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
static __inline__ struct compat_cmsghdr *__cmsg_compat_nxthdr(void *__ctl, __kernel_size_t __size,
struct compat_cmsghdr *__cmsg, int __cmsg_len)
{
struct compat_cmsghdr * __ptr;
__ptr = (struct compat_cmsghdr *)(((unsigned char *) __cmsg) +
CMSG_COMPAT_ALIGN(__cmsg_len));
if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
return NULL;
return __ptr;
}
static __inline__ struct compat_cmsghdr *cmsg_compat_nxthdr (struct msghdr *__msg,
struct compat_cmsghdr *__cmsg,
int __cmsg_len)
{
return __cmsg_compat_nxthdr(__msg->msg_control, __msg->msg_controllen,
__cmsg, __cmsg_len);
}
#endif /* CONFIG_COMPAT */
#endif
...@@ -25,14 +25,10 @@ ...@@ -25,14 +25,10 @@
#include <net/scm.h> #include <net/scm.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/compat_socket.h> #include <net/compat.h>
#define AA(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x))
extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
void * optval, int *optlen);
static inline int iov_from_user_compat_to_kern(struct iovec *kiov, static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
struct compat_iovec *uiov32, struct compat_iovec *uiov32,
int niov) int niov)
...@@ -40,7 +36,8 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, ...@@ -40,7 +36,8 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
int tot_len = 0; int tot_len = 0;
while(niov > 0) { while(niov > 0) {
u32 len, buf; compat_uptr_t buf;
compat_size_t len;
if(get_user(len, &uiov32->iov_len) || if(get_user(len, &uiov32->iov_len) ||
get_user(buf, &uiov32->iov_base)) { get_user(buf, &uiov32->iov_base)) {
...@@ -57,27 +54,23 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, ...@@ -57,27 +54,23 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
return tot_len; return tot_len;
} }
int msghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct compat_msghdr *umsg) int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr *umsg)
{ {
compat_uptr_t tmp1, tmp2, tmp3; compat_uptr_t tmp1, tmp2, tmp3;
int err;
err = get_user(tmp1, &umsg->msg_name); if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
err |= __get_user(tmp2, &umsg->msg_iov); __get_user(tmp1, &umsg->msg_name) ||
err |= __get_user(tmp3, &umsg->msg_control); __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
if (err) __get_user(tmp2, &umsg->msg_iov) ||
__get_user(kmsg->msg_iovlen, &umsg->msg_iovlen) ||
__get_user(tmp3, &umsg->msg_control) ||
__get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
__get_user(kmsg->msg_flags, &umsg->msg_flags))
return -EFAULT; return -EFAULT;
kmsg->msg_name = compat_ptr(tmp1); kmsg->msg_name = compat_ptr(tmp1);
kmsg->msg_iov = compat_ptr(tmp2); kmsg->msg_iov = compat_ptr(tmp2);
kmsg->msg_control = compat_ptr(tmp3); kmsg->msg_control = compat_ptr(tmp3);
return 0;
err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
return err;
} }
/* I've named the args so it is easy to tell whose space the pointers are in. */ /* I've named the args so it is easy to tell whose space the pointers are in. */
...@@ -116,6 +109,34 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, ...@@ -116,6 +109,34 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
return tot_len; return tot_len;
} }
/* Bleech... */
#define CMSG_COMPAT_ALIGN(len) ALIGN((len), sizeof(s32))
#define CMSG_COMPAT_DATA(cmsg) \
((void *)((char *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
#define CMSG_COMPAT_SPACE(len) \
(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
#define CMSG_COMPAT_LEN(len) \
(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
#define CMSG_COMPAT_FIRSTHDR(msg) \
(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ? \
(struct compat_cmsghdr *)((msg)->msg_control) : \
(struct compat_cmsghdr *)NULL)
static inline struct compat_cmsghdr *cmsg_compat_nxthdr(struct msghdr *msg,
struct compat_cmsghdr *cmsg, int cmsg_len)
{
struct compat_cmsghdr *ptr;
ptr = (struct compat_cmsghdr *)(((unsigned char *)cmsg) +
CMSG_COMPAT_ALIGN(cmsg_len));
if ((unsigned long)((char *)(ptr + 1) - (char *)msg->msg_control) >
msg->msg_controllen)
return NULL;
return ptr;
}
/* There is a lot of hair here because the alignment rules (and /* There is a lot of hair here because the alignment rules (and
* thus placement) of cmsg headers and length are different for * thus placement) of cmsg headers and length are different for
* 32-bit apps. -DaveM * 32-bit apps. -DaveM
...@@ -146,7 +167,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, ...@@ -146,7 +167,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr))); CMSG_ALIGN(sizeof(struct cmsghdr)));
kcmlen += tmp; kcmlen += tmp;
ucmsg = CMSG_COMPAT_NXTHDR(kmsg, ucmsg, ucmlen); ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
} }
if(kcmlen == 0) if(kcmlen == 0)
return -EINVAL; return -EINVAL;
...@@ -180,7 +201,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, ...@@ -180,7 +201,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
/* Advance. */ /* Advance. */
kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
ucmsg = CMSG_COMPAT_NXTHDR(kmsg, ucmsg, ucmlen); ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
} }
/* Ok, looks like we made it. Hook it up and return success. */ /* Ok, looks like we made it. Hook it up and return success. */
...@@ -303,7 +324,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) ...@@ -303,7 +324,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
* IPV6_RTHDR ipv6 routing exthdr 32-bit clean * IPV6_RTHDR ipv6 routing exthdr 32-bit clean
* IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean
*/ */
void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) static void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
{ {
unsigned char *workbuf, *wp; unsigned char *workbuf, *wp;
unsigned long bufsz, space_avail; unsigned long bufsz, space_avail;
...@@ -364,112 +385,133 @@ void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr ...@@ -364,112 +385,133 @@ void cmsg_compat_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr
kmsg->msg_control = (void *) orig_cmsg_uptr; kmsg->msg_control = (void *) orig_cmsg_uptr;
} }
int put_compat_msg_controllen(struct msghdr *msg_sys,
struct compat_msghdr *msg_compat, unsigned long cmsg_ptr)
{
unsigned long ucmsg_ptr;
compat_size_t uclen;
if ((unsigned long)msg_sys->msg_control != cmsg_ptr)
cmsg_compat_recvmsg_fixup(msg_sys, cmsg_ptr);
ucmsg_ptr = ((unsigned long)msg_sys->msg_control);
uclen = (compat_size_t) (ucmsg_ptr - cmsg_ptr);
return __put_user(uclen, &msg_compat->msg_controllen);
}
extern asmlinkage long sys_setsockopt(int fd, int level, int optname, extern asmlinkage long sys_setsockopt(int fd, int level, int optname,
char *optval, int optlen); char *optval, int optlen);
/*
* For now, we assume that the compatibility and native version
* of struct ipt_entry are the same - sfr. FIXME
*/
struct compat_ipt_replace {
char name[IPT_TABLE_MAXNAMELEN];
u32 valid_hooks;
u32 num_entries;
u32 size;
u32 hook_entry[NF_IP_NUMHOOKS];
u32 underflow[NF_IP_NUMHOOKS];
u32 num_counters;
compat_uptr_t counters; /* struct ipt_counters * */
struct ipt_entry entries[0];
};
static int do_netfilter_replace(int fd, int level, int optname, static int do_netfilter_replace(int fd, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct ipt_replace32 { struct compat_ipt_replace *urepl = (struct compat_ipt_replace *)optval;
char name[IPT_TABLE_MAXNAMELEN];
__u32 valid_hooks;
__u32 num_entries;
__u32 size;
__u32 hook_entry[NF_IP_NUMHOOKS];
__u32 underflow[NF_IP_NUMHOOKS];
__u32 num_counters;
__u32 counters;
struct ipt_entry entries[0];
} *repl32 = (struct ipt_replace32 *)optval;
struct ipt_replace *krepl; struct ipt_replace *krepl;
struct ipt_counters *counters32; struct ipt_counters *ucounters;
__u32 origsize; u32 origsize;
unsigned int kreplsize, kcountersize; unsigned int kreplsize;
mm_segment_t old_fs; mm_segment_t old_fs;
int ret; int ret;
int i;
compat_uptr_t ucntrs;
if (optlen < sizeof(repl32)) if (get_user(origsize, &urepl->size))
return -EINVAL;
if (copy_from_user(&origsize,
&repl32->size,
sizeof(origsize)))
return -EFAULT; return -EFAULT;
kreplsize = sizeof(*krepl) + origsize;
kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
/* Hack: Causes ipchains to give correct error msg --RR */ /* Hack: Causes ipchains to give correct error msg --RR */
if (optlen != kreplsize) if (optlen != sizeof(*urepl) + origsize)
return -ENOPROTOOPT; return -ENOPROTOOPT;
kreplsize = sizeof(*krepl) + origsize - num_entries *
(sizeof(struct compat_ipt_entry) - sizeof(struct ipt_entry));
krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL); krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
if (krepl == NULL) if (krepl == NULL)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(krepl, optval, kreplsize)) { ret = -EFAULT;
kfree(krepl); krepl->size = origsize;
return -EFAULT; if (!access_ok(VERIFY_READ, urepl, optlen) ||
__copy_from_user(krepl->name, urepl->name, sizeof(urepl->name)) ||
__get_user(krepl->valid_hooks, &urepl->valid_hooks) ||
__get_user(krepl->num_entries, &urepl->num_entries) ||
__get_user(krepl->num_counters, &urepl->num_counters) ||
__get_user(ucntrs, &urepl->counters) ||
__copy_from_user(krepl->entries, &urepl->entries, origsize))
goto out_free;
for (i = 0; i < NF_IP_NUM_HOOKS; i++) {
if (__get_user(krepl->hook_entry[i], &urepl->hook_entry[i]) ||
__get_user(krepl->underflow[i], &urepl->underflow[i]))
goto out_free;
} }
counters32 = (struct ipt_counters *)AA( /*
((struct ipt_replace32 *)krepl)->counters); * Since struct ipt_counters just contains two u_int64_t members
* we can just do the access_ok check here and pass the (converted)
kcountersize = krepl->num_counters * sizeof(struct ipt_counters); * pointer into the standard syscall. We hope that the pointer is
krepl->counters = (struct ipt_counters *)kmalloc( * not misaligned ...
kcountersize, GFP_KERNEL); */
if (krepl->counters == NULL) { krepl->counters = compat_ptr(ucntrs);
kfree(krepl); if (!access_ok(VERIFY_WRITE, krepl->counters,
return -ENOMEM; krepl->num_counters * sizeof(struct ipt_counters)))
} goto out_free;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
ret = sys_setsockopt(fd, level, optname, ret = sys_setsockopt(fd, level, optname, (char *)krepl, kreplsize);
(char *)krepl, kreplsize);
set_fs(old_fs); set_fs(old_fs);
if (ret == 0 && out_free:
copy_to_user(counters32, krepl->counters, kcountersize))
ret = -EFAULT;
kfree(krepl->counters);
kfree(krepl); kfree(krepl);
return ret; return ret;
} }
/*
* A struct sock_filter is architecture independent.
*/
struct compat_sock_fprog {
u16 len;
compat_uptr_t filter; /* struct sock_filter * */
};
static int do_set_attach_filter(int fd, int level, int optname, static int do_set_attach_filter(int fd, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock_fprog32 { struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval;
__u16 len;
__u32 filter;
} *fprog32 = (struct sock_fprog32 *)optval;
struct sock_fprog kfprog; struct sock_fprog kfprog;
struct sock_filter *kfilter; struct sock_filter *kfilter;
unsigned int fsize;
mm_segment_t old_fs; mm_segment_t old_fs;
compat_uptr_t uptr; compat_uptr_t uptr;
int ret; int ret;
if (get_user(kfprog.len, &fprog32->len) || if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
__get_user(kfprog.len, &fprog32->len) ||
__get_user(uptr, &fprog32->filter)) __get_user(uptr, &fprog32->filter))
return -EFAULT; return -EFAULT;
kfprog.filter = compat_ptr(uptr); kfprog.filter = compat_ptr(uptr);
fsize = kfprog.len * sizeof(struct sock_filter); /*
* Since struct sock_filter is architecure independent,
kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); * we can just do the access_ok check and pass the
if (kfilter == NULL) * same pointer to the real syscall.
return -ENOMEM; */
if (!access_ok(VERIFY_READ, kfprog.filter,
if (copy_from_user(kfilter, kfprog.filter, fsize)) { kfprog.len * sizeof(struct sock_filter)))
kfree(kfilter);
return -EFAULT; return -EFAULT;
}
kfprog.filter = kfilter;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
...@@ -477,8 +519,6 @@ static int do_set_attach_filter(int fd, int level, int optname, ...@@ -477,8 +519,6 @@ static int do_set_attach_filter(int fd, int level, int optname,
(char *)&kfprog, sizeof(kfprog)); (char *)&kfprog, sizeof(kfprog));
set_fs(old_fs); set_fs(old_fs);
kfree(kfilter);
return ret; return ret;
} }
...@@ -489,10 +529,11 @@ static int do_set_icmpv6_filter(int fd, int level, int optname, ...@@ -489,10 +529,11 @@ static int do_set_icmpv6_filter(int fd, int level, int optname,
mm_segment_t old_fs; mm_segment_t old_fs;
int ret, i; int ret, i;
if (optlen < sizeof(*kfilter))
return -EINVAL;
if (copy_from_user(&kfilter, optval, sizeof(kfilter))) if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
return -EFAULT; return -EFAULT;
for (i = 0; i < 8; i += 2) { for (i = 0; i < 8; i += 2) {
u32 tmp = kfilter.data[i]; u32 tmp = kfilter.data[i];
...@@ -518,7 +559,8 @@ static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int ...@@ -518,7 +559,8 @@ static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int
if (optlen < sizeof(*up)) if (optlen < sizeof(*up))
return -EINVAL; return -EINVAL;
if (get_user(ktime.tv_sec, &up->tv_sec) || if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
__get_user(ktime.tv_sec, &up->tv_sec) ||
__get_user(ktime.tv_usec, &up->tv_usec)) __get_user(ktime.tv_usec, &up->tv_usec))
return -EFAULT; return -EFAULT;
old_fs = get_fs(); old_fs = get_fs();
...@@ -547,7 +589,11 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, ...@@ -547,7 +589,11 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
return sys_setsockopt(fd, level, optname, optval, optlen); return sys_setsockopt(fd, level, optname, optval, optlen);
} }
static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int *optlen) extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
void * optval, int *optlen);
static int do_get_sock_timeout(int fd, int level, int optname, char *optval,
int *optlen)
{ {
struct compat_timeval *up = (struct compat_timeval *) optval; struct compat_timeval *up = (struct compat_timeval *) optval;
struct timeval ktime; struct timeval ktime;
...@@ -566,7 +612,8 @@ static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int ...@@ -566,7 +612,8 @@ static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int
if (!err) { if (!err) {
if (put_user(sizeof(*up), optlen) || if (put_user(sizeof(*up), optlen) ||
put_user(ktime.tv_sec, &up->tv_sec) || !access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
__put_user(ktime.tv_sec, &up->tv_sec) ||
__put_user(ktime.tv_usec, &up->tv_usec)) __put_user(ktime.tv_usec, &up->tv_usec))
err = -EFAULT; err = -EFAULT;
} }
...@@ -588,27 +635,21 @@ static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), ...@@ -588,27 +635,21 @@ static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
#undef AL #undef AL
extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); extern asmlinkage long sys_bind(int, struct sockaddr *, int);
extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, extern asmlinkage long sys_connect(int, struct sockaddr *, int);
int addrlen); extern asmlinkage long sys_accept(int, struct sockaddr *, int *);
extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, extern asmlinkage long sys_getsockname(int, struct sockaddr *, int *);
int *upeer_addrlen); extern asmlinkage long sys_getpeername(int, struct sockaddr *, int *);
extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, extern asmlinkage long sys_send(int, void *, size_t, unsigned);
int *usockaddr_len); extern asmlinkage long sys_sendto(int, void *, size_t, unsigned,
extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, struct sockaddr *, int);
int *usockaddr_len); extern asmlinkage long sys_recv(int, void *, size_t, unsigned);
extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags); extern asmlinkage long sys_recvfrom(int, void *, size_t, unsigned,
extern asmlinkage long sys_sendto(int fd, u32 buff, compat_size_t len, struct sockaddr *, int *);
unsigned flags, u32 addr, int addr_len); extern asmlinkage long sys_socket(int, int, int);
extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags); extern asmlinkage long sys_socketpair(int, int, int, int [2]);
extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, compat_size_t size, extern asmlinkage long sys_shutdown(int, int);
unsigned flags, u32 addr, u32 addr_len); extern asmlinkage long sys_listen(int, int);
extern asmlinkage long sys_socket(int family, int type, int protocol);
extern asmlinkage long sys_socketpair(int family, int type, int protocol,
int usockvec[2]);
extern asmlinkage long sys_shutdown(int fd, int how);
extern asmlinkage long sys_listen(int fd, int backlog);
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags) asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags)
{ {
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <net/protocol.h> #include <net/protocol.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/compat.h>
#include <net/scm.h> #include <net/scm.h>
......
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
#endif /* CONFIG_NET_RADIO */ #endif /* CONFIG_NET_RADIO */
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/compat_socket.h> #include <net/compat.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
...@@ -1558,7 +1558,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) ...@@ -1558,7 +1558,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
err = -EFAULT; err = -EFAULT;
if (MSG_CMSG_COMPAT & flags) { if (MSG_CMSG_COMPAT & flags) {
if (msghdr_from_user_compat_to_kern(&msg_sys, msg_compat)) if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT; return -EFAULT;
} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT; return -EFAULT;
...@@ -1652,7 +1652,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) ...@@ -1652,7 +1652,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
int *uaddr_len; int *uaddr_len;
if (MSG_CMSG_COMPAT & flags) { if (MSG_CMSG_COMPAT & flags) {
if (msghdr_from_user_compat_to_kern(&msg_sys, msg_compat)) if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT; return -EFAULT;
} else } else
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
...@@ -1708,15 +1708,9 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) ...@@ -1708,15 +1708,9 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg)); err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg));
if (err) if (err)
goto out_freeiov; goto out_freeiov;
if (MSG_CMSG_COMPAT & flags) { if (MSG_CMSG_COMPAT & flags)
unsigned long ucmsg_ptr; err = put_compat_msg_controllen(&msg_sys, msg_compat, cmsg_ptr);
compat_size_t uclen; else
if((unsigned long) msg_sys.msg_control != cmsg_ptr)
cmsg_compat_recvmsg_fixup(&msg_sys, cmsg_ptr);
ucmsg_ptr = ((unsigned long)msg_sys.msg_control);
uclen = (compat_size_t) (ucmsg_ptr - cmsg_ptr);
err = __put_user(uclen, &msg_compat->msg_controllen);
} else
err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr,
&msg->msg_controllen); &msg->msg_controllen);
if (err) if (err)
......
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