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) |
