diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 66 |
1 files changed, 26 insertions, 40 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f1dffe84f0d5..433ae1bbef97 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -954,20 +954,32 @@ fail: | |||
954 | return NULL; | 954 | return NULL; |
955 | } | 955 | } |
956 | 956 | ||
957 | static int unix_mknod(struct dentry *dentry, const struct path *path, umode_t mode, | 957 | static int unix_mknod(const char *sun_path, umode_t mode, struct path *res) |
958 | struct path *res) | ||
959 | { | 958 | { |
960 | int err; | 959 | struct dentry *dentry; |
960 | struct path path; | ||
961 | int err = 0; | ||
962 | /* | ||
963 | * Get the parent directory, calculate the hash for last | ||
964 | * component. | ||
965 | */ | ||
966 | dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); | ||
967 | err = PTR_ERR(dentry); | ||
968 | if (IS_ERR(dentry)) | ||
969 | return err; | ||
961 | 970 | ||
962 | err = security_path_mknod(path, dentry, mode, 0); | 971 | /* |
972 | * All right, let's create it. | ||
973 | */ | ||
974 | err = security_path_mknod(&path, dentry, mode, 0); | ||
963 | if (!err) { | 975 | if (!err) { |
964 | err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0); | 976 | err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0); |
965 | if (!err) { | 977 | if (!err) { |
966 | res->mnt = mntget(path->mnt); | 978 | res->mnt = mntget(path.mnt); |
967 | res->dentry = dget(dentry); | 979 | res->dentry = dget(dentry); |
968 | } | 980 | } |
969 | } | 981 | } |
970 | 982 | done_path_create(&path, dentry); | |
971 | return err; | 983 | return err; |
972 | } | 984 | } |
973 | 985 | ||
@@ -978,12 +990,10 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
978 | struct unix_sock *u = unix_sk(sk); | 990 | struct unix_sock *u = unix_sk(sk); |
979 | struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; | 991 | struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; |
980 | char *sun_path = sunaddr->sun_path; | 992 | char *sun_path = sunaddr->sun_path; |
981 | int err, name_err; | 993 | int err; |
982 | unsigned int hash; | 994 | unsigned int hash; |
983 | struct unix_address *addr; | 995 | struct unix_address *addr; |
984 | struct hlist_head *list; | 996 | struct hlist_head *list; |
985 | struct path path; | ||
986 | struct dentry *dentry; | ||
987 | 997 | ||
988 | err = -EINVAL; | 998 | err = -EINVAL; |
989 | if (sunaddr->sun_family != AF_UNIX) | 999 | if (sunaddr->sun_family != AF_UNIX) |
@@ -999,34 +1009,14 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
999 | goto out; | 1009 | goto out; |
1000 | addr_len = err; | 1010 | addr_len = err; |
1001 | 1011 | ||
1002 | name_err = 0; | ||
1003 | dentry = NULL; | ||
1004 | if (sun_path[0]) { | ||
1005 | /* Get the parent directory, calculate the hash for last | ||
1006 | * component. | ||
1007 | */ | ||
1008 | dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); | ||
1009 | |||
1010 | if (IS_ERR(dentry)) { | ||
1011 | /* delay report until after 'already bound' check */ | ||
1012 | name_err = PTR_ERR(dentry); | ||
1013 | dentry = NULL; | ||
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | err = mutex_lock_interruptible(&u->readlock); | 1012 | err = mutex_lock_interruptible(&u->readlock); |
1018 | if (err) | 1013 | if (err) |
1019 | goto out_path; | 1014 | goto out; |
1020 | 1015 | ||
1021 | err = -EINVAL; | 1016 | err = -EINVAL; |
1022 | if (u->addr) | 1017 | if (u->addr) |
1023 | goto out_up; | 1018 | goto out_up; |
1024 | 1019 | ||
1025 | if (name_err) { | ||
1026 | err = name_err == -EEXIST ? -EADDRINUSE : name_err; | ||
1027 | goto out_up; | ||
1028 | } | ||
1029 | |||
1030 | err = -ENOMEM; | 1020 | err = -ENOMEM; |
1031 | addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); | 1021 | addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); |
1032 | if (!addr) | 1022 | if (!addr) |
@@ -1037,11 +1027,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
1037 | addr->hash = hash ^ sk->sk_type; | 1027 | addr->hash = hash ^ sk->sk_type; |
1038 | atomic_set(&addr->refcnt, 1); | 1028 | atomic_set(&addr->refcnt, 1); |
1039 | 1029 | ||
1040 | if (dentry) { | 1030 | if (sun_path[0]) { |
1041 | struct path u_path; | 1031 | struct path path; |
1042 | umode_t mode = S_IFSOCK | | 1032 | umode_t mode = S_IFSOCK | |
1043 | (SOCK_INODE(sock)->i_mode & ~current_umask()); | 1033 | (SOCK_INODE(sock)->i_mode & ~current_umask()); |
1044 | err = unix_mknod(dentry, &path, mode, &u_path); | 1034 | err = unix_mknod(sun_path, mode, &path); |
1045 | if (err) { | 1035 | if (err) { |
1046 | if (err == -EEXIST) | 1036 | if (err == -EEXIST) |
1047 | err = -EADDRINUSE; | 1037 | err = -EADDRINUSE; |
@@ -1049,9 +1039,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
1049 | goto out_up; | 1039 | goto out_up; |
1050 | } | 1040 | } |
1051 | addr->hash = UNIX_HASH_SIZE; | 1041 | addr->hash = UNIX_HASH_SIZE; |
1052 | hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1); | 1042 | hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); |
1053 | spin_lock(&unix_table_lock); | 1043 | spin_lock(&unix_table_lock); |
1054 | u->path = u_path; | 1044 | u->path = path; |
1055 | list = &unix_socket_table[hash]; | 1045 | list = &unix_socket_table[hash]; |
1056 | } else { | 1046 | } else { |
1057 | spin_lock(&unix_table_lock); | 1047 | spin_lock(&unix_table_lock); |
@@ -1074,10 +1064,6 @@ out_unlock: | |||
1074 | spin_unlock(&unix_table_lock); | 1064 | spin_unlock(&unix_table_lock); |
1075 | out_up: | 1065 | out_up: |
1076 | mutex_unlock(&u->readlock); | 1066 | mutex_unlock(&u->readlock); |
1077 | out_path: | ||
1078 | if (dentry) | ||
1079 | done_path_create(&path, dentry); | ||
1080 | |||
1081 | out: | 1067 | out: |
1082 | return err; | 1068 | return err; |
1083 | } | 1069 | } |