summaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c83
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;