diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 3dc283fd4716..bdc3cb4fd222 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/mnt_namespace.h> | 23 | #include <linux/mnt_namespace.h> |
24 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
25 | #include <linux/nsproxy.h> | ||
25 | #include <linux/security.h> | 26 | #include <linux/security.h> |
26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
27 | #include <linux/ramfs.h> | 28 | #include <linux/ramfs.h> |
@@ -315,7 +316,8 @@ EXPORT_SYMBOL_GPL(mnt_clone_write); | |||
315 | */ | 316 | */ |
316 | int mnt_want_write_file(struct file *file) | 317 | int mnt_want_write_file(struct file *file) |
317 | { | 318 | { |
318 | if (!(file->f_mode & FMODE_WRITE)) | 319 | struct inode *inode = file->f_dentry->d_inode; |
320 | if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) | ||
319 | return mnt_want_write(file->f_path.mnt); | 321 | return mnt_want_write(file->f_path.mnt); |
320 | else | 322 | else |
321 | return mnt_clone_write(file->f_path.mnt); | 323 | return mnt_clone_write(file->f_path.mnt); |
@@ -1638,7 +1640,7 @@ static int do_new_mount(struct path *path, char *type, int flags, | |||
1638 | { | 1640 | { |
1639 | struct vfsmount *mnt; | 1641 | struct vfsmount *mnt; |
1640 | 1642 | ||
1641 | if (!type || !memchr(type, 0, PAGE_SIZE)) | 1643 | if (!type) |
1642 | return -EINVAL; | 1644 | return -EINVAL; |
1643 | 1645 | ||
1644 | /* we need capabilities... */ | 1646 | /* we need capabilities... */ |
@@ -1869,6 +1871,23 @@ int copy_mount_options(const void __user * data, unsigned long *where) | |||
1869 | return 0; | 1871 | return 0; |
1870 | } | 1872 | } |
1871 | 1873 | ||
1874 | int copy_mount_string(const void __user *data, char **where) | ||
1875 | { | ||
1876 | char *tmp; | ||
1877 | |||
1878 | if (!data) { | ||
1879 | *where = NULL; | ||
1880 | return 0; | ||
1881 | } | ||
1882 | |||
1883 | tmp = strndup_user(data, PAGE_SIZE); | ||
1884 | if (IS_ERR(tmp)) | ||
1885 | return PTR_ERR(tmp); | ||
1886 | |||
1887 | *where = tmp; | ||
1888 | return 0; | ||
1889 | } | ||
1890 | |||
1872 | /* | 1891 | /* |
1873 | * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to | 1892 | * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to |
1874 | * be given to the mount() call (ie: read-only, no-dev, no-suid etc). | 1893 | * be given to the mount() call (ie: read-only, no-dev, no-suid etc). |
@@ -1898,8 +1917,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1898 | 1917 | ||
1899 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) | 1918 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) |
1900 | return -EINVAL; | 1919 | return -EINVAL; |
1901 | if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) | ||
1902 | return -EINVAL; | ||
1903 | 1920 | ||
1904 | if (data_page) | 1921 | if (data_page) |
1905 | ((char *)data_page)[PAGE_SIZE - 1] = 0; | 1922 | ((char *)data_page)[PAGE_SIZE - 1] = 0; |
@@ -2068,40 +2085,42 @@ EXPORT_SYMBOL(create_mnt_ns); | |||
2068 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2085 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2069 | char __user *, type, unsigned long, flags, void __user *, data) | 2086 | char __user *, type, unsigned long, flags, void __user *, data) |
2070 | { | 2087 | { |
2071 | int retval; | 2088 | int ret; |
2089 | char *kernel_type; | ||
2090 | char *kernel_dir; | ||
2091 | char *kernel_dev; | ||
2072 | unsigned long data_page; | 2092 | unsigned long data_page; |
2073 | unsigned long type_page; | ||
2074 | unsigned long dev_page; | ||
2075 | char *dir_page; | ||
2076 | 2093 | ||
2077 | retval = copy_mount_options(type, &type_page); | 2094 | ret = copy_mount_string(type, &kernel_type); |
2078 | if (retval < 0) | 2095 | if (ret < 0) |
2079 | return retval; | 2096 | goto out_type; |
2080 | 2097 | ||
2081 | dir_page = getname(dir_name); | 2098 | kernel_dir = getname(dir_name); |
2082 | retval = PTR_ERR(dir_page); | 2099 | if (IS_ERR(kernel_dir)) { |
2083 | if (IS_ERR(dir_page)) | 2100 | ret = PTR_ERR(kernel_dir); |
2084 | goto out1; | 2101 | goto out_dir; |
2102 | } | ||
2085 | 2103 | ||
2086 | retval = copy_mount_options(dev_name, &dev_page); | 2104 | ret = copy_mount_string(dev_name, &kernel_dev); |
2087 | if (retval < 0) | 2105 | if (ret < 0) |
2088 | goto out2; | 2106 | goto out_dev; |
2089 | 2107 | ||
2090 | retval = copy_mount_options(data, &data_page); | 2108 | ret = copy_mount_options(data, &data_page); |
2091 | if (retval < 0) | 2109 | if (ret < 0) |
2092 | goto out3; | 2110 | goto out_data; |
2093 | 2111 | ||
2094 | retval = do_mount((char *)dev_page, dir_page, (char *)type_page, | 2112 | ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, |
2095 | flags, (void *)data_page); | 2113 | (void *) data_page); |
2096 | free_page(data_page); | ||
2097 | 2114 | ||
2098 | out3: | 2115 | free_page(data_page); |
2099 | free_page(dev_page); | 2116 | out_data: |
2100 | out2: | 2117 | kfree(kernel_dev); |
2101 | putname(dir_page); | 2118 | out_dev: |
2102 | out1: | 2119 | putname(kernel_dir); |
2103 | free_page(type_page); | 2120 | out_dir: |
2104 | return retval; | 2121 | kfree(kernel_type); |
2122 | out_type: | ||
2123 | return ret; | ||
2105 | } | 2124 | } |
2106 | 2125 | ||
2107 | /* | 2126 | /* |