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

Stephen Rothwell (sfr@canb.auug.org.au)
Mon, 24 Mar 2003 15:32:39 +1100


Hi Dave,

On Mon, 24 Mar 2003 11:36:26 +1100 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> On Sun, 23 Mar 2003 01:00:26 -0800 (PST) "David S. Miller" <davem@redhat.com> wrote:
> >
> > I'm fine with this, but I just tried to apply it and there were a ton
> > of rejects. Can you rediff this against Linus's current tree and send
> > it to me?
>
> The real problem is that Linus has not applied one of my previous
> patches. Included below. Linus please, please, pleas apply ...

OK, sorry, that was part of the problem. (stupid mistake on my part).
Here is the rediffed patch but you still need linus to apply the previous
patch which defines compat_uptr_t ...

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

diff -ruN 2.5.65-2003032309-32bit.2/arch/sparc64/kernel/sparc64_ksyms.c 2.5.65-2003032309-32bit.3/arch/sparc64/kernel/sparc64_ksyms.c --- 2.5.65-2003032309-32bit.2/arch/sparc64/kernel/sparc64_ksyms.c 2003-03-24 14:24:03.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/arch/sparc64/kernel/sparc64_ksyms.c 2003-03-24 15:12:52.000000000 +1100 @@ -21,6 +21,7 @@ #include <linux/fs_struct.h> #include <linux/mm.h> #include <linux/socket.h> +#include <net/compat.h> #include <asm/oplib.h> #include <asm/delay.h> diff -ruN 2.5.65-2003032309-32bit.2/arch/sparc64/kernel/sys_sunos32.c 2.5.65-2003032309-32bit.3/arch/sparc64/kernel/sys_sunos32.c --- 2.5.65-2003032309-32bit.2/arch/sparc64/kernel/sys_sunos32.c 2003-03-18 10:17:05.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/arch/sparc64/kernel/sys_sunos32.c 2003-03-18 22:14:26.000000000 +1100 @@ -56,6 +56,7 @@ /* For SOCKET_I */ #include <linux/socket.h> #include <net/sock.h> +#include <net/compat.h> /* Use this to get at 32-bit user passed pointers. */ #define A(__x) \ diff -ruN 2.5.65-2003032309-32bit.2/arch/sparc64/solaris/socket.c 2.5.65-2003032309-32bit.3/arch/sparc64/solaris/socket.c --- 2.5.65-2003032309-32bit.2/arch/sparc64/solaris/socket.c 2003-03-18 10:17:05.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/arch/sparc64/solaris/socket.c 2003-03-18 22:26:22.000000000 +1100 @@ -15,6 +15,7 @@ #include <linux/file.h> #include <linux/net.h> #include <linux/compat.h> +#include <net/compat.h> #include <asm/uaccess.h> #include <asm/string.h> diff -ruN 2.5.65-2003032309-32bit.2/include/linux/compat.h 2.5.65-2003032309-32bit.3/include/linux/compat.h --- 2.5.65-2003032309-32bit.2/include/linux/compat.h 2003-03-18 10:17:24.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/include/linux/compat.h 2003-03-13 17:54:27.000000000 +1100 @@ -43,11 +43,9 @@ extern int put_compat_timespec(struct timespec *, struct compat_timespec *); struct compat_iovec { - u32 iov_base; + compat_uptr_t iov_base; compat_size_t iov_len; }; -#else /* no CONFIG_COMPAT */ -#define compat_size_t size_t #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff -ruN 2.5.65-2003032309-32bit.2/include/linux/socket.h 2.5.65-2003032309-32bit.3/include/linux/socket.h --- 2.5.65-2003032309-32bit.2/include/linux/socket.h 2003-03-18 10:17:24.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/include/linux/socket.h 2003-03-14 17:36:50.000000000 +1100 @@ -3,6 +3,7 @@ #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) +#include <linux/config.h> /* for CONFIG_COMPAT */ #include <linux/linkage.h> #include <asm/socket.h> /* arch-dependent defines */ #include <linux/sockios.h> /* the SIOCxxx I/O controls */ @@ -239,18 +240,10 @@ #define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ #else #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ -#define compat_msghdr msghdr /* Needed to avoid compiler hoops */ #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_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 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 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 /* not kernel and not glibc */ diff -ruN 2.5.65-2003032309-32bit.2/include/net/compat.h 2.5.65-2003032309-32bit.3/include/net/compat.h --- 2.5.65-2003032309-32bit.2/include/net/compat.h 1970-01-01 10:00:00.000000000 +1000 +++ 2.5.65-2003032309-32bit.3/include/net/compat.h 2003-03-18 22:13:49.000000000 +1100 @@ -0,0 +1,41 @@ +#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 */ diff -ruN 2.5.65-2003032309-32bit.2/include/net/compat_socket.h 2.5.65-2003032309-32bit.3/include/net/compat_socket.h --- 2.5.65-2003032309-32bit.2/include/net/compat_socket.h 2003-03-18 10:17:25.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/include/net/compat_socket.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,67 +0,0 @@ -#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 diff -ruN 2.5.65-2003032309-32bit.2/net/compat.c 2.5.65-2003032309-32bit.3/net/compat.c --- 2.5.65-2003032309-32bit.2/net/compat.c 2003-03-24 14:25:45.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/net/compat.c 2003-03-24 15:19:18.000000000 +1100 @@ -25,14 +25,10 @@ #include <net/scm.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <net/compat_socket.h> +#include <net/compat.h> #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, struct compat_iovec *uiov32, int niov) @@ -40,7 +36,8 @@ int tot_len = 0; while(niov > 0) { - u32 len, buf; + compat_uptr_t buf; + compat_size_t len; if(get_user(len, &uiov32->iov_len) || get_user(buf, &uiov32->iov_base)) { @@ -57,27 +54,23 @@ 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; - int err; - err = get_user(tmp1, &umsg->msg_name); - err |= __get_user(tmp2, &umsg->msg_iov); - err |= __get_user(tmp3, &umsg->msg_control); - if (err) + if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || + __get_user(tmp1, &umsg->msg_name) || + __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || + __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; - kmsg->msg_name = compat_ptr(tmp1); kmsg->msg_iov = compat_ptr(tmp2); kmsg->msg_control = compat_ptr(tmp3); - - 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; + return 0; } /* I've named the args so it is easy to tell whose space the pointers are in. */ @@ -116,6 +109,34 @@ 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 * thus placement) of cmsg headers and length are different for * 32-bit apps. -DaveM @@ -146,7 +167,7 @@ tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); kcmlen += tmp; - ucmsg = CMSG_COMPAT_NXTHDR(kmsg, ucmsg, ucmlen); + ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); } if(kcmlen == 0) return -EINVAL; @@ -180,7 +201,7 @@ /* Advance. */ 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. */ @@ -303,7 +324,7 @@ * IPV6_RTHDR ipv6 routing 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 long bufsz, space_avail; @@ -364,112 +385,133 @@ 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, - 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, char *optval, int optlen) { - struct ipt_replace32 { - 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 compat_ipt_replace *urepl = (struct compat_ipt_replace *)optval; struct ipt_replace *krepl; - struct ipt_counters *counters32; - __u32 origsize; - unsigned int kreplsize, kcountersize; + struct ipt_counters *ucounters; + u32 origsize; + unsigned int kreplsize; mm_segment_t old_fs; int ret; + int i; + compat_uptr_t ucntrs; - if (optlen < sizeof(repl32)) - return -EINVAL; - - if (copy_from_user(&origsize, - &repl32->size, - sizeof(origsize))) + if (get_user(origsize, &urepl->size)) return -EFAULT; - kreplsize = sizeof(*krepl) + origsize; - kcountersize = krepl->num_counters * sizeof(struct ipt_counters); - /* Hack: Causes ipchains to give correct error msg --RR */ - if (optlen != kreplsize) + if (optlen != sizeof(*urepl) + origsize) 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); if (krepl == NULL) return -ENOMEM; - if (copy_from_user(krepl, optval, kreplsize)) { - kfree(krepl); - return -EFAULT; + ret = -EFAULT; + krepl->size = origsize; + 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); - - kcountersize = krepl->num_counters * sizeof(struct ipt_counters); - krepl->counters = (struct ipt_counters *)kmalloc( - kcountersize, GFP_KERNEL); - if (krepl->counters == NULL) { - kfree(krepl); - return -ENOMEM; - } + /* + * Since struct ipt_counters just contains two u_int64_t members + * we can just do the access_ok check here and pass the (converted) + * pointer into the standard syscall. We hope that the pointer is + * not misaligned ... + */ + krepl->counters = compat_ptr(ucntrs); + if (!access_ok(VERIFY_WRITE, krepl->counters, + krepl->num_counters * sizeof(struct ipt_counters))) + goto out_free; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_setsockopt(fd, level, optname, - (char *)krepl, kreplsize); + ret = sys_setsockopt(fd, level, optname, (char *)krepl, kreplsize); set_fs(old_fs); - if (ret == 0 && - copy_to_user(counters32, krepl->counters, kcountersize)) - ret = -EFAULT; - - kfree(krepl->counters); +out_free: kfree(krepl); - 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, char *optval, int optlen) { - struct sock_fprog32 { - __u16 len; - __u32 filter; - } *fprog32 = (struct sock_fprog32 *)optval; + struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval; struct sock_fprog kfprog; struct sock_filter *kfilter; - unsigned int fsize; mm_segment_t old_fs; compat_uptr_t uptr; 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)) return -EFAULT; kfprog.filter = compat_ptr(uptr); - fsize = kfprog.len * sizeof(struct sock_filter); - - kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); - if (kfilter == NULL) - return -ENOMEM; - - if (copy_from_user(kfilter, kfprog.filter, fsize)) { - kfree(kfilter); + /* + * Since struct sock_filter is architecure independent, + * we can just do the access_ok check and pass the + * same pointer to the real syscall. + */ + if (!access_ok(VERIFY_READ, kfprog.filter, + kfprog.len * sizeof(struct sock_filter))) return -EFAULT; - } - - kfprog.filter = kfilter; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -477,8 +519,6 @@ (char *)&kfprog, sizeof(kfprog)); set_fs(old_fs); - kfree(kfilter); - return ret; } @@ -489,10 +529,11 @@ mm_segment_t old_fs; int ret, i; + if (optlen < sizeof(*kfilter)) + return -EINVAL; if (copy_from_user(&kfilter, optval, sizeof(kfilter))) return -EFAULT; - for (i = 0; i < 8; i += 2) { u32 tmp = kfilter.data[i]; @@ -518,7 +559,8 @@ if (optlen < sizeof(*up)) 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)) return -EFAULT; old_fs = get_fs(); @@ -547,7 +589,11 @@ 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 timeval ktime; @@ -566,7 +612,8 @@ if (!err) { 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)) err = -EFAULT; } @@ -588,27 +635,21 @@ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL -extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); -extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, - int addrlen); -extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, - int *upeer_addrlen); -extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); -extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, - int *usockaddr_len); -extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags); -extern asmlinkage long sys_sendto(int fd, u32 buff, compat_size_t len, - unsigned flags, u32 addr, int addr_len); -extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags); -extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, compat_size_t size, - unsigned flags, u32 addr, u32 addr_len); -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); - +extern asmlinkage long sys_bind(int, struct sockaddr *, int); +extern asmlinkage long sys_connect(int, struct sockaddr *, int); +extern asmlinkage long sys_accept(int, struct sockaddr *, int *); +extern asmlinkage long sys_getsockname(int, struct sockaddr *, int *); +extern asmlinkage long sys_getpeername(int, struct sockaddr *, int *); +extern asmlinkage long sys_send(int, void *, size_t, unsigned); +extern asmlinkage long sys_sendto(int, void *, size_t, unsigned, + struct sockaddr *, int); +extern asmlinkage long sys_recv(int, void *, size_t, unsigned); +extern asmlinkage long sys_recvfrom(int, void *, size_t, unsigned, + struct sockaddr *, int *); +extern asmlinkage long sys_socket(int, int, int); +extern asmlinkage long sys_socketpair(int, int, int, int [2]); +extern asmlinkage long sys_shutdown(int, int); +extern asmlinkage long sys_listen(int, int); asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr *msg, unsigned flags) { diff -ruN 2.5.65-2003032309-32bit.2/net/core/scm.c 2.5.65-2003032309-32bit.3/net/core/scm.c --- 2.5.65-2003032309-32bit.2/net/core/scm.c 2003-03-18 10:17:26.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/net/core/scm.c 2003-03-18 22:14:51.000000000 +1100 @@ -30,6 +30,7 @@ #include <net/protocol.h> #include <linux/skbuff.h> #include <net/sock.h> +#include <net/compat.h> #include <net/scm.h> diff -ruN 2.5.65-2003032309-32bit.2/net/socket.c 2.5.65-2003032309-32bit.3/net/socket.c --- 2.5.65-2003032309-32bit.2/net/socket.c 2003-03-18 10:17:29.000000000 +1100 +++ 2.5.65-2003032309-32bit.3/net/socket.c 2003-03-18 22:14:58.000000000 +1100 @@ -89,7 +89,7 @@ #endif /* CONFIG_NET_RADIO */ #include <asm/uaccess.h> -#include <net/compat_socket.h> +#include <net/compat.h> #include <net/sock.h> #include <linux/netfilter.h> @@ -1558,7 +1558,7 @@ err = -EFAULT; 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; } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) return -EFAULT; @@ -1652,7 +1652,7 @@ int *uaddr_len; 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; } else if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) @@ -1708,15 +1708,9 @@ err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg)); if (err) goto out_freeiov; - if (MSG_CMSG_COMPAT & flags) { - 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); - err = __put_user(uclen, &msg_compat->msg_controllen); - } else + if (MSG_CMSG_COMPAT & flags) + err = put_compat_msg_controllen(&msg_sys, msg_compat, cmsg_ptr); + else err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen); if (err) - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/