diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 93 |
1 files changed, 43 insertions, 50 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 79981d97bc9c..e4768c180da2 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -823,6 +823,34 @@ fail: | |||
823 | return NULL; | 823 | return NULL; |
824 | } | 824 | } |
825 | 825 | ||
826 | static int unix_mknod(const char *sun_path, umode_t mode, struct path *res) | ||
827 | { | ||
828 | struct dentry *dentry; | ||
829 | struct path path; | ||
830 | int err = 0; | ||
831 | /* | ||
832 | * Get the parent directory, calculate the hash for last | ||
833 | * component. | ||
834 | */ | ||
835 | dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); | ||
836 | err = PTR_ERR(dentry); | ||
837 | if (IS_ERR(dentry)) | ||
838 | return err; | ||
839 | |||
840 | /* | ||
841 | * All right, let's create it. | ||
842 | */ | ||
843 | err = security_path_mknod(&path, dentry, mode, 0); | ||
844 | if (!err) { | ||
845 | err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); | ||
846 | if (!err) { | ||
847 | res->mnt = mntget(path.mnt); | ||
848 | res->dentry = dget(dentry); | ||
849 | } | ||
850 | } | ||
851 | done_path_create(&path, dentry); | ||
852 | return err; | ||
853 | } | ||
826 | 854 | ||
827 | static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | 855 | static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) |
828 | { | 856 | { |
@@ -831,8 +859,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
831 | struct unix_sock *u = unix_sk(sk); | 859 | struct unix_sock *u = unix_sk(sk); |
832 | struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; | 860 | struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; |
833 | char *sun_path = sunaddr->sun_path; | 861 | char *sun_path = sunaddr->sun_path; |
834 | struct dentry *dentry = NULL; | ||
835 | struct path path; | ||
836 | int err; | 862 | int err; |
837 | unsigned int hash; | 863 | unsigned int hash; |
838 | struct unix_address *addr; | 864 | struct unix_address *addr; |
@@ -869,43 +895,23 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
869 | atomic_set(&addr->refcnt, 1); | 895 | atomic_set(&addr->refcnt, 1); |
870 | 896 | ||
871 | if (sun_path[0]) { | 897 | if (sun_path[0]) { |
872 | umode_t mode; | 898 | struct path path; |
873 | err = 0; | 899 | umode_t mode = S_IFSOCK | |
874 | /* | ||
875 | * Get the parent directory, calculate the hash for last | ||
876 | * component. | ||
877 | */ | ||
878 | dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); | ||
879 | err = PTR_ERR(dentry); | ||
880 | if (IS_ERR(dentry)) | ||
881 | goto out_mknod_parent; | ||
882 | |||
883 | /* | ||
884 | * All right, let's create it. | ||
885 | */ | ||
886 | mode = S_IFSOCK | | ||
887 | (SOCK_INODE(sock)->i_mode & ~current_umask()); | 900 | (SOCK_INODE(sock)->i_mode & ~current_umask()); |
888 | err = mnt_want_write(path.mnt); | 901 | err = unix_mknod(sun_path, mode, &path); |
889 | if (err) | 902 | if (err) { |
890 | goto out_mknod_dput; | 903 | if (err == -EEXIST) |
891 | err = security_path_mknod(&path, dentry, mode, 0); | 904 | err = -EADDRINUSE; |
892 | if (err) | 905 | unix_release_addr(addr); |
893 | goto out_mknod_drop_write; | 906 | goto out_up; |
894 | err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); | 907 | } |
895 | out_mknod_drop_write: | ||
896 | mnt_drop_write(path.mnt); | ||
897 | if (err) | ||
898 | goto out_mknod_dput; | ||
899 | mutex_unlock(&path.dentry->d_inode->i_mutex); | ||
900 | dput(path.dentry); | ||
901 | path.dentry = dentry; | ||
902 | |||
903 | addr->hash = UNIX_HASH_SIZE; | 908 | addr->hash = UNIX_HASH_SIZE; |
904 | } | 909 | hash = path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1); |
905 | 910 | spin_lock(&unix_table_lock); | |
906 | spin_lock(&unix_table_lock); | 911 | u->path = path; |
907 | 912 | list = &unix_socket_table[hash]; | |
908 | if (!sun_path[0]) { | 913 | } else { |
914 | spin_lock(&unix_table_lock); | ||
909 | err = -EADDRINUSE; | 915 | err = -EADDRINUSE; |
910 | if (__unix_find_socket_byname(net, sunaddr, addr_len, | 916 | if (__unix_find_socket_byname(net, sunaddr, addr_len, |
911 | sk->sk_type, hash)) { | 917 | sk->sk_type, hash)) { |
@@ -914,9 +920,6 @@ out_mknod_drop_write: | |||
914 | } | 920 | } |
915 | 921 | ||
916 | list = &unix_socket_table[addr->hash]; | 922 | list = &unix_socket_table[addr->hash]; |
917 | } else { | ||
918 | list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; | ||
919 | u->path = path; | ||
920 | } | 923 | } |
921 | 924 | ||
922 | err = 0; | 925 | err = 0; |
@@ -930,16 +933,6 @@ out_up: | |||
930 | mutex_unlock(&u->readlock); | 933 | mutex_unlock(&u->readlock); |
931 | out: | 934 | out: |
932 | return err; | 935 | return err; |
933 | |||
934 | out_mknod_dput: | ||
935 | dput(dentry); | ||
936 | mutex_unlock(&path.dentry->d_inode->i_mutex); | ||
937 | path_put(&path); | ||
938 | out_mknod_parent: | ||
939 | if (err == -EEXIST) | ||
940 | err = -EADDRINUSE; | ||
941 | unix_release_addr(addr); | ||
942 | goto out_up; | ||
943 | } | 936 | } |
944 | 937 | ||
945 | static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) | 938 | static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) |