diff options
Diffstat (limited to 'net/unix')
| -rw-r--r-- | net/unix/af_unix.c | 87 | ||||
| -rw-r--r-- | net/unix/garbage.c | 17 |
2 files changed, 76 insertions, 28 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2358f2690ec5..928691c43408 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
| @@ -85,7 +85,7 @@ | |||
| 85 | #include <linux/module.h> | 85 | #include <linux/module.h> |
| 86 | #include <linux/kernel.h> | 86 | #include <linux/kernel.h> |
| 87 | #include <linux/signal.h> | 87 | #include <linux/signal.h> |
| 88 | #include <linux/sched.h> | 88 | #include <linux/sched/signal.h> |
| 89 | #include <linux/errno.h> | 89 | #include <linux/errno.h> |
| 90 | #include <linux/string.h> | 90 | #include <linux/string.h> |
| 91 | #include <linux/stat.h> | 91 | #include <linux/stat.h> |
| @@ -100,7 +100,7 @@ | |||
| 100 | #include <linux/in.h> | 100 | #include <linux/in.h> |
| 101 | #include <linux/fs.h> | 101 | #include <linux/fs.h> |
| 102 | #include <linux/slab.h> | 102 | #include <linux/slab.h> |
| 103 | #include <asm/uaccess.h> | 103 | #include <linux/uaccess.h> |
| 104 | #include <linux/skbuff.h> | 104 | #include <linux/skbuff.h> |
| 105 | #include <linux/netdevice.h> | 105 | #include <linux/netdevice.h> |
| 106 | #include <net/net_namespace.h> | 106 | #include <net/net_namespace.h> |
| @@ -117,6 +117,7 @@ | |||
| 117 | #include <net/checksum.h> | 117 | #include <net/checksum.h> |
| 118 | #include <linux/security.h> | 118 | #include <linux/security.h> |
| 119 | #include <linux/freezer.h> | 119 | #include <linux/freezer.h> |
| 120 | #include <linux/file.h> | ||
| 120 | 121 | ||
| 121 | struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; | 122 | struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; |
| 122 | EXPORT_SYMBOL_GPL(unix_socket_table); | 123 | EXPORT_SYMBOL_GPL(unix_socket_table); |
| @@ -315,7 +316,7 @@ static struct sock *unix_find_socket_byinode(struct inode *i) | |||
| 315 | &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { | 316 | &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { |
| 316 | struct dentry *dentry = unix_sk(s)->path.dentry; | 317 | struct dentry *dentry = unix_sk(s)->path.dentry; |
| 317 | 318 | ||
| 318 | if (dentry && d_real_inode(dentry) == i) { | 319 | if (dentry && d_backing_inode(dentry) == i) { |
| 319 | sock_hold(s); | 320 | sock_hold(s); |
| 320 | goto found; | 321 | goto found; |
| 321 | } | 322 | } |
| @@ -635,7 +636,7 @@ static int unix_bind(struct socket *, struct sockaddr *, int); | |||
| 635 | static int unix_stream_connect(struct socket *, struct sockaddr *, | 636 | static int unix_stream_connect(struct socket *, struct sockaddr *, |
| 636 | int addr_len, int flags); | 637 | int addr_len, int flags); |
| 637 | static int unix_socketpair(struct socket *, struct socket *); | 638 | static int unix_socketpair(struct socket *, struct socket *); |
| 638 | static int unix_accept(struct socket *, struct socket *, int); | 639 | static int unix_accept(struct socket *, struct socket *, int, bool); |
| 639 | static int unix_getname(struct socket *, struct sockaddr *, int *, int); | 640 | static int unix_getname(struct socket *, struct sockaddr *, int *, int); |
| 640 | static unsigned int unix_poll(struct file *, struct socket *, poll_table *); | 641 | static unsigned int unix_poll(struct file *, struct socket *, poll_table *); |
| 641 | static unsigned int unix_dgram_poll(struct file *, struct socket *, | 642 | static unsigned int unix_dgram_poll(struct file *, struct socket *, |
| @@ -913,7 +914,7 @@ static struct sock *unix_find_other(struct net *net, | |||
| 913 | err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path); | 914 | err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path); |
| 914 | if (err) | 915 | if (err) |
| 915 | goto fail; | 916 | goto fail; |
| 916 | inode = d_real_inode(path.dentry); | 917 | inode = d_backing_inode(path.dentry); |
| 917 | err = inode_permission(inode, MAY_WRITE); | 918 | err = inode_permission(inode, MAY_WRITE); |
| 918 | if (err) | 919 | if (err) |
| 919 | goto put_fail; | 920 | goto put_fail; |
| @@ -995,6 +996,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 995 | unsigned int hash; | 996 | unsigned int hash; |
| 996 | struct unix_address *addr; | 997 | struct unix_address *addr; |
| 997 | struct hlist_head *list; | 998 | struct hlist_head *list; |
| 999 | struct path path = { NULL, NULL }; | ||
| 998 | 1000 | ||
| 999 | err = -EINVAL; | 1001 | err = -EINVAL; |
| 1000 | if (sunaddr->sun_family != AF_UNIX) | 1002 | if (sunaddr->sun_family != AF_UNIX) |
| @@ -1010,9 +1012,20 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 1010 | goto out; | 1012 | goto out; |
| 1011 | addr_len = err; | 1013 | addr_len = err; |
| 1012 | 1014 | ||
| 1015 | if (sun_path[0]) { | ||
| 1016 | umode_t mode = S_IFSOCK | | ||
| 1017 | (SOCK_INODE(sock)->i_mode & ~current_umask()); | ||
| 1018 | err = unix_mknod(sun_path, mode, &path); | ||
| 1019 | if (err) { | ||
| 1020 | if (err == -EEXIST) | ||
| 1021 | err = -EADDRINUSE; | ||
| 1022 | goto out; | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1013 | err = mutex_lock_interruptible(&u->bindlock); | 1026 | err = mutex_lock_interruptible(&u->bindlock); |
| 1014 | if (err) | 1027 | if (err) |
| 1015 | goto out; | 1028 | goto out_put; |
| 1016 | 1029 | ||
| 1017 | err = -EINVAL; | 1030 | err = -EINVAL; |
| 1018 | if (u->addr) | 1031 | if (u->addr) |
| @@ -1029,18 +1042,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 1029 | atomic_set(&addr->refcnt, 1); | 1042 | atomic_set(&addr->refcnt, 1); |
| 1030 | 1043 | ||
| 1031 | if (sun_path[0]) { | 1044 | if (sun_path[0]) { |
| 1032 | struct path path; | ||
| 1033 | umode_t mode = S_IFSOCK | | ||
| 1034 | (SOCK_INODE(sock)->i_mode & ~current_umask()); | ||
| 1035 | err = unix_mknod(sun_path, mode, &path); | ||
| 1036 | if (err) { | ||
| 1037 | if (err == -EEXIST) | ||
| 1038 | err = -EADDRINUSE; | ||
| 1039 | unix_release_addr(addr); | ||
| 1040 | goto out_up; | ||
| 1041 | } | ||
| 1042 | addr->hash = UNIX_HASH_SIZE; | 1045 | addr->hash = UNIX_HASH_SIZE; |
| 1043 | hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); | 1046 | hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); |
| 1044 | spin_lock(&unix_table_lock); | 1047 | spin_lock(&unix_table_lock); |
| 1045 | u->path = path; | 1048 | u->path = path; |
| 1046 | list = &unix_socket_table[hash]; | 1049 | list = &unix_socket_table[hash]; |
| @@ -1065,6 +1068,9 @@ out_unlock: | |||
| 1065 | spin_unlock(&unix_table_lock); | 1068 | spin_unlock(&unix_table_lock); |
| 1066 | out_up: | 1069 | out_up: |
| 1067 | mutex_unlock(&u->bindlock); | 1070 | mutex_unlock(&u->bindlock); |
| 1071 | out_put: | ||
| 1072 | if (err) | ||
| 1073 | path_put(&path); | ||
| 1068 | out: | 1074 | out: |
| 1069 | return err; | 1075 | return err; |
| 1070 | } | 1076 | } |
| @@ -1396,7 +1402,8 @@ static void unix_sock_inherit_flags(const struct socket *old, | |||
| 1396 | set_bit(SOCK_PASSSEC, &new->flags); | 1402 | set_bit(SOCK_PASSSEC, &new->flags); |
| 1397 | } | 1403 | } |
| 1398 | 1404 | ||
| 1399 | static int unix_accept(struct socket *sock, struct socket *newsock, int flags) | 1405 | static int unix_accept(struct socket *sock, struct socket *newsock, int flags, |
| 1406 | bool kern) | ||
| 1400 | { | 1407 | { |
| 1401 | struct sock *sk = sock->sk; | 1408 | struct sock *sk = sock->sk; |
| 1402 | struct sock *tsk; | 1409 | struct sock *tsk; |
| @@ -2113,8 +2120,8 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, | |||
| 2113 | mutex_lock(&u->iolock); | 2120 | mutex_lock(&u->iolock); |
| 2114 | 2121 | ||
| 2115 | skip = sk_peek_offset(sk, flags); | 2122 | skip = sk_peek_offset(sk, flags); |
| 2116 | skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err, | 2123 | skb = __skb_try_recv_datagram(sk, flags, NULL, &peeked, &skip, |
| 2117 | &last); | 2124 | &err, &last); |
| 2118 | if (skb) | 2125 | if (skb) |
| 2119 | break; | 2126 | break; |
| 2120 | 2127 | ||
| @@ -2587,6 +2594,43 @@ long unix_outq_len(struct sock *sk) | |||
| 2587 | } | 2594 | } |
| 2588 | EXPORT_SYMBOL_GPL(unix_outq_len); | 2595 | EXPORT_SYMBOL_GPL(unix_outq_len); |
| 2589 | 2596 | ||
| 2597 | static int unix_open_file(struct sock *sk) | ||
| 2598 | { | ||
| 2599 | struct path path; | ||
| 2600 | struct file *f; | ||
| 2601 | int fd; | ||
| 2602 | |||
| 2603 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) | ||
| 2604 | return -EPERM; | ||
| 2605 | |||
| 2606 | unix_state_lock(sk); | ||
| 2607 | path = unix_sk(sk)->path; | ||
| 2608 | if (!path.dentry) { | ||
| 2609 | unix_state_unlock(sk); | ||
| 2610 | return -ENOENT; | ||
| 2611 | } | ||
| 2612 | |||
| 2613 | path_get(&path); | ||
| 2614 | unix_state_unlock(sk); | ||
| 2615 | |||
| 2616 | fd = get_unused_fd_flags(O_CLOEXEC); | ||
| 2617 | if (fd < 0) | ||
| 2618 | goto out; | ||
| 2619 | |||
| 2620 | f = dentry_open(&path, O_PATH, current_cred()); | ||
| 2621 | if (IS_ERR(f)) { | ||
| 2622 | put_unused_fd(fd); | ||
| 2623 | fd = PTR_ERR(f); | ||
| 2624 | goto out; | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | fd_install(fd, f); | ||
| 2628 | out: | ||
| 2629 | path_put(&path); | ||
| 2630 | |||
| 2631 | return fd; | ||
| 2632 | } | ||
| 2633 | |||
| 2590 | static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | 2634 | static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
| 2591 | { | 2635 | { |
| 2592 | struct sock *sk = sock->sk; | 2636 | struct sock *sk = sock->sk; |
| @@ -2605,6 +2649,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
| 2605 | else | 2649 | else |
| 2606 | err = put_user(amount, (int __user *)arg); | 2650 | err = put_user(amount, (int __user *)arg); |
| 2607 | break; | 2651 | break; |
| 2652 | case SIOCUNIXFILE: | ||
| 2653 | err = unix_open_file(sk); | ||
| 2654 | break; | ||
| 2608 | default: | 2655 | default: |
| 2609 | err = -ENOIOCTLCMD; | 2656 | err = -ENOIOCTLCMD; |
| 2610 | break; | 2657 | break; |
diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 6a0d48525fcf..c36757e72844 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c | |||
| @@ -146,6 +146,7 @@ void unix_notinflight(struct user_struct *user, struct file *fp) | |||
| 146 | if (s) { | 146 | if (s) { |
| 147 | struct unix_sock *u = unix_sk(s); | 147 | struct unix_sock *u = unix_sk(s); |
| 148 | 148 | ||
| 149 | BUG_ON(!atomic_long_read(&u->inflight)); | ||
| 149 | BUG_ON(list_empty(&u->link)); | 150 | BUG_ON(list_empty(&u->link)); |
| 150 | 151 | ||
| 151 | if (atomic_long_dec_and_test(&u->inflight)) | 152 | if (atomic_long_dec_and_test(&u->inflight)) |
| @@ -341,6 +342,14 @@ void unix_gc(void) | |||
| 341 | } | 342 | } |
| 342 | list_del(&cursor); | 343 | list_del(&cursor); |
| 343 | 344 | ||
| 345 | /* Now gc_candidates contains only garbage. Restore original | ||
| 346 | * inflight counters for these as well, and remove the skbuffs | ||
| 347 | * which are creating the cycle(s). | ||
| 348 | */ | ||
| 349 | skb_queue_head_init(&hitlist); | ||
| 350 | list_for_each_entry(u, &gc_candidates, link) | ||
| 351 | scan_children(&u->sk, inc_inflight, &hitlist); | ||
| 352 | |||
| 344 | /* not_cycle_list contains those sockets which do not make up a | 353 | /* not_cycle_list contains those sockets which do not make up a |
| 345 | * cycle. Restore these to the inflight list. | 354 | * cycle. Restore these to the inflight list. |
| 346 | */ | 355 | */ |
| @@ -350,14 +359,6 @@ void unix_gc(void) | |||
| 350 | list_move_tail(&u->link, &gc_inflight_list); | 359 | list_move_tail(&u->link, &gc_inflight_list); |
| 351 | } | 360 | } |
| 352 | 361 | ||
| 353 | /* Now gc_candidates contains only garbage. Restore original | ||
| 354 | * inflight counters for these as well, and remove the skbuffs | ||
| 355 | * which are creating the cycle(s). | ||
| 356 | */ | ||
| 357 | skb_queue_head_init(&hitlist); | ||
| 358 | list_for_each_entry(u, &gc_candidates, link) | ||
| 359 | scan_children(&u->sk, inc_inflight, &hitlist); | ||
| 360 | |||
| 361 | spin_unlock(&unix_gc_lock); | 362 | spin_unlock(&unix_gc_lock); |
| 362 | 363 | ||
| 363 | /* Here we are. Hitlist is filled. Die. */ | 364 | /* Here we are. Hitlist is filled. Die. */ |
