#include #include #include #include "lve_os_compat.h" #include "lve_debug.h" #include "lve_hooks.h" #include "lsm.h" #include "lsm_int.h" int (*lve___ptrace_may_access)(struct task_struct *child, unsigned int mode); int (*lve_security_ptrace_traceme)(struct task_struct *parent); int (*lve_security_task_fix_setuid)(struct cred *new, const struct cred *old, int flags); #if defined(IMPL_LINK_PROT_NEW) || defined(IMPL_LINK_PROT_EXPERIMENTAL) int (*lve_security_inode_follow_link)(struct dentry *, struct inode *, bool); int (*lve_security_path_symlink)(const struct path *dir, struct dentry *dentry, const char *old_name); #else int (*lve_security_path_symlink)(struct path *dir, struct dentry *dentry, const char *old_name); int (*lve_security_inode_follow_link)(struct dentry *link_dentry, struct nameidata *nd_orig); #endif int (*lve_security_inode_permission)(struct inode *inode, int mask); int (*lve_security_inode_readlink)(struct dentry *link_dentry, struct vfsmount *link_mnt); void (*lve_security_d_instantiate)(struct dentry *de, struct inode *inode); /* network hooks */ int (*lve_security_socket_bind)(struct socket *sock, struct sockaddr *address, int addrlen); /************ *****************************/ /*** Proxy functions ******/ static int lsm_ipermission(struct inode *inode, int mask) { int ret; ret = sandbox_permission(inode, mask); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_inode_permission(inode, mask)); } static int lsm_ptrace_access(struct task_struct *child, unsigned int mode) { int ret; ret = sandbox_ptrace_access(child, mode); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve___ptrace_may_access(child, mode)); } static int lsm_ptrace_traceme(struct task_struct *parent) { int ret; ret = sandbox_ptrace_traceme(parent); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_ptrace_traceme(parent)); } #if FEAT_LINK_PROT == 1 #if defined(IMPL_LINK_PROT_NEW) int lsm_inode_follow_link(struct dentry *dentry, struct inode *i, bool rcu) { int ret; ret = sandbox_inode_follow_link(dentry, i, rcu); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_inode_follow_link(dentry, i, rcu)); } int lsm_path_symlink(const struct path *dir, struct dentry *dentry, const char *old_name) { int ret; ret = sandbox_path_symlink(dir, dentry, old_name); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_path_symlink(dir, dentry, old_name)); } #elif defined(IMPL_LINK_PROT_OLD) static int lsm_inode_follow_link(struct dentry *dentry, struct nameidata *nd) { int ret; ret = sandbox_inode_follow_link(dentry, nd); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_inode_follow_link(dentry, nd)); } static int lsm_path_symlink(struct path *dir, struct dentry *dentry, const char *old_name) { int ret; ret = sandbox_path_symlink(dir, dentry, old_name); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_path_symlink(dir, dentry, old_name)); } #elif defined(IMPL_LINK_PROT_EXPERIMENTAL) int lsm_inode_follow_link(struct dentry *dentry, struct inode *i, bool rcu) { int ret; ret = sandbox_inode_follow_link(dentry, i, rcu); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_inode_follow_link(dentry, i, rcu)); } #endif #if RHEL_MAJOR > 8 static int lsm_inode_link(struct dentry *old_dentry, struct user_namespace *mnt_userns, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode) #else static int lsm_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode) #endif { int ret; ret = sandbox_inode_link(old_dentry, dir, new_dentry); if (ret < 0) return ret; #if RHEL_MAJOR > 8 return LVE_HOOK_RECURSIVE_CALL(vfs_link(old_dentry, mnt_userns, dir, new_dentry, delegated_inode)); #else return LVE_HOOK_RECURSIVE_CALL(vfs_link(old_dentry, dir, new_dentry, delegated_inode)); #endif } #endif static int lsm_setuid(struct cred *new, const struct cred *old, int flags) { int ret; ret = sandbox_task_fix_setuid(new, old, flags); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_task_fix_setuid(new, old, flags)); } static int lsm_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { int ret; ret = sandbox_socket_bind(sock, address, addrlen); if (ret < 0) return ret; return LVE_HOOK_RECURSIVE_CALL(lve_security_socket_bind(sock, address, addrlen)); } static void lsm_d_instantiate(struct dentry *de, struct inode *inode) { sandbox_d_instantiate(de, inode); LVE_HOOK_RECURSIVE_CALL(lve_security_d_instantiate(de, inode)); } #if RHEL_MAJOR > 8 static int lsm_inode_rmdir(struct user_namespace *mnt_userns, struct inode *inode, struct dentry *de) #else static int lsm_inode_rmdir(struct inode *inode, struct dentry *de) #endif { int ret; ret = sandbox_inode_rmdir(inode, de); if (ret < 0) return ret; #if RHEL_MAJOR > 8 return LVE_HOOK_RECURSIVE_CALL(vfs_rmdir(mnt_userns, inode, de)); #else return LVE_HOOK_RECURSIVE_CALL(vfs_rmdir(inode, de)); #endif } int __init lve_lsm_init(void) { int rc; rc = lve_register_hook("security_inode_permission", lsm_ipermission); if (rc) goto exit; #ifndef HAVE_USER_PTRACE_ENABLED rc = lve_register_hook("__ptrace_may_access", lsm_ptrace_access); if (rc) goto exit; rc = lve_register_hook("security_ptrace_traceme", lsm_ptrace_traceme); if (rc) goto exit; #endif #if FEAT_LINK_PROT == 1 rc = lve_register_hook("security_inode_follow_link", lsm_inode_follow_link); if (rc) goto exit; #ifdef CONFIG_SECURITY_PATH #ifndef IMPL_LINK_PROT_EXPERIMENTAL rc = lve_register_hook("security_path_symlink", lsm_path_symlink); if (rc) goto exit; #endif #endif rc = lve_register_hook("vfs_link", lsm_inode_link); if (rc) goto exit; #endif rc = lve_register_hook("security_task_fix_setuid", lsm_setuid); if (rc) goto exit; rc = lve_register_hook("security_socket_bind", lsm_socket_bind); if (rc) goto exit; rc = lve_register_hook("security_d_instantiate", lsm_d_instantiate); if (rc) goto exit; rc = lve_register_hook("vfs_rmdir", lsm_inode_rmdir); if (rc) goto exit; exit: return rc; }