diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 92 |
1 files changed, 77 insertions, 15 deletions
diff --git a/net/socket.c b/net/socket.c index 0778c544241..1ad62c08377 100644 --- a/net/socket.c +++ b/net/socket.c @@ -585,6 +585,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) { @@ -1194,6 +1225,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 @@ -1212,18 +1244,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. */ @@ -1238,17 +1289,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; } /* @@ -1266,7 +1323,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, @@ -1355,7 +1412,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) @@ -1388,6 +1445,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); |