X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fsocket.c;h=b7111425004656a3e35be074a2372af43da29e6c;hb=40b77c943468236c6dfad3e7b94348fe70c70331;hp=4e396312f8d58751d0c23914a056126e79ff72ac;hpb=e7b3ca08549caccf5d6e1cf066780bf4f0ae77a7;p=linux-2.6 diff --git a/net/socket.c b/net/socket.c index 4e396312f8..b711142500 100644 --- a/net/socket.c +++ b/net/socket.c @@ -117,7 +117,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, * in the operation structures but are done directly via the socketcall() multiplexor. */ -static struct file_operations socket_file_ops = { +static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, @@ -261,9 +261,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { struct socket_alloc *ei = (struct socket_alloc *)foo; - if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) - == SLAB_CTOR_CONSTRUCTOR) - inode_init_once(&ei->vfs_inode); + inode_init_once(&ei->vfs_inode); } static int init_inodecache(void) @@ -314,8 +312,19 @@ static int sockfs_delete_dentry(struct dentry *dentry) dentry->d_flags |= DCACHE_UNHASHED; return 0; } + +/* + * sockfs_dname() is called from d_path(). + */ +static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) +{ + return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", + dentry->d_inode->i_ino); +} + static struct dentry_operations sockfs_dentry_operations = { .d_delete = sockfs_delete_dentry, + .d_dname = sockfs_dname, }; /* @@ -355,14 +364,9 @@ static int sock_alloc_fd(struct file **filep) static int sock_attach_fd(struct socket *sock, struct file *file) { - struct qstr this; - char name[32]; + struct qstr name = { .name = "" }; - this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); - this.name = name; - this.hash = 0; - - file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); + file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); if (unlikely(!file->f_path.dentry)) return -ENOMEM; @@ -407,24 +411,11 @@ int sock_map_fd(struct socket *sock) 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_path.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; + *err = -ENOTSOCK; + return NULL; } /** @@ -598,6 +589,37 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, return result; } +/* + * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) + */ +void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) +{ + ktime_t kt = skb->tstamp; + + if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { + struct timeval tv; + /* Race occurred between timestamp enabling and packet + receiving. Fill in the current time for now. */ + if (kt.tv64 == 0) + kt = ktime_get_real(); + skb->tstamp = kt; + tv = ktime_to_timeval(kt); + put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv); + } else { + struct timespec ts; + /* Race occurred between timestamp enabling and packet + receiving. Fill in the current time for now. */ + if (kt.tv64 == 0) + kt = ktime_get_real(); + skb->tstamp = kt; + ts = ktime_to_timespec(kt); + put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts); + } +} + +EXPORT_SYMBOL_GPL(__sock_recv_timestamp); + static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { @@ -1207,6 +1229,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, { struct socket *sock1, *sock2; int fd1, fd2, err; + struct file *newfile1, *newfile2; /* * Obtain the first socket and check if the underlying protocol @@ -1225,18 +1248,37 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, if (err < 0) goto out_release_both; - fd1 = fd2 = -1; + fd1 = sock_alloc_fd(&newfile1); + if (unlikely(fd1 < 0)) + goto out_release_both; - err = sock_map_fd(sock1); - if (err < 0) + fd2 = sock_alloc_fd(&newfile2); + if (unlikely(fd2 < 0)) { + put_filp(newfile1); + put_unused_fd(fd1); goto out_release_both; - fd1 = err; + } - err = sock_map_fd(sock2); - if (err < 0) - goto out_close_1; - fd2 = err; + err = sock_attach_fd(sock1, newfile1); + if (unlikely(err < 0)) { + goto out_fd2; + } + err = sock_attach_fd(sock2, newfile2); + if (unlikely(err < 0)) { + fput(newfile1); + goto out_fd1; + } + + err = audit_fd_pair(fd1, fd2); + if (err < 0) { + fput(newfile1); + fput(newfile2); + goto out_fd; + } + + fd_install(fd1, newfile1); + fd_install(fd2, newfile2); /* fd1 and fd2 may be already another descriptors. * Not kernel problem. */ @@ -1251,17 +1293,23 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, sys_close(fd1); return err; -out_close_1: - sock_release(sock2); - sys_close(fd1); - return err; - out_release_both: sock_release(sock2); out_release_1: sock_release(sock1); out: return err; + +out_fd2: + put_filp(newfile1); + sock_release(sock1); +out_fd1: + put_filp(newfile2); + sock_release(sock2); +out_fd: + put_unused_fd(fd1); + put_unused_fd(fd2); + goto out; } /* @@ -1279,7 +1327,7 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) int err, fput_needed; sock = sockfd_lookup_light(fd, &err, &fput_needed); - if(sock) { + if (sock) { err = move_addr_to_kernel(umyaddr, addrlen, address); if (err >= 0) { err = security_socket_bind(sock, @@ -1368,7 +1416,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, err = sock_attach_fd(newsock, newfile); if (err < 0) - goto out_fd; + goto out_fd_simple; err = security_socket_accept(sock, newsock); if (err) @@ -1401,6 +1449,11 @@ out_put: fput_light(sock->file, fput_needed); out: return err; +out_fd_simple: + sock_release(newsock); + put_filp(newfile); + put_unused_fd(newfd); + goto out_put; out_fd: fput(newfile); put_unused_fd(newfd); @@ -1527,8 +1580,9 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, struct file *sock_file; sock_file = fget_light(fd, &fput_needed); + err = -EBADF; if (!sock_file) - return -EBADF; + goto out; sock = sock_from_file(sock_file, &err); if (!sock) @@ -1555,6 +1609,7 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, out_put: fput_light(sock_file, fput_needed); +out: return err; } @@ -1586,12 +1641,13 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, int fput_needed; sock_file = fget_light(fd, &fput_needed); + err = -EBADF; if (!sock_file) - return -EBADF; + goto out; sock = sock_from_file(sock_file, &err); if (!sock) - goto out; + goto out_put; msg.msg_control = NULL; msg.msg_controllen = 0; @@ -1610,8 +1666,9 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, if (err2 < 0) err = err2; } -out: +out_put: fput_light(sock_file, fput_needed); +out: return err; } @@ -1882,9 +1939,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, total_len = err; cmsg_ptr = (unsigned long)msg_sys.msg_control; - msg_sys.msg_flags = 0; - if (MSG_CMSG_COMPAT & flags) - msg_sys.msg_flags = MSG_CMSG_COMPAT; + msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; @@ -2189,7 +2244,7 @@ done: } int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, - int flags) + int flags) { return sock->ops->connect(sock, addr, addrlen, flags); }