Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be6d3e56 authored by Kentaro Takeda's avatar Kentaro Takeda Committed by Al Viro
Browse files

introduce new LSM hooks where vfsmount is available.



Add new LSM hooks for path-based checks.  Call them on directory-modifying
operations at the points where we still know the vfsmount involved.

Signed-off-by: default avatarKentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarToshiharu Harada <haradats@nttdata.co.jp>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6a94cb73
Loading
Loading
Loading
Loading
+36 −0
Original line number Original line Diff line number Diff line
@@ -1556,6 +1556,9 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
		 * Refuse to truncate files with mandatory locks held on them.
		 * Refuse to truncate files with mandatory locks held on them.
		 */
		 */
		error = locks_verify_locked(inode);
		error = locks_verify_locked(inode);
		if (!error)
			error = security_path_truncate(&nd->path, 0,
					       ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
		if (!error) {
		if (!error) {
			DQUOT_INIT(inode);
			DQUOT_INIT(inode);


@@ -1586,7 +1589,11 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,


	if (!IS_POSIXACL(dir->d_inode))
	if (!IS_POSIXACL(dir->d_inode))
		mode &= ~current->fs->umask;
		mode &= ~current->fs->umask;
	error = security_path_mknod(&nd->path, path->dentry, mode, 0);
	if (error)
		goto out_unlock;
	error = vfs_create(dir->d_inode, path->dentry, mode, nd);
	error = vfs_create(dir->d_inode, path->dentry, mode, nd);
out_unlock:
	mutex_unlock(&dir->d_inode->i_mutex);
	mutex_unlock(&dir->d_inode->i_mutex);
	dput(nd->path.dentry);
	dput(nd->path.dentry);
	nd->path.dentry = path->dentry;
	nd->path.dentry = path->dentry;
@@ -1999,6 +2006,9 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(nd.path.mnt);
	if (error)
	if (error)
		goto out_dput;
		goto out_dput;
	error = security_path_mknod(&nd.path, dentry, mode, dev);
	if (error)
		goto out_drop_write;
	switch (mode & S_IFMT) {
	switch (mode & S_IFMT) {
		case 0: case S_IFREG:
		case 0: case S_IFREG:
			error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
			error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
@@ -2011,6 +2021,7 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
			break;
			break;
	}
	}
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(nd.path.mnt);
out_dput:
out_dput:
	dput(dentry);
	dput(dentry);
@@ -2070,7 +2081,11 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(nd.path.mnt);
	if (error)
	if (error)
		goto out_dput;
		goto out_dput;
	error = security_path_mkdir(&nd.path, dentry, mode);
	if (error)
		goto out_drop_write;
	error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
	error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(nd.path.mnt);
out_dput:
out_dput:
	dput(dentry);
	dput(dentry);
@@ -2180,7 +2195,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(nd.path.mnt);
	if (error)
	if (error)
		goto exit3;
		goto exit3;
	error = security_path_rmdir(&nd.path, dentry);
	if (error)
		goto exit4;
	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
exit4:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(nd.path.mnt);
exit3:
exit3:
	dput(dentry);
	dput(dentry);
@@ -2265,7 +2284,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
		error = mnt_want_write(nd.path.mnt);
		error = mnt_want_write(nd.path.mnt);
		if (error)
		if (error)
			goto exit2;
			goto exit2;
		error = security_path_unlink(&nd.path, dentry);
		if (error)
			goto exit3;
		error = vfs_unlink(nd.path.dentry->d_inode, dentry);
		error = vfs_unlink(nd.path.dentry->d_inode, dentry);
exit3:
		mnt_drop_write(nd.path.mnt);
		mnt_drop_write(nd.path.mnt);
	exit2:
	exit2:
		dput(dentry);
		dput(dentry);
@@ -2346,7 +2369,11 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(nd.path.mnt);
	if (error)
	if (error)
		goto out_dput;
		goto out_dput;
	error = security_path_symlink(&nd.path, dentry, from);
	if (error)
		goto out_drop_write;
	error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
	error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(nd.path.mnt);
out_dput:
out_dput:
	dput(dentry);
	dput(dentry);
@@ -2443,7 +2470,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
	error = mnt_want_write(nd.path.mnt);
	error = mnt_want_write(nd.path.mnt);
	if (error)
	if (error)
		goto out_dput;
		goto out_dput;
	error = security_path_link(old_path.dentry, &nd.path, new_dentry);
	if (error)
		goto out_drop_write;
	error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
	error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
out_drop_write:
	mnt_drop_write(nd.path.mnt);
	mnt_drop_write(nd.path.mnt);
out_dput:
out_dput:
	dput(new_dentry);
	dput(new_dentry);
@@ -2679,8 +2710,13 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
	error = mnt_want_write(oldnd.path.mnt);
	error = mnt_want_write(oldnd.path.mnt);
	if (error)
	if (error)
		goto exit5;
		goto exit5;
	error = security_path_rename(&oldnd.path, old_dentry,
				     &newnd.path, new_dentry);
	if (error)
		goto exit6;
	error = vfs_rename(old_dir->d_inode, old_dentry,
	error = vfs_rename(old_dir->d_inode, old_dentry,
				   new_dir->d_inode, new_dentry);
				   new_dir->d_inode, new_dentry);
exit6:
	mnt_drop_write(oldnd.path.mnt);
	mnt_drop_write(oldnd.path.mnt);
exit5:
exit5:
	dput(new_dentry);
	dput(new_dentry);
+5 −0
Original line number Original line Diff line number Diff line
@@ -272,6 +272,8 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
		goto put_write_and_out;
		goto put_write_and_out;


	error = locks_verify_truncate(inode, NULL, length);
	error = locks_verify_truncate(inode, NULL, length);
	if (!error)
		error = security_path_truncate(&path, length, 0);
	if (!error) {
	if (!error) {
		DQUOT_INIT(inode);
		DQUOT_INIT(inode);
		error = do_truncate(path.dentry, length, 0, NULL);
		error = do_truncate(path.dentry, length, 0, NULL);
@@ -328,6 +330,9 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
		goto out_putf;
		goto out_putf;


	error = locks_verify_truncate(inode, file, length);
	error = locks_verify_truncate(inode, file, length);
	if (!error)
		error = security_path_truncate(&file->f_path, length,
					       ATTR_MTIME|ATTR_CTIME);
	if (!error)
	if (!error)
		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
out_putf:
+137 −0
Original line number Original line Diff line number Diff line
@@ -335,17 +335,37 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 *	@dir contains the inode structure of the parent directory of the new link.
 *	@dir contains the inode structure of the parent directory of the new link.
 *	@new_dentry contains the dentry structure for the new link.
 *	@new_dentry contains the dentry structure for the new link.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_link:
 *	Check permission before creating a new hard link to a file.
 *	@old_dentry contains the dentry structure for an existing link
 *	to the file.
 *	@new_dir contains the path structure of the parent directory of
 *	the new link.
 *	@new_dentry contains the dentry structure for the new link.
 *	Return 0 if permission is granted.
 * @inode_unlink:
 * @inode_unlink:
 *	Check the permission to remove a hard link to a file.
 *	Check the permission to remove a hard link to a file.
 *	@dir contains the inode structure of parent directory of the file.
 *	@dir contains the inode structure of parent directory of the file.
 *	@dentry contains the dentry structure for file to be unlinked.
 *	@dentry contains the dentry structure for file to be unlinked.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_unlink:
 *	Check the permission to remove a hard link to a file.
 *	@dir contains the path structure of parent directory of the file.
 *	@dentry contains the dentry structure for file to be unlinked.
 *	Return 0 if permission is granted.
 * @inode_symlink:
 * @inode_symlink:
 *	Check the permission to create a symbolic link to a file.
 *	Check the permission to create a symbolic link to a file.
 *	@dir contains the inode structure of parent directory of the symbolic link.
 *	@dir contains the inode structure of parent directory of the symbolic link.
 *	@dentry contains the dentry structure of the symbolic link.
 *	@dentry contains the dentry structure of the symbolic link.
 *	@old_name contains the pathname of file.
 *	@old_name contains the pathname of file.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_symlink:
 *	Check the permission to create a symbolic link to a file.
 *	@dir contains the path structure of parent directory of
 *	the symbolic link.
 *	@dentry contains the dentry structure of the symbolic link.
 *	@old_name contains the pathname of file.
 *	Return 0 if permission is granted.
 * @inode_mkdir:
 * @inode_mkdir:
 *	Check permissions to create a new directory in the existing directory
 *	Check permissions to create a new directory in the existing directory
 *	associated with inode strcture @dir.
 *	associated with inode strcture @dir.
@@ -353,11 +373,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 *	@dentry contains the dentry structure of new directory.
 *	@dentry contains the dentry structure of new directory.
 *	@mode contains the mode of new directory.
 *	@mode contains the mode of new directory.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_mkdir:
 *	Check permissions to create a new directory in the existing directory
 *	associated with path strcture @path.
 *	@dir containst the path structure of parent of the directory
 *	to be created.
 *	@dentry contains the dentry structure of new directory.
 *	@mode contains the mode of new directory.
 *	Return 0 if permission is granted.
 * @inode_rmdir:
 * @inode_rmdir:
 *	Check the permission to remove a directory.
 *	Check the permission to remove a directory.
 *	@dir contains the inode structure of parent of the directory to be removed.
 *	@dir contains the inode structure of parent of the directory to be removed.
 *	@dentry contains the dentry structure of directory to be removed.
 *	@dentry contains the dentry structure of directory to be removed.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_rmdir:
 *	Check the permission to remove a directory.
 *	@dir contains the path structure of parent of the directory to be
 *	removed.
 *	@dentry contains the dentry structure of directory to be removed.
 *	Return 0 if permission is granted.
 * @inode_mknod:
 * @inode_mknod:
 *	Check permissions when creating a special file (or a socket or a fifo
 *	Check permissions when creating a special file (or a socket or a fifo
 *	file created via the mknod system call).  Note that if mknod operation
 *	file created via the mknod system call).  Note that if mknod operation
@@ -368,6 +402,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 *	@mode contains the mode of the new file.
 *	@mode contains the mode of the new file.
 *	@dev contains the device number.
 *	@dev contains the device number.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_mknod:
 *	Check permissions when creating a file. Note that this hook is called
 *	even if mknod operation is being done for a regular file.
 *	@dir contains the path structure of parent of the new file.
 *	@dentry contains the dentry structure of the new file.
 *	@mode contains the mode of the new file.
 *	@dev contains the undecoded device number. Use new_decode_dev() to get
 *	the decoded device number.
 *	Return 0 if permission is granted.
 * @inode_rename:
 * @inode_rename:
 *	Check for permission to rename a file or directory.
 *	Check for permission to rename a file or directory.
 *	@old_dir contains the inode structure for parent of the old link.
 *	@old_dir contains the inode structure for parent of the old link.
@@ -375,6 +418,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 *	@new_dir contains the inode structure for parent of the new link.
 *	@new_dir contains the inode structure for parent of the new link.
 *	@new_dentry contains the dentry structure of the new link.
 *	@new_dentry contains the dentry structure of the new link.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_rename:
 *	Check for permission to rename a file or directory.
 *	@old_dir contains the path structure for parent of the old link.
 *	@old_dentry contains the dentry structure of the old link.
 *	@new_dir contains the path structure for parent of the new link.
 *	@new_dentry contains the dentry structure of the new link.
 *	Return 0 if permission is granted.
 * @inode_readlink:
 * @inode_readlink:
 *	Check the permission to read the symbolic link.
 *	Check the permission to read the symbolic link.
 *	@dentry contains the dentry structure for the file link.
 *	@dentry contains the dentry structure for the file link.
@@ -403,6 +453,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 *	@dentry contains the dentry structure for the file.
 *	@dentry contains the dentry structure for the file.
 *	@attr is the iattr structure containing the new file attributes.
 *	@attr is the iattr structure containing the new file attributes.
 *	Return 0 if permission is granted.
 *	Return 0 if permission is granted.
 * @path_truncate:
 *	Check permission before truncating a file.
 *	@path contains the path structure for the file.
 *	@length is the new length of the file.
 *	@time_attrs is the flags passed to do_truncate().
 *	Return 0 if permission is granted.
 * @inode_getattr:
 * @inode_getattr:
 *	Check permission before obtaining file attributes.
 *	Check permission before obtaining file attributes.
 *	@mnt is the vfsmount where the dentry was looked up
 *	@mnt is the vfsmount where the dentry was looked up
@@ -1331,6 +1387,22 @@ struct security_operations {
				   struct super_block *newsb);
				   struct super_block *newsb);
	int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
	int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);


#ifdef CONFIG_SECURITY_PATH
	int (*path_unlink) (struct path *dir, struct dentry *dentry);
	int (*path_mkdir) (struct path *dir, struct dentry *dentry, int mode);
	int (*path_rmdir) (struct path *dir, struct dentry *dentry);
	int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
			   unsigned int dev);
	int (*path_truncate) (struct path *path, loff_t length,
			      unsigned int time_attrs);
	int (*path_symlink) (struct path *dir, struct dentry *dentry,
			     const char *old_name);
	int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
			  struct dentry *new_dentry);
	int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
			    struct path *new_dir, struct dentry *new_dentry);
#endif

	int (*inode_alloc_security) (struct inode *inode);
	int (*inode_alloc_security) (struct inode *inode);
	void (*inode_free_security) (struct inode *inode);
	void (*inode_free_security) (struct inode *inode);
	int (*inode_init_security) (struct inode *inode, struct inode *dir,
	int (*inode_init_security) (struct inode *inode, struct inode *dir,
@@ -2705,6 +2777,71 @@ static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi


#endif	/* CONFIG_SECURITY_NETWORK_XFRM */
#endif	/* CONFIG_SECURITY_NETWORK_XFRM */


#ifdef CONFIG_SECURITY_PATH
int security_path_unlink(struct path *dir, struct dentry *dentry);
int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
int security_path_rmdir(struct path *dir, struct dentry *dentry);
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
			unsigned int dev);
int security_path_truncate(struct path *path, loff_t length,
			   unsigned int time_attrs);
int security_path_symlink(struct path *dir, struct dentry *dentry,
			  const char *old_name);
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
		       struct dentry *new_dentry);
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
			 struct path *new_dir, struct dentry *new_dentry);
#else	/* CONFIG_SECURITY_PATH */
static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
{
	return 0;
}

static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
				      int mode)
{
	return 0;
}

static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
{
	return 0;
}

static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
				      int mode, unsigned int dev)
{
	return 0;
}

static inline int security_path_truncate(struct path *path, loff_t length,
					 unsigned int time_attrs)
{
	return 0;
}

static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
					const char *old_name)
{
	return 0;
}

static inline int security_path_link(struct dentry *old_dentry,
				     struct path *new_dir,
				     struct dentry *new_dentry)
{
	return 0;
}

static inline int security_path_rename(struct path *old_dir,
				       struct dentry *old_dentry,
				       struct path *new_dir,
				       struct dentry *new_dentry)
{
	return 0;
}
#endif	/* CONFIG_SECURITY_PATH */

#ifdef CONFIG_KEYS
#ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY
#ifdef CONFIG_SECURITY


+4 −0
Original line number Original line Diff line number Diff line
@@ -836,7 +836,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
		err = mnt_want_write(nd.path.mnt);
		err = mnt_want_write(nd.path.mnt);
		if (err)
		if (err)
			goto out_mknod_dput;
			goto out_mknod_dput;
		err = security_path_mknod(&nd.path, dentry, mode, 0);
		if (err)
			goto out_mknod_drop_write;
		err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
		err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
out_mknod_drop_write:
		mnt_drop_write(nd.path.mnt);
		mnt_drop_write(nd.path.mnt);
		if (err)
		if (err)
			goto out_mknod_dput;
			goto out_mknod_dput;
+9 −0
Original line number Original line Diff line number Diff line
@@ -81,6 +81,15 @@ config SECURITY_NETWORK_XFRM
	  IPSec.
	  IPSec.
	  If you are unsure how to answer this question, answer N.
	  If you are unsure how to answer this question, answer N.


config SECURITY_PATH
	bool "Security hooks for pathname based access control"
	depends on SECURITY
	help
	  This enables the security hooks for pathname based access control.
	  If enabled, a security module can use these hooks to
	  implement pathname based access controls.
	  If you are unsure how to answer this question, answer N.

config SECURITY_FILE_CAPABILITIES
config SECURITY_FILE_CAPABILITIES
	bool "File POSIX Capabilities"
	bool "File POSIX Capabilities"
	default n
	default n
Loading