diff options
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 49 | 
1 files changed, 29 insertions, 20 deletions
| diff --git a/fs/namespace.c b/fs/namespace.c index 0570729c87fd..a830e1463704 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1584,6 +1584,14 @@ static inline bool may_mount(void)  	return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN);  } +static inline bool may_mandlock(void) +{ +#ifndef	CONFIG_MANDATORY_FILE_LOCKING +	return false; +#endif +	return capable(CAP_SYS_ADMIN); +} +  /*   * Now umount can handle mount points as well as block devices.   * This is important for filesystems which use unnamed block devices. @@ -2601,18 +2609,18 @@ static long exact_copy_from_user(void *to, const void __user * from,  	return n;  } -int copy_mount_options(const void __user * data, unsigned long *where) +void *copy_mount_options(const void __user * data)  {  	int i; -	unsigned long page;  	unsigned long size; +	char *copy; -	*where = 0;  	if (!data) -		return 0; +		return NULL; -	if (!(page = __get_free_page(GFP_KERNEL))) -		return -ENOMEM; +	copy = kmalloc(PAGE_SIZE, GFP_KERNEL); +	if (!copy) +		return ERR_PTR(-ENOMEM);  	/* We only care that *some* data at the address the user  	 * gave us is valid.  Just in case, we'll zero @@ -2623,15 +2631,14 @@ int copy_mount_options(const void __user * data, unsigned long *where)  	if (size > PAGE_SIZE)  		size = PAGE_SIZE; -	i = size - exact_copy_from_user((void *)page, data, size); +	i = size - exact_copy_from_user(copy, data, size);  	if (!i) { -		free_page(page); -		return -EFAULT; +		kfree(copy); +		return ERR_PTR(-EFAULT);  	}  	if (i != PAGE_SIZE) -		memset((char *)page + i, 0, PAGE_SIZE - i); -	*where = page; -	return 0; +		memset(copy + i, 0, PAGE_SIZE - i); +	return copy;  }  char *copy_mount_string(const void __user *data) @@ -2677,6 +2684,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,  				   type_page, flags, data_page);  	if (!retval && !may_mount())  		retval = -EPERM; +	if (!retval && (flags & MS_MANDLOCK) && !may_mandlock()) +		retval = -EPERM;  	if (retval)  		goto dput_out; @@ -2896,7 +2905,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,  	int ret;  	char *kernel_type;  	char *kernel_dev; -	unsigned long data_page; +	void *options;  	kernel_type = copy_mount_string(type);  	ret = PTR_ERR(kernel_type); @@ -2908,14 +2917,14 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,  	if (IS_ERR(kernel_dev))  		goto out_dev; -	ret = copy_mount_options(data, &data_page); -	if (ret < 0) +	options = copy_mount_options(data); +	ret = PTR_ERR(options); +	if (IS_ERR(options))  		goto out_data; -	ret = do_mount(kernel_dev, dir_name, kernel_type, flags, -		(void *) data_page); +	ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options); -	free_page(data_page); +	kfree(options);  out_data:  	kfree(kernel_dev);  out_dev: @@ -2939,9 +2948,9 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,  	return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);  } -int path_is_under(struct path *path1, struct path *path2) +bool path_is_under(struct path *path1, struct path *path2)  { -	int res; +	bool res;  	read_seqlock_excl(&mount_lock);  	res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2);  	read_sequnlock_excl(&mount_lock); | 
