diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 80 |
1 files changed, 63 insertions, 17 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2358f2690ec5..e2d18b9f910f 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -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 | } |
@@ -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 | } |
@@ -2113,8 +2119,8 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, | |||
2113 | mutex_lock(&u->iolock); | 2119 | mutex_lock(&u->iolock); |
2114 | 2120 | ||
2115 | skip = sk_peek_offset(sk, flags); | 2121 | skip = sk_peek_offset(sk, flags); |
2116 | skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err, | 2122 | skb = __skb_try_recv_datagram(sk, flags, NULL, &peeked, &skip, |
2117 | &last); | 2123 | &err, &last); |
2118 | if (skb) | 2124 | if (skb) |
2119 | break; | 2125 | break; |
2120 | 2126 | ||
@@ -2587,6 +2593,43 @@ long unix_outq_len(struct sock *sk) | |||
2587 | } | 2593 | } |
2588 | EXPORT_SYMBOL_GPL(unix_outq_len); | 2594 | EXPORT_SYMBOL_GPL(unix_outq_len); |
2589 | 2595 | ||
2596 | static int unix_open_file(struct sock *sk) | ||
2597 | { | ||
2598 | struct path path; | ||
2599 | struct file *f; | ||
2600 | int fd; | ||
2601 | |||
2602 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) | ||
2603 | return -EPERM; | ||
2604 | |||
2605 | unix_state_lock(sk); | ||
2606 | path = unix_sk(sk)->path; | ||
2607 | if (!path.dentry) { | ||
2608 | unix_state_unlock(sk); | ||
2609 | return -ENOENT; | ||
2610 | } | ||
2611 | |||
2612 | path_get(&path); | ||
2613 | unix_state_unlock(sk); | ||
2614 | |||
2615 | fd = get_unused_fd_flags(O_CLOEXEC); | ||
2616 | if (fd < 0) | ||
2617 | goto out; | ||
2618 | |||
2619 | f = dentry_open(&path, O_PATH, current_cred()); | ||
2620 | if (IS_ERR(f)) { | ||
2621 | put_unused_fd(fd); | ||
2622 | fd = PTR_ERR(f); | ||
2623 | goto out; | ||
2624 | } | ||
2625 | |||
2626 | fd_install(fd, f); | ||
2627 | out: | ||
2628 | path_put(&path); | ||
2629 | |||
2630 | return fd; | ||
2631 | } | ||
2632 | |||
2590 | static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | 2633 | static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
2591 | { | 2634 | { |
2592 | struct sock *sk = sock->sk; | 2635 | struct sock *sk = sock->sk; |
@@ -2605,6 +2648,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
2605 | else | 2648 | else |
2606 | err = put_user(amount, (int __user *)arg); | 2649 | err = put_user(amount, (int __user *)arg); |
2607 | break; | 2650 | break; |
2651 | case SIOCUNIXFILE: | ||
2652 | err = unix_open_file(sk); | ||
2653 | break; | ||
2608 | default: | 2654 | default: |
2609 | err = -ENOIOCTLCMD; | 2655 | err = -ENOIOCTLCMD; |
2610 | break; | 2656 | break; |