From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752916AbYIQEAk (ORCPT ); Wed, 17 Sep 2008 00:00:40 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1750730AbYIQEA3 (ORCPT ); Wed, 17 Sep 2008 00:00:29 -0400 Received: from smtp108.prem.mail.sp1.yahoo.com ([98.136.44.63]:23055 "HELO smtp108.prem.mail.sp1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1750695AbYIQEA1 (ORCPT ); Wed, 17 Sep 2008 00:00:27 -0400 X-YMail-OSG: mZHxojMVM1k1x8wT.9k12H9.uk8XiKzStvKp8r64iQ75JiW9gY1LDUkfvZhvlsQtuBKoTTA06varIOleRZsuLM_qRX_ljS5o82PVs1R41s_ZXyhNr3Pin8a8RY3OWtzE.49piX2eej1Vqryikyrn4AQT X-Yahoo-Newman-Property: ymail-3 Message-ID: <48D080D1.5060405@schaufler-ca.com> Date: Tue, 16 Sep 2008 21:00:17 -0700 From: Casey Schaufler User-Agent: Thunderbird 2.0.0.16 (Windows/20080708) MIME-Version: 1.0 To: Kentaro Takeda CC: linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Toshiharu Harada Subject: Re: [PATCH] Introduce new LSM hooks where vfsmount is available. References: <48C65E9D.3070106@nttdata.co.jp> <5fb14edc0809090902m32431bf6yf518a457e410764d@mail.gmail.com> <20080910134540.45ec1272.akpm@linux-foundation.org> <48C877DE.4040402@nttdata.co.jp> <48D06865.8070602@nttdata.co.jp> In-Reply-To: <48D06865.8070602@nttdata.co.jp> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 > Signed-off-by: Tetsuo Handa > Signed-off-by: Toshiharu Harada > --- > 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@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > > >