From: Jeff Mahoney Subject: [PATCH] security: add ->path_permission This patch adds a security_ops->path_permission hook that is identical to security_ops->inode_permission except that it is passed a struct path instead of a struct inode. LSMs which don't implement it will have their ->inode_permission call used instead. Signed-off-by: Jeff Mahoney --- include/linux/security.h | 21 +++++++++++++++++++++ security/capability.c | 6 ++++++ security/security.c | 9 +++++++++ 3 files changed, 36 insertions(+) --- a/include/linux/security.h +++ b/include/linux/security.h @@ -592,6 +592,20 @@ static inline void security_free_mnt_opt * file_permission, and recheck access if anything has changed * since inode_permission. * + * Security hook for path + * + * @path_permission: + * Check permission before accessing a path. This hook is called by the + * existing Linux permission function, so a security module can use it to + * provide additional checking for existing Linux permission checks. + * Notice that this hook is called when a file is opened (as well as many + * other operations), whereas the file_security_ops permission hook is + * called when the actual read/write operations are performed. This + * hook is optional and if absent, inode_permission will be substituted. + * @path contains the path structure to check. + * @mask contains the permission mask. + * Return 0 if permission is granted. + * Security hooks for task operations. * * @task_create: @@ -1434,6 +1448,7 @@ struct security_operations { struct fown_struct *fown, int sig); int (*file_receive) (struct file *file); int (*dentry_open) (struct file *file); + int (*path_permission) (struct path *path, int mask); int (*task_create) (unsigned long clone_flags); int (*task_alloc_security) (struct task_struct *p); @@ -1708,6 +1723,7 @@ int security_file_send_sigiotask(struct struct fown_struct *fown, int sig); int security_file_receive(struct file *file); int security_dentry_open(struct file *file); +int security_path_permission(struct path *path, int mask); int security_task_create(unsigned long clone_flags); int security_task_alloc(struct task_struct *p); void security_task_free(struct task_struct *p); @@ -2240,6 +2256,11 @@ static inline int security_dentry_open(s { return 0; } + +static inline int security_path_permission(struct path *path, int mask) +{ + return 0; +} static inline int security_task_create(unsigned long clone_flags) { --- a/security/capability.c +++ b/security/capability.c @@ -343,6 +343,11 @@ static int cap_dentry_open(struct file * return 0; } +static int cap_path_permission(struct path *path, int mask) +{ + return security_inode_permission(path->dentry->d_inode, mask); +} + static int cap_task_create(unsigned long clone_flags) { return 0; @@ -897,6 +902,7 @@ void security_fixup_ops(struct security_ set_to_cap_if_null(ops, file_send_sigiotask); set_to_cap_if_null(ops, file_receive); set_to_cap_if_null(ops, dentry_open); + set_to_cap_if_null(ops, path_permission); set_to_cap_if_null(ops, task_create); set_to_cap_if_null(ops, task_alloc_security); set_to_cap_if_null(ops, task_free_security); --- a/security/security.c +++ b/security/security.c @@ -615,6 +615,15 @@ int security_dentry_open(struct file *fi return security_ops->dentry_open(file); } +int security_path_permission(struct path *path, int mask) +{ + struct inode *inode = path->dentry->d_inode; + if (unlikely(IS_PRIVATE(inode))) + return 0; + + return security_ops->path_permission(path, mask); +} + int security_task_create(unsigned long clone_flags) { return security_ops->task_create(clone_flags);