[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <48D080D1.5060405@schaufler-ca.com>
Date: Tue, 16 Sep 2008 21:00:17 -0700
From: Casey Schaufler <casey@...aufler-ca.com>
To: Kentaro Takeda <takedakn@...data.co.jp>
CC: linux-security-module@...r.kernel.org,
linux-fsdevel@...r.kernel.org, linux-kernel@...r.kernel.org,
Toshiharu Harada <haradats@...data.co.jp>
Subject: Re: [PATCH] Introduce new LSM hooks where vfsmount is available.
Kentaro Takeda wrote:
> TOMOYO Linux needs method for calculating pathname in LSM module.
> However, we have received comment from Al Viro, the vfs maintainer,
> that adding vfsmount parameter to vfs helper functions (and LSM hooks)
> is not preferable. We have asked some people (including Al), and we
> came back to the most straightforward approach; adding new LSM hooks
> where vfsmount is available.
>
> The attached patch introduces several new LSM hooks TOMOYO Linux
> needs. It has less impact to existing LSM module and no impact to vfs
> helper functions. Please review it.
>
> Regards,
>
>
As always, the community will be eager to see the code that makes
use of these hooks.
> ---
> Subject: Introduce new LSM hooks.
>
> This patch allows LSM to check permission using "struct vfsmount"
> without passing "struct vfsmount" to VFS helper functions.
>
> Signed-off-by: Kentaro Takeda <takedakn@...data.co.jp>
> Signed-off-by: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
> Signed-off-by: Toshiharu Harada <haradats@...data.co.jp>
> ---
> fs/namei.c | 37 ++++++++++++
> fs/open.c | 5 +
> include/linux/security.h | 135 +++++++++++++++++++++++++++++++++++++++++++++++
> net/unix/af_unix.c | 4 +
> security/capability.c | 53 ++++++++++++++++++
> security/security.c | 63 +++++++++++++++++++++
> 6 files changed, 297 insertions(+)
>
> --- linux-2.6.27-rc6.orig/fs/namei.c
> +++ linux-2.6.27-rc6/fs/namei.c
> @@ -1585,6 +1585,10 @@ int may_open(struct nameidata *nd, int a
> * Refuse to truncate files with mandatory locks held on them.
> */
> error = locks_verify_locked(inode);
> + if (!error)
> + error = security_path_truncate(&nd->path, 0,
> + ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
> + NULL);
> if (!error) {
> DQUOT_INIT(inode);
>
> @@ -1615,7 +1619,11 @@ static int __open_namei_create(struct na
>
> if (!IS_POSIXACL(dir->d_inode))
> 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);
> +out_unlock:
> mutex_unlock(&dir->d_inode->i_mutex);
> dput(nd->path.dentry);
> nd->path.dentry = path->dentry;
> @@ -2018,6 +2026,9 @@ asmlinkage long sys_mknodat(int dfd, con
> error = mnt_want_write(nd.path.mnt);
> if (error)
> goto out_dput;
> + error = security_path_mknod(&nd.path, dentry, mode, dev);
> + if (error)
> + goto out_drop_write;
> switch (mode & S_IFMT) {
> case 0: case S_IFREG:
> error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
> @@ -2030,6 +2041,7 @@ asmlinkage long sys_mknodat(int dfd, con
> error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
> break;
> }
> +out_drop_write:
> mnt_drop_write(nd.path.mnt);
> out_dput:
> dput(dentry);
> @@ -2089,7 +2101,11 @@ asmlinkage long sys_mkdirat(int dfd, con
> error = mnt_want_write(nd.path.mnt);
> if (error)
> 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);
> +out_drop_write:
> mnt_drop_write(nd.path.mnt);
> out_dput:
> dput(dentry);
> @@ -2196,7 +2212,11 @@ static long do_rmdir(int dfd, const char
> error = mnt_want_write(nd.path.mnt);
> if (error)
> goto exit3;
> + error = security_path_rmdir(&nd.path, dentry);
> + if (error)
> + goto exit4;
> error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
> +exit4:
> mnt_drop_write(nd.path.mnt);
> exit3:
> dput(dentry);
> @@ -2278,7 +2298,11 @@ static long do_unlinkat(int dfd, const c
> error = mnt_want_write(nd.path.mnt);
> if (error)
> goto exit2;
> + error = security_path_unlink(&nd.path, dentry);
> + if (error)
> + goto exit3;
> error = vfs_unlink(nd.path.dentry->d_inode, dentry);
> +exit3:
> mnt_drop_write(nd.path.mnt);
> exit2:
> dput(dentry);
> @@ -2359,7 +2383,11 @@ asmlinkage long sys_symlinkat(const char
> error = mnt_want_write(nd.path.mnt);
> if (error)
> 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);
> +out_drop_write:
> mnt_drop_write(nd.path.mnt);
> out_dput:
> dput(dentry);
> @@ -2456,7 +2484,11 @@ asmlinkage long sys_linkat(int olddfd, c
> error = mnt_want_write(nd.path.mnt);
> if (error)
> 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);
> +out_drop_write:
> mnt_drop_write(nd.path.mnt);
> out_dput:
> dput(new_dentry);
> @@ -2688,8 +2720,13 @@ asmlinkage long sys_renameat(int olddfd,
> error = mnt_want_write(oldnd.path.mnt);
> if (error)
> 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,
> new_dir->d_inode, new_dentry);
> +exit6:
> mnt_drop_write(oldnd.path.mnt);
> exit5:
> dput(new_dentry);
> --- linux-2.6.27-rc6.orig/fs/open.c
> +++ linux-2.6.27-rc6/fs/open.c
> @@ -272,6 +272,8 @@ static long do_sys_truncate(const char _
> goto put_write_and_out;
>
> error = locks_verify_truncate(inode, NULL, length);
> + if (!error)
> + error = security_path_truncate(&path, length, 0, NULL);
> if (!error) {
> DQUOT_INIT(inode);
> error = do_truncate(path.dentry, length, 0, NULL);
> @@ -329,6 +331,9 @@ static long do_sys_ftruncate(unsigned in
>
> error = locks_verify_truncate(inode, file, length);
> if (!error)
> + error = security_path_truncate(&file->f_path, length,
> + ATTR_MTIME|ATTR_CTIME, file);
> + if (!error)
> error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
> out_putf:
> fput(file);
> --- linux-2.6.27-rc6.orig/include/linux/security.h
> +++ linux-2.6.27-rc6/include/linux/security.h
> @@ -345,17 +345,37 @@ static inline void security_free_mnt_opt
> * @dir contains the inode 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.
> + * @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:
> * Check the permission to remove a hard link to a file.
> * @dir contains the inode structure of parent directory of the file.
> * @dentry contains the dentry structure for file to be unlinked.
> * 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:
> * Check the permission to create a symbolic link to a file.
> * @dir contains the inode 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.
> + * @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:
> * Check permissions to create a new directory in the existing directory
> * associated with inode strcture @dir.
> @@ -363,11 +383,25 @@ static inline void security_free_mnt_opt
> * @dentry contains the dentry structure of new directory.
> * @mode contains the mode of new directory.
> * 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:
> * Check the permission to remove a directory.
> * @dir contains the inode 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.
> + * @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:
> * 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
> @@ -378,6 +412,15 @@ static inline void security_free_mnt_opt
> * @mode contains the mode of the new file.
> * @dev contains the device number.
> * 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:
> * Check for permission to rename a file or directory.
> * @old_dir contains the inode structure for parent of the old link.
> @@ -385,6 +428,13 @@ static inline void security_free_mnt_opt
> * @new_dir contains the inode structure for parent of the new link.
> * @new_dentry contains the dentry structure of the new link.
> * 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:
> * Check the permission to read the symbolic link.
> * @dentry contains the dentry structure for the file link.
> @@ -413,6 +463,13 @@ static inline void security_free_mnt_opt
> * @dentry contains the dentry structure for the file.
> * @attr is the iattr structure containing the new file attributes.
> * 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().
> + * @filp is the file structure (may be NULL).
> + * Return 0 if permission is granted.
> * @inode_getattr:
> * Check permission before obtaining file attributes.
> * @mnt is the vfsmount where the dentry was looked up
> @@ -1350,6 +1407,20 @@ struct security_operations {
> struct super_block *newsb);
> int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
>
> + 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, struct file *filp);
> + 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);
> +
> int (*inode_alloc_security) (struct inode *inode);
> void (*inode_free_security) (struct inode *inode);
> int (*inode_init_security) (struct inode *inode, struct inode *dir,
> @@ -1618,6 +1689,20 @@ void security_sb_clone_mnt_opts(const st
> struct super_block *newsb);
> int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
>
> +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, struct file *filp);
> +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);
> +
> int security_inode_alloc(struct inode *inode);
> void security_inode_free(struct inode *inode);
> int security_inode_init_security(struct inode *inode, struct inode *dir,
> @@ -1949,6 +2034,56 @@ static inline int security_sb_parse_opts
> return 0;
> }
>
> +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,
> + struct file *filp)
> +{
> + 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;
> +}
> +
> static inline int security_inode_alloc(struct inode *inode)
> {
> return 0;
> --- linux-2.6.27-rc6.orig/net/unix/af_unix.c
> +++ linux-2.6.27-rc6/net/unix/af_unix.c
> @@ -827,7 +827,11 @@ static int unix_bind(struct socket *sock
> err = mnt_want_write(nd.path.mnt);
> if (err)
> 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);
> +out_mknod_drop_write:
> mnt_drop_write(nd.path.mnt);
> if (err)
> goto out_mknod_dput;
> --- linux-2.6.27-rc6.orig/security/capability.c
> +++ linux-2.6.27-rc6/security/capability.c
> @@ -268,6 +268,51 @@ static void cap_inode_getsecid(const str
> *secid = 0;
> }
>
> +static int cap_path_mknod(struct path *dir, struct dentry *dentry, int mode,
> + unsigned int dev)
> +{
> + return 0;
> +}
> +
> +static int cap_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
> +{
> + return 0;
> +}
> +
> +static int cap_path_rmdir(struct path *dir, struct dentry *dentry)
> +{
> + return 0;
> +}
> +
> +static int cap_path_unlink(struct path *dir, struct dentry *dentry)
> +{
> + return 0;
> +}
> +
> +static int cap_path_symlink(struct path *dir, struct dentry *dentry,
> + const char *old_name)
> +{
> + return 0;
> +}
> +
> +static int cap_path_link(struct dentry *old_dentry, struct path *new_dir,
> + struct dentry *new_dentry)
> +{
> + return 0;
> +}
> +
> +static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
> + struct path *new_path, struct dentry *new_dentry)
> +{
> + return 0;
> +}
> +
> +static int cap_path_truncate(struct path *path, loff_t length,
> + unsigned int time_attrs, struct file *filp)
> +{
> + return 0;
> +}
> +
> static int cap_file_permission(struct file *file, int mask)
> {
> return 0;
> @@ -877,6 +922,14 @@ void security_fixup_ops(struct security_
> set_to_cap_if_null(ops, inode_setsecurity);
> set_to_cap_if_null(ops, inode_listsecurity);
> set_to_cap_if_null(ops, inode_getsecid);
> + set_to_cap_if_null(ops, path_mknod);
> + set_to_cap_if_null(ops, path_mkdir);
> + set_to_cap_if_null(ops, path_rmdir);
> + set_to_cap_if_null(ops, path_unlink);
> + set_to_cap_if_null(ops, path_symlink);
> + set_to_cap_if_null(ops, path_link);
> + set_to_cap_if_null(ops, path_rename);
> + set_to_cap_if_null(ops, path_truncate);
> set_to_cap_if_null(ops, file_permission);
> set_to_cap_if_null(ops, file_alloc_security);
> set_to_cap_if_null(ops, file_free_security);
> --- linux-2.6.27-rc6.orig/security/security.c
> +++ linux-2.6.27-rc6/security/security.c
> @@ -358,6 +358,69 @@ int security_inode_init_security(struct
> }
> EXPORT_SYMBOL(security_inode_init_security);
>
> +int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
> + unsigned int dev)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_mknod(path, dentry, mode, dev);
> +}
> +
> +int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_mkdir(path, dentry, mode);
> +}
> +
> +int security_path_rmdir(struct path *path, struct dentry *dentry)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_rmdir(path, dentry);
> +}
> +
> +int security_path_unlink(struct path *path, struct dentry *dentry)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_unlink(path, dentry);
> +}
> +
> +int security_path_symlink(struct path *path, struct dentry *dentry,
> + const char *old_name)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_symlink(path, dentry, old_name);
> +}
> +
> +int security_path_link(struct dentry *old_dentry, struct path *new_dir,
> + struct dentry *new_dentry)
> +{
> + if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
> + return 0;
> + return security_ops->path_link(old_dentry, new_dir, new_dentry);
> +}
> +
> +int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
> + struct path *new_dir, struct dentry *new_dentry)
> +{
> + if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
> + (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
> + return 0;
> + return security_ops->path_rename(old_dir, old_dentry, new_dir,
> + new_dentry);
> +}
> +
> +int security_path_truncate(struct path *path, loff_t length,
> + unsigned int time_attrs, struct file *filp)
> +{
> + if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
> + return 0;
> + return security_ops->path_truncate(path, length, time_attrs, filp);
> +}
> +
> int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
> {
> if (unlikely(IS_PRIVATE(dir)))
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists