From: Jeff Mahoney Subject: [PATCH] vfs: introduce path_permission() 2.6.27 eliminated the nameidata parameter from permission and replaced several call sites with inode_permission. This keeps the information required by AppArmor from reaching it. The following patch factors out the permission assessment part of inode_permission into __inode_permission and adds a path_permission function that takes a struct path instead of a struct inode and passes it to security_path_permission instead of security_inode_permission. All of the call sites that had access to a struct path whether by itself or via a file or nameidata (and used it) in 2.6.26 are changed to use the path_permission call. Signed-off-by: Jeff Mahoney --- fs/inotify_user.c | 2 +- fs/namei.c | 32 ++++++++++++++++++++++++-------- fs/open.c | 10 +++++----- include/linux/fs.h | 5 +++++ 4 files changed, 35 insertions(+), 14 deletions(-) --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -365,7 +365,7 @@ static int find_inode(const char __user if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = inode_permission(path->dentry->d_inode, MAY_READ); + error = path_permission(path, MAY_READ); if (error) path_put(path); return error; --- a/fs/namei.c +++ b/fs/namei.c @@ -227,7 +227,7 @@ int generic_permission(struct inode *ino return -EACCES; } -int inode_permission(struct inode *inode, int mask) +static int __inode_permission(struct inode *inode, int mask) { int retval; @@ -269,7 +269,12 @@ int inode_permission(struct inode *inode if (retval) return retval; - retval = devcgroup_inode_permission(inode, mask); + return devcgroup_inode_permission(inode, mask); +} + +int inode_permission(struct inode *inode, int mask) +{ + int retval = __inode_permission(inode, mask); if (retval) return retval; @@ -277,6 +282,15 @@ int inode_permission(struct inode *inode mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); } +int path_permission(struct path *path, int mask) +{ + int retval = __inode_permission(path->dentry->d_inode, mask); + if (retval) + return retval; + return security_path_permission(path, + mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); +} + /** * vfs_permission - check for access rights to a given path * @nd: lookup result that describes the path @@ -289,7 +303,7 @@ int inode_permission(struct inode *inode */ int vfs_permission(struct nameidata *nd, int mask) { - return inode_permission(nd->path.dentry->d_inode, mask); + return path_permission(&nd->path, mask); } /** @@ -306,7 +320,7 @@ int vfs_permission(struct nameidata *nd, */ int file_permission(struct file *file, int mask) { - return inode_permission(file->f_path.dentry->d_inode, mask); + return path_permission(&file->f_path, mask); } /* @@ -447,8 +461,9 @@ static struct dentry * cached_lookup(str * short-cut DAC fails, then call permission() to do more * complete permission check. */ -static int exec_permission_lite(struct inode *inode) +static int exec_permission_lite(struct path *path) { + struct inode *inode = path->dentry->d_inode; umode_t mode = inode->i_mode; if (inode->i_op && inode->i_op->permission) @@ -473,7 +488,7 @@ static int exec_permission_lite(struct i return -EACCES; ok: - return security_inode_permission(inode, MAY_EXEC); + return security_path_permission(path, MAY_EXEC); } /* @@ -870,7 +885,7 @@ static int __link_path_walk(const char * unsigned int c; nd->flags |= LOOKUP_CONTINUE; - err = exec_permission_lite(inode); + err = exec_permission_lite(&nd->path); if (err == -EAGAIN) err = vfs_permission(nd, MAY_EXEC); if (err) @@ -1245,7 +1260,7 @@ static struct dentry *lookup_hash(struct { int err; - err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); + err = path_permission(&nd->path, MAY_EXEC); if (err) return ERR_PTR(err); return __lookup_hash(&nd->last, nd->path.dentry, nd); @@ -2872,6 +2887,7 @@ EXPORT_SYMBOL(page_symlink_inode_operati EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(vfs_path_lookup); EXPORT_SYMBOL(inode_permission); +EXPORT_SYMBOL(path_permission); EXPORT_SYMBOL(vfs_permission); EXPORT_SYMBOL(file_permission); EXPORT_SYMBOL(unlock_rename); --- a/fs/open.c +++ b/fs/open.c @@ -250,7 +250,7 @@ static long do_sys_truncate(const char _ if (error) goto dput_and_out; - error = inode_permission(inode, MAY_WRITE); + error = path_permission(&path, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -474,7 +474,7 @@ asmlinkage long sys_faccessat(int dfd, c goto out_path_release; } - res = inode_permission(inode, mode | MAY_ACCESS); + res = path_permission(&path, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -517,7 +517,7 @@ asmlinkage long sys_chdir(const char __u if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&path, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; @@ -546,7 +546,7 @@ asmlinkage long sys_fchdir(unsigned int if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = inode_permission(inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&file->f_path, MAY_EXEC | MAY_ACCESS); if (!error) set_fs_pwd(current->fs, &file->f_path); out_putf: @@ -564,7 +564,7 @@ asmlinkage long sys_chroot(const char __ if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); + error = path_permission(&path, MAY_EXEC | MAY_ACCESS); if (error) goto dput_and_out; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1183,6 +1183,11 @@ extern void dentry_unhash(struct dentry extern int file_permission(struct file *, int); /* + * VFS path helper functions. + */ +extern int path_permission(struct path *, int); + +/* * File types * * NOTE! These match bits 12..15 of stat.st_mode