summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/socket.c192
1 files changed, 106 insertions, 86 deletions
diff --git a/net/socket.c b/net/socket.c
index 74283610db15..510ae18d220a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -426,6 +426,28 @@ int sock_map_fd(struct socket *sock)
return fd;
}
+static struct socket *sock_from_file(struct file *file, int *err)
+{
+ struct inode *inode;
+ struct socket *sock;
+
+ if (file->f_op == &socket_file_ops)
+ return file->private_data; /* set in sock_map_fd */
+
+ inode = file->f_dentry->d_inode;
+ if (!S_ISSOCK(inode->i_mode)) {
+ *err = -ENOTSOCK;
+ return NULL;
+ }
+
+ sock = SOCKET_I(inode);
+ if (sock->file != file) {
+ printk(KERN_ERR "socki_lookup: socket file changed!\n");
+ sock->file = file;
+ }
+ return sock;
+}
+
/**
* sockfd_lookup - Go from a file number to its socket slot
* @fd: file handle
@@ -442,31 +464,31 @@ int sock_map_fd(struct socket *sock)
struct socket *sockfd_lookup(int fd, int *err)
{
struct file *file;
- struct inode *inode;
struct socket *sock;
- if (!(file = fget(fd)))
- {
+ if (!(file = fget(fd))) {
*err = -EBADF;
return NULL;
}
-
- if (file->f_op == &socket_file_ops)
- return file->private_data; /* set in sock_map_fd */
-
- inode = file->f_dentry->d_inode;
- if (!S_ISSOCK(inode->i_mode)) {
- *err = -ENOTSOCK;
+ sock = sock_from_file(file, err);
+ if (!sock)
fput(file);
- return NULL;
- }
+ return sock;
+}
- sock = SOCKET_I(inode);
- if (sock->file != file) {
- printk(KERN_ERR "socki_lookup: socket file changed!\n");
- sock->file = file;
+static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
+{
+ struct file *file;
+ struct socket *sock;
+
+ file = fget_light(fd, fput_needed);
+ if (file) {
+ sock = sock_from_file(file, err);
+ if (sock)
+ return sock;
+ fput_light(file, *fput_needed);
}
- return sock;
+ return NULL;
}
/**
@@ -1301,19 +1323,17 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
- int err;
+ int err, fput_needed;
- if((sock = sockfd_lookup(fd,&err))!=NULL)
+ if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
{
if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
- if (err) {
- sockfd_put(sock);
- return err;
- }
- err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
+ if (!err)
+ err = sock->ops->bind(sock,
+ (struct sockaddr *)address, addrlen);
}
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1330,20 +1350,17 @@ int sysctl_somaxconn = SOMAXCONN;
asmlinkage long sys_listen(int fd, int backlog)
{
struct socket *sock;
- int err;
+ int err, fput_needed;
- if ((sock = sockfd_lookup(fd, &err)) != NULL) {
+ if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
if ((unsigned) backlog > sysctl_somaxconn)
backlog = sysctl_somaxconn;
err = security_socket_listen(sock, backlog);
- if (err) {
- sockfd_put(sock);
- return err;
- }
+ if (!err)
+ err = sock->ops->listen(sock, backlog);
- err=sock->ops->listen(sock, backlog);
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1365,10 +1382,10 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
{
struct socket *sock, *newsock;
struct file *newfile;
- int err, len, newfd;
+ int err, len, newfd, fput_needed;
char address[MAX_SOCK_ADDR];
- sock = sockfd_lookup(fd, &err);
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -1421,7 +1438,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
security_socket_post_accept(sock, newsock);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
out_fd:
@@ -1449,9 +1466,9 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
- int err;
+ int err, fput_needed;
- sock = sockfd_lookup(fd, &err);
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
err = move_addr_to_kernel(uservaddr, addrlen, address);
@@ -1465,7 +1482,7 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
sock->file->f_flags);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
}
@@ -1479,9 +1496,9 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
- int len, err;
+ int len, err, fput_needed;
- sock = sockfd_lookup(fd, &err);
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -1495,7 +1512,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
err = move_addr_to_user(address, len, usockaddr, usockaddr_len);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
}
@@ -1509,20 +1526,19 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
- int len, err;
+ int len, err, fput_needed;
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
+ if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
err = security_socket_getpeername(sock);
if (err) {
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
return err;
}
err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
if (!err)
err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1541,10 +1557,16 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
int err;
struct msghdr msg;
struct iovec iov;
-
- sock = sockfd_lookup(fd, &err);
+ int fput_needed;
+ struct file *sock_file;
+
+ sock_file = fget_light(fd, &fput_needed);
+ if (!sock_file)
+ return -EBADF;
+
+ sock = sock_from_file(sock_file, &err);
if (!sock)
- goto out;
+ goto out_put;
iov.iov_base=buff;
iov.iov_len=len;
msg.msg_name=NULL;
@@ -1553,8 +1575,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
msg.msg_control=NULL;
msg.msg_controllen=0;
msg.msg_namelen=0;
- if(addr)
- {
+ if (addr) {
err = move_addr_to_kernel(addr, addr_len, address);
if (err < 0)
goto out_put;
@@ -1567,8 +1588,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
err = sock_sendmsg(sock, &msg, len);
out_put:
- sockfd_put(sock);
-out:
+ fput_light(sock_file, fput_needed);
return err;
}
@@ -1595,8 +1615,14 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
struct msghdr msg;
char address[MAX_SOCK_ADDR];
int err,err2;
+ struct file *sock_file;
+ int fput_needed;
+
+ sock_file = fget_light(fd, &fput_needed);
+ if (!sock_file)
+ return -EBADF;
- sock = sockfd_lookup(fd, &err);
+ sock = sock_from_file(sock_file, &err);
if (!sock)
goto out;
@@ -1618,8 +1644,8 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
if(err2<0)
err=err2;
}
- sockfd_put(sock);
out:
+ fput_light(sock_file, fput_needed);
return err;
}
@@ -1639,25 +1665,24 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags
asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
{
- int err;
+ int err, fput_needed;
struct socket *sock;
if (optlen < 0)
return -EINVAL;
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
+ if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL)
{
err = security_socket_setsockopt(sock,level,optname);
- if (err) {
- sockfd_put(sock);
- return err;
- }
+ if (err)
+ goto out_put;
if (level == SOL_SOCKET)
err=sock_setsockopt(sock,level,optname,optval,optlen);
else
err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
- sockfd_put(sock);
+out_put:
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1669,23 +1694,20 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optv
asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen)
{
- int err;
+ int err, fput_needed;
struct socket *sock;
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
- err = security_socket_getsockopt(sock, level,
- optname);
- if (err) {
- sockfd_put(sock);
- return err;
- }
+ if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
+ err = security_socket_getsockopt(sock, level, optname);
+ if (err)
+ goto out_put;
if (level == SOL_SOCKET)
err=sock_getsockopt(sock,level,optname,optval,optlen);
else
err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
- sockfd_put(sock);
+out_put:
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1697,19 +1719,15 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optv
asmlinkage long sys_shutdown(int fd, int how)
{
- int err;
+ int err, fput_needed;
struct socket *sock;
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
+ if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
{
err = security_socket_shutdown(sock, how);
- if (err) {
- sockfd_put(sock);
- return err;
- }
-
- err=sock->ops->shutdown(sock, how);
- sockfd_put(sock);
+ if (!err)
+ err = sock->ops->shutdown(sock, how);
+ fput_light(sock->file, fput_needed);
}
return err;
}
@@ -1738,6 +1756,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
unsigned char *ctl_buf = ctl;
struct msghdr msg_sys;
int err, ctl_len, iov_size, total_len;
+ int fput_needed;
err = -EFAULT;
if (MSG_CMSG_COMPAT & flags) {
@@ -1746,7 +1765,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- sock = sockfd_lookup(fd, &err);
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -1814,7 +1833,7 @@ out_freeiov:
if (iov != iovstack)
sock_kfree_s(sock->sk, iov, iov_size);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
}
@@ -1832,6 +1851,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
struct msghdr msg_sys;
unsigned long cmsg_ptr;
int err, iov_size, total_len, len;
+ int fput_needed;
/* kernel mode address */
char addr[MAX_SOCK_ADDR];
@@ -1847,7 +1867,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
return -EFAULT;
- sock = sockfd_lookup(fd, &err);
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
@@ -1914,7 +1934,7 @@ out_freeiov:
if (iov != iovstack)
sock_kfree_s(sock->sk, iov, iov_size);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
}