diff options
-rw-r--r-- | fs/compat.c | 24 | ||||
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/namespace.c | 77 |
3 files changed, 60 insertions, 42 deletions
diff --git a/fs/compat.c b/fs/compat.c index 3aa48834a222..d576b552e8e2 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -768,13 +768,13 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | |||
768 | char __user * type, unsigned long flags, | 768 | char __user * type, unsigned long flags, |
769 | void __user * data) | 769 | void __user * data) |
770 | { | 770 | { |
771 | unsigned long type_page; | 771 | char *kernel_type; |
772 | unsigned long data_page; | 772 | unsigned long data_page; |
773 | unsigned long dev_page; | 773 | char *kernel_dev; |
774 | char *dir_page; | 774 | char *dir_page; |
775 | int retval; | 775 | int retval; |
776 | 776 | ||
777 | retval = copy_mount_options (type, &type_page); | 777 | retval = copy_mount_string(type, &kernel_type); |
778 | if (retval < 0) | 778 | if (retval < 0) |
779 | goto out; | 779 | goto out; |
780 | 780 | ||
@@ -783,38 +783,38 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | |||
783 | if (IS_ERR(dir_page)) | 783 | if (IS_ERR(dir_page)) |
784 | goto out1; | 784 | goto out1; |
785 | 785 | ||
786 | retval = copy_mount_options (dev_name, &dev_page); | 786 | retval = copy_mount_string(dev_name, &kernel_dev); |
787 | if (retval < 0) | 787 | if (retval < 0) |
788 | goto out2; | 788 | goto out2; |
789 | 789 | ||
790 | retval = copy_mount_options (data, &data_page); | 790 | retval = copy_mount_options(data, &data_page); |
791 | if (retval < 0) | 791 | if (retval < 0) |
792 | goto out3; | 792 | goto out3; |
793 | 793 | ||
794 | retval = -EINVAL; | 794 | retval = -EINVAL; |
795 | 795 | ||
796 | if (type_page && data_page) { | 796 | if (kernel_type && data_page) { |
797 | if (!strcmp((char *)type_page, SMBFS_NAME)) { | 797 | if (!strcmp(kernel_type, SMBFS_NAME)) { |
798 | do_smb_super_data_conv((void *)data_page); | 798 | do_smb_super_data_conv((void *)data_page); |
799 | } else if (!strcmp((char *)type_page, NCPFS_NAME)) { | 799 | } else if (!strcmp(kernel_type, NCPFS_NAME)) { |
800 | do_ncp_super_data_conv((void *)data_page); | 800 | do_ncp_super_data_conv((void *)data_page); |
801 | } else if (!strcmp((char *)type_page, NFS4_NAME)) { | 801 | } else if (!strcmp(kernel_type, NFS4_NAME)) { |
802 | if (do_nfs4_super_data_conv((void *) data_page)) | 802 | if (do_nfs4_super_data_conv((void *) data_page)) |
803 | goto out4; | 803 | goto out4; |
804 | } | 804 | } |
805 | } | 805 | } |
806 | 806 | ||
807 | retval = do_mount((char*)dev_page, dir_page, (char*)type_page, | 807 | retval = do_mount(kernel_dev, dir_page, kernel_type, |
808 | flags, (void*)data_page); | 808 | flags, (void*)data_page); |
809 | 809 | ||
810 | out4: | 810 | out4: |
811 | free_page(data_page); | 811 | free_page(data_page); |
812 | out3: | 812 | out3: |
813 | free_page(dev_page); | 813 | kfree(kernel_dev); |
814 | out2: | 814 | out2: |
815 | putname(dir_page); | 815 | putname(dir_page); |
816 | out1: | 816 | out1: |
817 | free_page(type_page); | 817 | kfree(kernel_type); |
818 | out: | 818 | out: |
819 | return retval; | 819 | return retval; |
820 | } | 820 | } |
diff --git a/fs/internal.h b/fs/internal.h index d55ef562f0bb..515175b8b72e 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -57,6 +57,7 @@ extern int check_unsafe_exec(struct linux_binprm *); | |||
57 | * namespace.c | 57 | * namespace.c |
58 | */ | 58 | */ |
59 | extern int copy_mount_options(const void __user *, unsigned long *); | 59 | extern int copy_mount_options(const void __user *, unsigned long *); |
60 | extern int copy_mount_string(const void __user *, char **); | ||
60 | 61 | ||
61 | extern void free_vfsmnt(struct vfsmount *); | 62 | extern void free_vfsmnt(struct vfsmount *); |
62 | extern struct vfsmount *alloc_vfsmnt(const char *); | 63 | extern struct vfsmount *alloc_vfsmnt(const char *); |
diff --git a/fs/namespace.c b/fs/namespace.c index 7230787d18b0..bdc3cb4fd222 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1640,7 +1640,7 @@ static int do_new_mount(struct path *path, char *type, int flags, | |||
1640 | { | 1640 | { |
1641 | struct vfsmount *mnt; | 1641 | struct vfsmount *mnt; |
1642 | 1642 | ||
1643 | if (!type || !memchr(type, 0, PAGE_SIZE)) | 1643 | if (!type) |
1644 | return -EINVAL; | 1644 | return -EINVAL; |
1645 | 1645 | ||
1646 | /* we need capabilities... */ | 1646 | /* we need capabilities... */ |
@@ -1871,6 +1871,23 @@ int copy_mount_options(const void __user * data, unsigned long *where) | |||
1871 | return 0; | 1871 | return 0; |
1872 | } | 1872 | } |
1873 | 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 | |||
1874 | /* | 1891 | /* |
1875 | * 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 |
1876 | * 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). |
@@ -1900,8 +1917,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1900 | 1917 | ||
1901 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) | 1918 | if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) |
1902 | return -EINVAL; | 1919 | return -EINVAL; |
1903 | if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) | ||
1904 | return -EINVAL; | ||
1905 | 1920 | ||
1906 | if (data_page) | 1921 | if (data_page) |
1907 | ((char *)data_page)[PAGE_SIZE - 1] = 0; | 1922 | ((char *)data_page)[PAGE_SIZE - 1] = 0; |
@@ -2070,40 +2085,42 @@ EXPORT_SYMBOL(create_mnt_ns); | |||
2070 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2085 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2071 | char __user *, type, unsigned long, flags, void __user *, data) | 2086 | char __user *, type, unsigned long, flags, void __user *, data) |
2072 | { | 2087 | { |
2073 | int retval; | 2088 | int ret; |
2089 | char *kernel_type; | ||
2090 | char *kernel_dir; | ||
2091 | char *kernel_dev; | ||
2074 | unsigned long data_page; | 2092 | unsigned long data_page; |
2075 | unsigned long type_page; | ||
2076 | unsigned long dev_page; | ||
2077 | char *dir_page; | ||
2078 | 2093 | ||
2079 | retval = copy_mount_options(type, &type_page); | 2094 | ret = copy_mount_string(type, &kernel_type); |
2080 | if (retval < 0) | 2095 | if (ret < 0) |
2081 | return retval; | 2096 | goto out_type; |
2082 | 2097 | ||
2083 | dir_page = getname(dir_name); | 2098 | kernel_dir = getname(dir_name); |
2084 | retval = PTR_ERR(dir_page); | 2099 | if (IS_ERR(kernel_dir)) { |
2085 | if (IS_ERR(dir_page)) | 2100 | ret = PTR_ERR(kernel_dir); |
2086 | goto out1; | 2101 | goto out_dir; |
2102 | } | ||
2087 | 2103 | ||
2088 | retval = copy_mount_options(dev_name, &dev_page); | 2104 | ret = copy_mount_string(dev_name, &kernel_dev); |
2089 | if (retval < 0) | 2105 | if (ret < 0) |
2090 | goto out2; | 2106 | goto out_dev; |
2091 | 2107 | ||
2092 | retval = copy_mount_options(data, &data_page); | 2108 | ret = copy_mount_options(data, &data_page); |
2093 | if (retval < 0) | 2109 | if (ret < 0) |
2094 | goto out3; | 2110 | goto out_data; |
2095 | 2111 | ||
2096 | retval = do_mount((char *)dev_page, dir_page, (char *)type_page, | 2112 | ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, |
2097 | flags, (void *)data_page); | 2113 | (void *) data_page); |
2098 | free_page(data_page); | ||
2099 | 2114 | ||
2100 | out3: | 2115 | free_page(data_page); |
2101 | free_page(dev_page); | 2116 | out_data: |
2102 | out2: | 2117 | kfree(kernel_dev); |
2103 | putname(dir_page); | 2118 | out_dev: |
2104 | out1: | 2119 | putname(kernel_dir); |
2105 | free_page(type_page); | 2120 | out_dir: |
2106 | return retval; | 2121 | kfree(kernel_type); |
2122 | out_type: | ||
2123 | return ret; | ||
2107 | } | 2124 | } |
2108 | 2125 | ||
2109 | /* | 2126 | /* |