diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 83 |
1 files changed, 45 insertions, 38 deletions
diff --git a/net/socket.c b/net/socket.c index 2e53ed446..482255255 100644 --- a/net/socket.c +++ b/net/socket.c @@ -39,6 +39,8 @@ * for sockets. May have errors at the * moment. * Kevin Buhr : Fixed the dumb errors in the above. + * Andi Kleen : Some small cleanups, optimizations, + * and fixed a copy_from_user() bug. * * * This program is free software; you can redistribute it and/or @@ -71,6 +73,7 @@ #include <linux/proc_fs.h> #include <linux/firewall.h> #include <linux/wanrouter.h> +#include <linux/init.h> #if defined(CONFIG_KERNELD) && defined(CONFIG_NET) #include <linux/kerneld.h> @@ -179,7 +182,7 @@ int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen) * "fromlen shall refer to the value before truncation.." * 1003.1g */ - return put_user(klen, ulen); + return __put_user(klen, ulen); } /* @@ -207,7 +210,6 @@ static int get_fd(struct inode *inode) file->f_op = &socket_file_ops; file->f_mode = 3; file->f_flags = O_RDWR; - file->f_count = 1; file->f_inode = inode; if (inode) inode->i_count++; @@ -365,6 +367,7 @@ static long sock_read(struct inode *inode, struct file *file, if (size==0) /* Match SYS5 behaviour */ return 0; + /* FIXME: I think this can be removed now. */ if ((err=verify_area(VERIFY_WRITE,ubuf,size))<0) return err; msg.msg_name=NULL; @@ -398,7 +401,8 @@ static long sock_write(struct inode *inode, struct file *file, if(size==0) /* Match SYS5 behaviour */ return 0; - + + /* FIXME: I think this can be removed now */ if ((err=verify_area(VERIFY_READ,ubuf,size))<0) return err; @@ -797,7 +801,6 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad { if (!(newsock = sock_alloc())) { - printk(KERN_WARNING "accept: no more sockets\n"); err=-EMFILE; goto out; } @@ -1130,6 +1133,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) struct msghdr msg_sys; int err= -EINVAL; int total_len; + unsigned char *ctl_buf = ctl; lock_kernel(); @@ -1149,22 +1153,26 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) if (msg_sys.msg_controllen) { - if (msg_sys.msg_controllen > sizeof(ctl)) + /* XXX We just limit the buffer and assume that the + * skbuff accounting stops it from going too far. + * I hope this is correct. + */ + if (msg_sys.msg_controllen > sizeof(ctl) && + msg_sys.msg_controllen <= 256) { - char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL); - if (tmp == NULL) + ctl_buf = kmalloc(msg_sys.msg_controllen, GFP_KERNEL); + if (ctl_buf == NULL) { err = -ENOBUFS; goto failed2; } - err = copy_from_user(tmp, msg_sys.msg_control, msg_sys.msg_controllen); - msg_sys.msg_control = tmp; - } else { - err = copy_from_user(ctl, msg_sys.msg_control, msg_sys.msg_controllen); - msg_sys.msg_control = ctl; } - if (err) + if (copy_from_user(ctl_buf, msg_sys.msg_control, + msg_sys.msg_controllen)) { + err = -EFAULT; goto failed; + } + msg_sys.msg_control = ctl_buf; } msg_sys.msg_flags = flags; if (current->files->fd[fd]->f_flags & O_NONBLOCK) @@ -1177,8 +1185,8 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) } failed: - if (msg_sys.msg_controllen && msg_sys.msg_control != ctl) - kfree(msg_sys.msg_control); + if (ctl_buf != ctl) + kfree_s(ctl_buf, msg_sys.msg_controllen); failed2: if (msg_sys.msg_iov != iov) kfree(msg_sys.msg_iov); @@ -1240,7 +1248,6 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) if (current->files->fd[fd]->f_flags&O_NONBLOCK) flags |= MSG_DONTWAIT; - if ((sock = sockfd_lookup(fd, &err))!=NULL) { err=sock_recvmsg(sock, &msg_sys, total_len, flags); @@ -1253,9 +1260,12 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) if (uaddr != NULL && err>=0) err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); - if (err>=0 && (put_user(msg_sys.msg_flags, &msg->msg_flags) || - put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))) - err = -EFAULT; + if (err>=0) { + err = __put_user(msg_sys.msg_flags, &msg->msg_flags); + if (!err) + err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, + &msg->msg_controllen); + } out: unlock_kernel(); if(err<0) @@ -1280,33 +1290,33 @@ int sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg) return(-EINVAL); } +/* Argument list sizes for sys_socketcall */ +#define AL(x) ((x) * sizeof(unsigned long)) +static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +#undef AL /* * System call vectors. * * Argument checking cleaned up. Saved 20% in size. + * This function doesn't need to set the kernel lock because + * it is set by the callees. */ asmlinkage int sys_socketcall(int call, unsigned long *args) { - unsigned char nargs[18]={0,3,3,3,2,3,3,3, - 4,4,4,6,6,2,5,5,3,3}; unsigned long a[6]; unsigned long a0,a1; - int err = -EINVAL; - - lock_kernel(); + int err; + if(call<1||call>SYS_RECVMSG) - goto out; - err = -EFAULT; + return -EINVAL; - /* - * Ideally we want to precompute the maths, but unsigned long - * isnt a fixed size.... - */ - - if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long)))) - goto out; + /* copy_from_user should be SMP safe. */ + if (copy_from_user(a, args, nargs[call])) + return -EFAULT; a0=a[0]; a1=a[1]; @@ -1370,12 +1380,9 @@ asmlinkage int sys_socketcall(int call, unsigned long *args) err = -EINVAL; break; } -out: - unlock_kernel(); return err; } - /* * This function is called by a protocol handler that wants to * advertise its address family, and have it linked into the @@ -1400,7 +1407,7 @@ int sock_unregister(int family) return 0; } -void proto_init(void) +__initfunc(void proto_init(void)) { extern struct net_proto protocols[]; /* Network protocols */ struct net_proto *pro; @@ -1417,7 +1424,7 @@ void proto_init(void) extern void sk_init(void); -void sock_init(void) +__initfunc(void sock_init(void)) { int i; |