Subject: [PATCH v17 2/4] LSM: Refactor existing LSM stacking
The existing code stacks up to three security modules.
If there is only one module it is the capability module.
If a module is specified the capability code is explicitly
called within the specified module. If Yama stacking is
configured the yama hooks are called and then the specified
module. The capability check is made twice in the yama
stacking case.
This patch adds a list for each of the LSM hooks. The capability
hooks that are non-trivial are put on the list first. If Yama
stacking is configured the yama hooks are added to the list.
If a module is configured it gets added next. Each entry in the
list is called in order:
(capability[ yama][ {selinux|smack|tomoyo|apparmor}])
Exit is on first failure (bail on fail) which matches the
existing behavior. The explict calls to the capability module
are removed where they would duplicate the stacked call.
Signed-off-by: Casey Schaufler <***@schaufler-ca.com>
---
include/linux/security.h | 40 +-
security/Makefile | 2 +-
security/apparmor/domain.c | 4 +-
security/apparmor/lsm.c | 21 +-
security/commoncap.c | 33 +-
security/security.c | 1160 +++++++++++++++++++++++++++++++++++++++++---
security/selinux/hooks.c | 67 +--
security/smack/smack_lsm.c | 43 +-
security/tomoyo/tomoyo.c | 6 -
security/yama/yama_lsm.c | 44 +-
10 files changed, 1171 insertions(+), 249 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 623f90e..611995a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -101,6 +101,8 @@ extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
+extern struct security_operations capability_ops;
+
struct msghdr;
struct sk_buff;
struct sock;
@@ -116,7 +118,9 @@ struct seq_file;
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
-void reset_security_ops(void);
+#ifdef CONFIG_SECURITY_SELINUX_DISABLE
+void security_module_disable(struct security_operations *);
+#endif
#ifdef CONFIG_MMU
extern unsigned long mmap_min_addr;
@@ -3169,36 +3173,8 @@ static inline void free_secdata(void *secdata)
{ }
#endif /* CONFIG_SECURITY */
-#ifdef CONFIG_SECURITY_YAMA
-extern int yama_ptrace_access_check(struct task_struct *child,
- unsigned int mode);
-extern int yama_ptrace_traceme(struct task_struct *parent);
-extern void yama_task_free(struct task_struct *task);
-extern int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5);
-#else
-static inline int yama_ptrace_access_check(struct task_struct *child,
- unsigned int mode)
-{
- return 0;
-}
-
-static inline int yama_ptrace_traceme(struct task_struct *parent)
-{
- return 0;
-}
-
-static inline void yama_task_free(struct task_struct *task)
-{
-}
-
-static inline int yama_task_prctl(int option, unsigned long arg2,
- unsigned long arg3, unsigned long arg4,
- unsigned long arg5)
-{
- return -ENOSYS;
-}
-#endif /* CONFIG_SECURITY_YAMA */
+#ifdef CONFIG_SECURITY_YAMA_STACKED
+extern struct security_operations yama_ops;
+#endif
#endif /* ! __LINUX_SECURITY_H */
-
diff --git a/security/Makefile b/security/Makefile
index 05f1c93..c9bfbc8 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,7 +14,7 @@ obj-y += commoncap.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o capability.o
+obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index d97cba3..b09fff7 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -347,9 +347,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
file_inode(bprm->file)->i_mode
};
const char *name = NULL, *target = NULL, *info = NULL;
- int error = cap_bprm_set_creds(bprm);
- if (error)
- return error;
+ int error = 0;
if (bprm->cred_prepared)
return 0;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 9981000..30e562a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -96,19 +96,11 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int error = cap_ptrace_access_check(child, mode);
- if (error)
- return error;
-
return aa_ptrace(current, child, mode);
}
static int apparmor_ptrace_traceme(struct task_struct *parent)
{
- int error = cap_ptrace_traceme(parent);
- if (error)
- return error;
-
return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
}
@@ -140,13 +132,11 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit)
{
struct aa_profile *profile;
- /* cap_capable returns 0 on success, else -EPERM */
- int error = cap_capable(cred, ns, cap, audit);
- if (!error) {
- profile = aa_cred_profile(cred);
- if (!unconfined(profile))
- error = aa_capable(profile, cap, audit);
- }
+ int error = 0;
+
+ profile = aa_cred_profile(cred);
+ if (!unconfined(profile))
+ error = aa_capable(profile, cap, audit);
return error;
}
@@ -640,7 +630,6 @@ static struct security_operations apparmor_ops = {
.file_alloc_security = apparmor_file_alloc_security,
.file_free_security = apparmor_file_free_security,
.mmap_file = apparmor_mmap_file,
- .mmap_addr = cap_mmap_addr,
.file_mprotect = apparmor_file_mprotect,
.file_lock = apparmor_file_lock,
diff --git a/security/commoncap.c b/security/commoncap.c
index bab0611..02eb0c8 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -954,7 +954,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
SECURITY_CAP_NOAUDIT) == 0)
cap_sys_admin = 1;
- return __vm_enough_memory(mm, pages, cap_sys_admin);
+ return cap_sys_admin;
}
/*
@@ -985,3 +985,34 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,
{
return 0;
}
+
+#ifdef CONFIG_SECURITY
+
+struct security_operations capability_ops = {
+ .name = "capability",
+ .capable = cap_capable,
+ .settime = cap_settime,
+ .ptrace_access_check = cap_ptrace_access_check,
+ .ptrace_traceme = cap_ptrace_traceme,
+ .capget = cap_capget,
+ .capset = cap_capset,
+ .bprm_set_creds = cap_bprm_set_creds,
+ .bprm_secureexec = cap_bprm_secureexec,
+ /*
+ * Not stacked in the usual way.
+ * .inode_setxattr = cap_inode_setxattr,
+ * .inode_removexattr = cap_inode_removexattr,
+ */
+ .inode_need_killpriv = cap_inode_need_killpriv,
+ .inode_killpriv = cap_inode_killpriv,
+ .mmap_addr = cap_mmap_addr,
+ .mmap_file = cap_mmap_file,
+ .task_fix_setuid = cap_task_fix_setuid,
+ .task_prctl = cap_task_prctl,
+ .task_setscheduler = cap_task_setscheduler,
+ .task_setioprio = cap_task_setioprio,
+ .task_setnice = cap_task_setnice,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#endif /* CONFIG_SECURITY */
diff --git a/security/security.c b/security/security.c
index d51eb40..c1d8853 100644
--- a/security/security.c
+++ b/security/security.c
@@ -25,28 +25,20 @@
#include <linux/mount.h>
#include <linux/personality.h>
#include <linux/backing-dev.h>
+#include <linux/list.h>
#include <net/flow.h>
+struct security_hook_list {
+ struct list_head shl_head;
+ struct security_operations *shl_ops;
+};
+
#define MAX_LSM_EVM_XATTR 2
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY;
-static struct security_operations *security_ops;
-static struct security_operations default_security_ops = {
- .name = "default",
-};
-
-static inline int __init verify(struct security_operations *ops)
-{
- /* verify the security_operations structure exists */
- if (!ops)
- return -EINVAL;
- security_fixup_ops(ops);
- return 0;
-}
-
static void __init do_security_initcalls(void)
{
initcall_t *call;
@@ -57,6 +49,8 @@ static void __init do_security_initcalls(void)
}
}
+static int __init security_enlist_ops(struct security_operations *sop);
+
/**
* security_init - initializes the security framework
*
@@ -64,20 +58,30 @@ static void __init do_security_initcalls(void)
*/
int __init security_init(void)
{
- printk(KERN_INFO "Security Framework initialized\n");
+ int rc;
- security_fixup_ops(&default_security_ops);
- security_ops = &default_security_ops;
+ pr_info("Security Framework initialized\n");
+
+ /*
+ * Always load the capability module.
+ */
+ rc = security_enlist_ops(&capability_ops);
+ if (rc)
+ return rc;
+#ifdef CONFIG_SECURITY_YAMA_STACKED
+ rc = security_enlist_ops(&yama_ops);
+ if (rc)
+ return rc;
+#endif
+ /*
+ * Load the chosen module if there is one.
+ * This will also find yama if it is stacking
+ */
do_security_initcalls();
return 0;
}
-void reset_security_ops(void)
-{
- security_ops = &default_security_ops;
-}
-
/* Save user chosen LSM */
static int __init choose_lsm(char *str)
{
@@ -119,56 +123,66 @@ int __init security_module_enable(struct security_operations *ops)
*/
int __init register_security(struct security_operations *ops)
{
- if (verify(ops)) {
- printk(KERN_DEBUG "%s could not verify "
- "security_operations structure.\n", __func__);
+ /*
+ * Verify the security_operations structure exists
+ */
+ if (!ops) {
+ pr_debug("%s could not verify security_operations.\n",
+ __func__);
return -EINVAL;
}
- if (security_ops != &default_security_ops)
- return -EAGAIN;
-
- security_ops = ops;
- return 0;
+ return security_enlist_ops(ops);
}
/*
- * Hook operation macros.
+ * Hook list operation macros.
*
* call_void_hook:
* This is a hook that does not return a value.
*
* call_int_hook:
* This is a hook that returns a value.
+ * Stop on the first failure.
*/
-#define call_void_hook(FUNC, ...) security_ops->FUNC(__VA_ARGS__)
-#define call_int_hook(FUNC, ...) security_ops->FUNC(__VA_ARGS__)
+#define call_void_hook(FUNC, ...) \
+ do { \
+ struct security_hook_list *P; \
+ \
+ list_for_each_entry(P, &hooks_##FUNC, shl_head) \
+ P->shl_ops->FUNC(__VA_ARGS__); \
+ } while (0) \
+
+#define call_int_hook(FUNC, ...) ({ \
+ int RC = 0; \
+ do { \
+ struct security_hook_list *P; \
+ \
+ list_for_each_entry(P, &hooks_##FUNC, shl_head) { \
+ RC = P->shl_ops->FUNC(__VA_ARGS__); \
+ if (RC != 0) \
+ break; \
+ } \
+ } while (0); \
+ RC; \
+}) \
/* Security operations */
+static LIST_HEAD(hooks_ptrace_access_check);
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_ptrace_access_check(child, mode);
- if (rc)
- return rc;
-#endif
return call_int_hook(ptrace_access_check, child, mode);
}
+static LIST_HEAD(hooks_ptrace_traceme);
int security_ptrace_traceme(struct task_struct *parent)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_ptrace_traceme(parent);
- if (rc)
- return rc;
-#endif
return call_int_hook(ptrace_traceme, parent);
}
+static LIST_HEAD(hooks_capget);
int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
@@ -177,6 +191,7 @@ int security_capget(struct task_struct *target,
return call_int_hook(capget, target, effective, inheritable, permitted);
}
+static LIST_HEAD(hooks_capset);
int security_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
@@ -186,6 +201,7 @@ int security_capset(struct cred *new, const struct cred *old,
effective, inheritable, permitted);
}
+static LIST_HEAD(hooks_capable);
int security_capable(const struct cred *cred, struct user_namespace *ns,
int cap)
{
@@ -202,36 +218,61 @@ int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
return call_int_hook(capable, cred, ns, cap, SECURITY_CAP_NOAUDIT);
}
+static LIST_HEAD(hooks_quotactl);
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
{
return call_int_hook(quotactl, cmds, type, id, sb);
}
+static LIST_HEAD(hooks_quota_on);
int security_quota_on(struct dentry *dentry)
{
return call_int_hook(quota_on, dentry);
}
+static LIST_HEAD(hooks_syslog);
int security_syslog(int type)
{
return call_int_hook(syslog, type);
}
+static LIST_HEAD(hooks_settime);
int security_settime(const struct timespec *ts, const struct timezone *tz)
{
return call_int_hook(settime, ts, tz);
}
+static LIST_HEAD(hooks_vm_enough_memory);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
{
- return call_int_hook(vm_enough_memory, mm, pages);
+ struct security_hook_list *shp;
+ int cap_sys_admin = 1;
+ int rc;
+
+ /*
+ * The module will respond with a positive value if
+ * it thinks the __vm_enough_memory() call should be
+ * made with the cap_sys_admin set. If all of the modules
+ * agree that it should be set it will. If any module
+ * thinks it should not be set it won't.
+ */
+ list_for_each_entry(shp, &hooks_vm_enough_memory, shl_head) {
+ rc = shp->shl_ops->vm_enough_memory(mm, pages);
+ if (rc <= 0) {
+ cap_sys_admin = 0;
+ break;
+ }
+ }
+ return __vm_enough_memory(mm, pages, cap_sys_admin);
}
+static LIST_HEAD(hooks_bprm_set_creds);
int security_bprm_set_creds(struct linux_binprm *bprm)
{
return call_int_hook(bprm_set_creds, bprm);
}
+static LIST_HEAD(hooks_bprm_check_security);
int security_bprm_check(struct linux_binprm *bprm)
{
int ret;
@@ -242,83 +283,104 @@ int security_bprm_check(struct linux_binprm *bprm)
return ima_bprm_check(bprm);
}
+static LIST_HEAD(hooks_bprm_committing_creds);
void security_bprm_committing_creds(struct linux_binprm *bprm)
{
call_void_hook(bprm_committing_creds, bprm);
}
+static LIST_HEAD(hooks_bprm_committed_creds);
void security_bprm_committed_creds(struct linux_binprm *bprm)
{
call_void_hook(bprm_committed_creds, bprm);
}
+static LIST_HEAD(hooks_bprm_secureexec);
int security_bprm_secureexec(struct linux_binprm *bprm)
{
return call_int_hook(bprm_secureexec, bprm);
}
+static LIST_HEAD(hooks_sb_alloc_security);
int security_sb_alloc(struct super_block *sb)
{
return call_int_hook(sb_alloc_security, sb);
}
+static LIST_HEAD(hooks_sb_free_security);
void security_sb_free(struct super_block *sb)
{
call_void_hook(sb_free_security, sb);
}
+static LIST_HEAD(hooks_sb_copy_data);
int security_sb_copy_data(char *orig, char *copy)
{
return call_int_hook(sb_copy_data, orig, copy);
}
EXPORT_SYMBOL(security_sb_copy_data);
+static LIST_HEAD(hooks_sb_remount);
int security_sb_remount(struct super_block *sb, void *data)
{
return call_int_hook(sb_remount, sb, data);
}
+static LIST_HEAD(hooks_sb_kern_mount);
int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
return call_int_hook(sb_kern_mount, sb, flags, data);
}
+static LIST_HEAD(hooks_sb_show_options);
int security_sb_show_options(struct seq_file *m, struct super_block *sb)
{
return call_int_hook(sb_show_options, m, sb);
}
+static LIST_HEAD(hooks_sb_statfs);
int security_sb_statfs(struct dentry *dentry)
{
return call_int_hook(sb_statfs, dentry);
}
+static LIST_HEAD(hooks_sb_mount);
int security_sb_mount(const char *dev_name, struct path *path,
const char *type, unsigned long flags, void *data)
{
return call_int_hook(sb_mount, dev_name, path, type, flags, data);
}
+static LIST_HEAD(hooks_sb_umount);
int security_sb_umount(struct vfsmount *mnt, int flags)
{
return call_int_hook(sb_umount, mnt, flags);
}
+static LIST_HEAD(hooks_sb_pivotroot);
int security_sb_pivotroot(struct path *old_path, struct path *new_path)
{
return call_int_hook(sb_pivotroot, old_path, new_path);
}
+static LIST_HEAD(hooks_sb_set_mnt_opts);
int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts,
unsigned long kern_flags,
unsigned long *set_kern_flags)
{
+ if (list_empty(&hooks_sb_set_mnt_opts)) {
+ if (unlikely(opts->num_mnt_opts))
+ return -EOPNOTSUPP;
+ return 0;
+ }
+
return call_int_hook(sb_set_mnt_opts, sb, opts, kern_flags,
set_kern_flags);
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);
+static LIST_HEAD(hooks_sb_clone_mnt_opts);
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
@@ -326,33 +388,40 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
}
EXPORT_SYMBOL(security_sb_clone_mnt_opts);
+static LIST_HEAD(hooks_sb_parse_opts_str);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return call_int_hook(sb_parse_opts_str, options, opts);
}
EXPORT_SYMBOL(security_sb_parse_opts_str);
+static LIST_HEAD(hooks_inode_alloc_security);
int security_inode_alloc(struct inode *inode)
{
inode->i_security = NULL;
return call_int_hook(inode_alloc_security, inode);
}
+static LIST_HEAD(hooks_inode_free_security);
void security_inode_free(struct inode *inode)
{
integrity_inode_free(inode);
call_void_hook(inode_free_security, inode);
}
+static LIST_HEAD(hooks_dentry_init_security);
int security_dentry_init_security(struct dentry *dentry, int mode,
struct qstr *name, void **ctx,
u32 *ctxlen)
{
+ if (list_empty(&hooks_dentry_init_security))
+ return -EOPNOTSUPP;
return call_int_hook(dentry_init_security, dentry, mode, name,
ctx, ctxlen);
}
EXPORT_SYMBOL(security_dentry_init_security);
+static LIST_HEAD(hooks_inode_init_security);
int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
const initxattrs initxattrs, void *fs_data)
@@ -364,11 +433,15 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
if (unlikely(IS_PRIVATE(inode)))
return 0;
+ if (list_empty(&hooks_inode_init_security))
+ return 0;
+
if (!initxattrs)
return call_int_hook(inode_init_security, inode, dir, qstr,
NULL, NULL, NULL);
memset(new_xattrs, 0, sizeof(new_xattrs));
lsm_xattr = new_xattrs;
+
ret = call_int_hook(inode_init_security, inode, dir, qstr,
&lsm_xattr->name,
&lsm_xattr->value,
@@ -404,6 +477,7 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir,
EXPORT_SYMBOL(security_old_inode_init_security);
#ifdef CONFIG_SECURITY_PATH
+static LIST_HEAD(hooks_path_mknod);
int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
unsigned int dev)
{
@@ -413,6 +487,7 @@ int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
}
EXPORT_SYMBOL(security_path_mknod);
+static LIST_HEAD(hooks_path_mkdir);
int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
@@ -421,6 +496,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
}
EXPORT_SYMBOL(security_path_mkdir);
+static LIST_HEAD(hooks_path_rmdir);
int security_path_rmdir(struct path *dir, struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
@@ -428,6 +504,7 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry)
return call_int_hook(path_rmdir, dir, dentry);
}
+static LIST_HEAD(hooks_path_unlink);
int security_path_unlink(struct path *dir, struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
@@ -436,6 +513,7 @@ int security_path_unlink(struct path *dir, struct dentry *dentry)
}
EXPORT_SYMBOL(security_path_unlink);
+static LIST_HEAD(hooks_path_symlink);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name)
{
@@ -444,6 +522,7 @@ int security_path_symlink(struct path *dir, struct dentry *dentry,
return call_int_hook(path_symlink, dir, dentry, old_name);
}
+static LIST_HEAD(hooks_path_link);
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
struct dentry *new_dentry)
{
@@ -452,6 +531,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
return call_int_hook(path_link, old_dentry, new_dir, new_dentry);
}
+static LIST_HEAD(hooks_path_rename);
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry,
unsigned int flags)
@@ -472,6 +552,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
}
EXPORT_SYMBOL(security_path_rename);
+static LIST_HEAD(hooks_path_truncate);
int security_path_truncate(struct path *path)
{
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
@@ -479,6 +560,7 @@ int security_path_truncate(struct path *path)
return call_int_hook(path_truncate, path);
}
+static LIST_HEAD(hooks_path_chmod);
int security_path_chmod(struct path *path, umode_t mode)
{
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
@@ -486,6 +568,7 @@ int security_path_chmod(struct path *path, umode_t mode)
return call_int_hook(path_chmod, path, mode);
}
+static LIST_HEAD(hooks_path_chown);
int security_path_chown(struct path *path, kuid_t uid, kgid_t gid)
{
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
@@ -493,12 +576,14 @@ int security_path_chown(struct path *path, kuid_t uid, kgid_t gid)
return call_int_hook(path_chown, path, uid, gid);
}
+static LIST_HEAD(hooks_path_chroot);
int security_path_chroot(struct path *path)
{
return call_int_hook(path_chroot, path);
}
#endif
+static LIST_HEAD(hooks_inode_create);
int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
@@ -507,6 +592,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode
}
EXPORT_SYMBOL_GPL(security_inode_create);
+static LIST_HEAD(hooks_inode_link);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
@@ -515,6 +601,7 @@ int security_inode_link(struct dentry *old_dentry, struct inode *dir,
return call_int_hook(inode_link, old_dentry, dir, new_dentry);
}
+static LIST_HEAD(hooks_inode_unlink);
int security_inode_unlink(struct inode *dir, struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -522,6 +609,7 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry)
return call_int_hook(inode_unlink, dir, dentry);
}
+static LIST_HEAD(hooks_inode_symlink);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
const char *old_name)
{
@@ -530,6 +618,7 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
return call_int_hook(inode_symlink, dir, dentry, old_name);
}
+static LIST_HEAD(hooks_inode_mkdir);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
@@ -538,6 +627,7 @@ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
}
EXPORT_SYMBOL_GPL(security_inode_mkdir);
+static LIST_HEAD(hooks_inode_rmdir);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -545,6 +635,7 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
return call_int_hook(inode_rmdir, dir, dentry);
}
+static LIST_HEAD(hooks_inode_mknod);
int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
if (unlikely(IS_PRIVATE(dir)))
@@ -552,6 +643,7 @@ int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
return call_int_hook(inode_mknod, dir, dentry, mode, dev);
}
+static LIST_HEAD(hooks_inode_rename);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
@@ -571,6 +663,7 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dir, new_dentry);
}
+static LIST_HEAD(hooks_inode_readlink);
int security_inode_readlink(struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -578,6 +671,7 @@ int security_inode_readlink(struct dentry *dentry)
return call_int_hook(inode_readlink, dentry);
}
+static LIST_HEAD(hooks_inode_follow_link);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -585,6 +679,7 @@ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
return call_int_hook(inode_follow_link, dentry, nd);
}
+static LIST_HEAD(hooks_inode_permission);
int security_inode_permission(struct inode *inode, int mask)
{
if (unlikely(IS_PRIVATE(inode)))
@@ -592,6 +687,7 @@ int security_inode_permission(struct inode *inode, int mask)
return call_int_hook(inode_permission, inode, mask);
}
+static LIST_HEAD(hooks_inode_setattr);
int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
{
int ret;
@@ -605,6 +701,7 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
+static LIST_HEAD(hooks_inode_getattr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -612,6 +709,7 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
return call_int_hook(inode_getattr, mnt, dentry);
}
+static LIST_HEAD(hooks_inode_setxattr);
int security_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
@@ -619,7 +717,15 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- ret = call_int_hook(inode_setxattr, dentry, name, value, size, flags);
+ /*
+ * SELinux and Smack integrate the cap call,
+ * so assume that all LSMs supplying this call do so.
+ */
+ if (list_empty(&hooks_inode_setxattr))
+ ret = cap_inode_setxattr(dentry, name, value, size, flags);
+ else
+ ret = call_int_hook(inode_setxattr, dentry, name, value,
+ size, flags);
if (ret)
return ret;
@@ -629,6 +735,7 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
return evm_inode_setxattr(dentry, name, value, size);
}
+static LIST_HEAD(hooks_inode_post_setxattr);
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
@@ -638,6 +745,7 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
evm_inode_post_setxattr(dentry, name, value, size);
}
+static LIST_HEAD(hooks_inode_getxattr);
int security_inode_getxattr(struct dentry *dentry, const char *name)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -645,6 +753,7 @@ int security_inode_getxattr(struct dentry *dentry, const char *name)
return call_int_hook(inode_getxattr, dentry, name);
}
+static LIST_HEAD(hooks_inode_listxattr);
int security_inode_listxattr(struct dentry *dentry)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
@@ -652,13 +761,19 @@ int security_inode_listxattr(struct dentry *dentry)
return call_int_hook(inode_listxattr, dentry);
}
+static LIST_HEAD(hooks_inode_removexattr);
int security_inode_removexattr(struct dentry *dentry, const char *name)
{
int ret;
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- ret = call_int_hook(inode_removexattr, dentry, name);
+
+ if (list_empty(&hooks_inode_removexattr))
+ ret = cap_inode_removexattr(dentry, name);
+ else
+ ret = call_int_hook(inode_removexattr, dentry, name);
+
if (ret)
return ret;
ret = ima_inode_removexattr(dentry, name);
@@ -667,31 +782,55 @@ int security_inode_removexattr(struct dentry *dentry, const char *name)
return evm_inode_removexattr(dentry, name);
}
+static LIST_HEAD(hooks_inode_need_killpriv);
int security_inode_need_killpriv(struct dentry *dentry)
{
return call_int_hook(inode_need_killpriv, dentry);
}
+static LIST_HEAD(hooks_inode_killpriv);
int security_inode_killpriv(struct dentry *dentry)
{
return call_int_hook(inode_killpriv, dentry);
}
+static LIST_HEAD(hooks_inode_getsecurity);
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
+ struct security_hook_list *shp;
+ int rc = -EOPNOTSUPP;
+
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
- return call_int_hook(inode_getsecurity, inode, name, buffer, alloc);
+
+ list_for_each_entry(shp, &hooks_inode_getsecurity, shl_head) {
+ rc = shp->shl_ops->inode_getsecurity(inode, name, buffer,
+ alloc);
+ if (rc != 0)
+ break;
+ }
+ return rc;
}
+static LIST_HEAD(hooks_inode_setsecurity);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
{
+ struct security_hook_list *shp;
+ int rc = -EOPNOTSUPP;
+
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
- return call_int_hook(inode_setsecurity, inode, name, value, size,
- flags);
+
+ list_for_each_entry(shp, &hooks_inode_setsecurity, shl_head) {
+ rc = shp->shl_ops->inode_setsecurity(inode, name, value, size,
+ flags);
+ if (rc != 0)
+ break;
+ }
+ return rc;
}
+static LIST_HEAD(hooks_inode_listsecurity);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{
if (unlikely(IS_PRIVATE(inode)))
@@ -700,11 +839,14 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
}
EXPORT_SYMBOL(security_inode_listsecurity);
+static LIST_HEAD(hooks_inode_getsecid);
void security_inode_getsecid(const struct inode *inode, u32 *secid)
{
+ *secid = 0;
call_void_hook(inode_getsecid, inode, secid);
}
+static LIST_HEAD(hooks_file_permission);
int security_file_permission(struct file *file, int mask)
{
int ret;
@@ -716,16 +858,19 @@ int security_file_permission(struct file *file, int mask)
return fsnotify_perm(file, mask);
}
+static LIST_HEAD(hooks_file_alloc_security);
int security_file_alloc(struct file *file)
{
return call_int_hook(file_alloc_security, file);
}
+static LIST_HEAD(hooks_file_free_security);
void security_file_free(struct file *file)
{
call_void_hook(file_free_security, file);
}
+static LIST_HEAD(hooks_file_ioctl);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return call_int_hook(file_ioctl, file, cmd, arg);
@@ -765,6 +910,7 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
return prot;
}
+static LIST_HEAD(hooks_mmap_file);
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
@@ -776,43 +922,51 @@ int security_mmap_file(struct file *file, unsigned long prot,
return ima_file_mmap(file, prot);
}
+static LIST_HEAD(hooks_mmap_addr);
int security_mmap_addr(unsigned long addr)
{
return call_int_hook(mmap_addr, addr);
}
+static LIST_HEAD(hooks_file_mprotect);
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot)
{
return call_int_hook(file_mprotect, vma, reqprot, prot);
}
+static LIST_HEAD(hooks_file_lock);
int security_file_lock(struct file *file, unsigned int cmd)
{
return call_int_hook(file_lock, file, cmd);
}
+static LIST_HEAD(hooks_file_fcntl);
int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
{
return call_int_hook(file_fcntl, file, cmd, arg);
}
+static LIST_HEAD(hooks_file_set_fowner);
int security_file_set_fowner(struct file *file)
{
return call_int_hook(file_set_fowner, file);
}
+static LIST_HEAD(hooks_file_send_sigiotask);
int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig)
{
return call_int_hook(file_send_sigiotask, tsk, fown, sig);
}
+static LIST_HEAD(hooks_file_receive);
int security_file_receive(struct file *file)
{
return call_int_hook(file_receive, file);
}
+static LIST_HEAD(hooks_file_open);
int security_file_open(struct file *file, const struct cred *cred)
{
int ret;
@@ -824,49 +978,55 @@ int security_file_open(struct file *file, const struct cred *cred)
return fsnotify_perm(file, MAY_OPEN);
}
+static LIST_HEAD(hooks_task_create);
int security_task_create(unsigned long clone_flags)
{
return call_int_hook(task_create, clone_flags);
}
+static LIST_HEAD(hooks_task_free);
void security_task_free(struct task_struct *task)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- yama_task_free(task);
-#endif
call_void_hook(task_free, task);
}
+static LIST_HEAD(hooks_cred_alloc_blank);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
return call_int_hook(cred_alloc_blank, cred, gfp);
}
+static LIST_HEAD(hooks_cred_free);
void security_cred_free(struct cred *cred)
{
call_void_hook(cred_free, cred);
}
+static LIST_HEAD(hooks_cred_prepare);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
{
return call_int_hook(cred_prepare, new, old, gfp);
}
+static LIST_HEAD(hooks_cred_transfer);
void security_transfer_creds(struct cred *new, const struct cred *old)
{
call_void_hook(cred_transfer, new, old);
}
+static LIST_HEAD(hooks_kernel_act_as);
int security_kernel_act_as(struct cred *new, u32 secid)
{
return call_int_hook(kernel_act_as, new, secid);
}
+static LIST_HEAD(hooks_kernel_create_files_as);
int security_kernel_create_files_as(struct cred *new, struct inode *inode)
{
return call_int_hook(kernel_create_files_as, new, inode);
}
+static LIST_HEAD(hooks_kernel_fw_from_file);
int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
{
int ret;
@@ -878,11 +1038,13 @@ int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
}
EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
+static LIST_HEAD(hooks_kernel_module_request);
int security_kernel_module_request(char *kmod_name)
{
return call_int_hook(kernel_module_request, kmod_name);
}
+static LIST_HEAD(hooks_kernel_module_from_file);
int security_kernel_module_from_file(struct file *file)
{
int ret;
@@ -893,200 +1055,249 @@ int security_kernel_module_from_file(struct file *file)
return ima_module_check(file);
}
+static LIST_HEAD(hooks_task_fix_setuid);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags)
{
return call_int_hook(task_fix_setuid, new, old, flags);
}
+static LIST_HEAD(hooks_task_setpgid);
int security_task_setpgid(struct task_struct *p, pid_t pgid)
{
return call_int_hook(task_setpgid, p, pgid);
}
+static LIST_HEAD(hooks_task_getpgid);
int security_task_getpgid(struct task_struct *p)
{
return call_int_hook(task_getpgid, p);
}
+static LIST_HEAD(hooks_task_getsid);
int security_task_getsid(struct task_struct *p)
{
return call_int_hook(task_getsid, p);
}
+static LIST_HEAD(hooks_task_getsecid);
void security_task_getsecid(struct task_struct *p, u32 *secid)
{
+ *secid = 0;
call_void_hook(task_getsecid, p, secid);
}
EXPORT_SYMBOL(security_task_getsecid);
+static LIST_HEAD(hooks_task_setnice);
int security_task_setnice(struct task_struct *p, int nice)
{
return call_int_hook(task_setnice, p, nice);
}
+static LIST_HEAD(hooks_task_setioprio);
int security_task_setioprio(struct task_struct *p, int ioprio)
{
return call_int_hook(task_setioprio, p, ioprio);
}
+static LIST_HEAD(hooks_task_getioprio);
int security_task_getioprio(struct task_struct *p)
{
return call_int_hook(task_getioprio, p);
}
+static LIST_HEAD(hooks_task_setrlimit);
int security_task_setrlimit(struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim)
{
return call_int_hook(task_setrlimit, p, resource, new_rlim);
}
+static LIST_HEAD(hooks_task_setscheduler);
int security_task_setscheduler(struct task_struct *p)
{
return call_int_hook(task_setscheduler, p);
}
+static LIST_HEAD(hooks_task_getscheduler);
int security_task_getscheduler(struct task_struct *p)
{
return call_int_hook(task_getscheduler, p);
}
+static LIST_HEAD(hooks_task_movememory);
int security_task_movememory(struct task_struct *p)
{
return call_int_hook(task_movememory, p);
}
+static LIST_HEAD(hooks_task_kill);
int security_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid)
{
return call_int_hook(task_kill, p, info, sig, secid);
}
+static LIST_HEAD(hooks_task_wait);
int security_task_wait(struct task_struct *p)
{
return call_int_hook(task_wait, p);
}
+static LIST_HEAD(hooks_task_prctl);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_task_prctl(option, arg2, arg3, arg4, arg5);
- if (rc != -ENOSYS)
- return rc;
-#endif
- return call_int_hook(task_prctl, option, arg2, arg3, arg4, arg5);
+ int thisrc;
+ int rc = -ENOSYS;
+ struct security_hook_list *shp;
+
+ if (list_empty(&hooks_task_prctl))
+ return -ENOSYS;
+
+ list_for_each_entry(shp, &hooks_task_prctl, shl_head) {
+ thisrc = shp->shl_ops->task_prctl(option, arg2, arg3,
+ arg4, arg5);
+ if (thisrc != -ENOSYS) {
+ rc = thisrc;
+ if (thisrc != 0)
+ break;
+ }
+ }
+ return rc;
}
+static LIST_HEAD(hooks_task_to_inode);
void security_task_to_inode(struct task_struct *p, struct inode *inode)
{
call_void_hook(task_to_inode, p, inode);
}
+static LIST_HEAD(hooks_ipc_permission);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
{
return call_int_hook(ipc_permission, ipcp, flag);
}
+static LIST_HEAD(hooks_ipc_getsecid);
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
+ *secid = 0;
call_void_hook(ipc_getsecid, ipcp, secid);
}
+static LIST_HEAD(hooks_msg_msg_alloc_security);
int security_msg_msg_alloc(struct msg_msg *msg)
{
return call_int_hook(msg_msg_alloc_security, msg);
}
+static LIST_HEAD(hooks_msg_msg_free_security);
void security_msg_msg_free(struct msg_msg *msg)
{
call_void_hook(msg_msg_free_security, msg);
}
+static LIST_HEAD(hooks_msg_queue_alloc_security);
int security_msg_queue_alloc(struct msg_queue *msq)
{
return call_int_hook(msg_queue_alloc_security, msq);
}
+static LIST_HEAD(hooks_msg_queue_free_security);
void security_msg_queue_free(struct msg_queue *msq)
{
call_void_hook(msg_queue_free_security, msq);
}
+static LIST_HEAD(hooks_msg_queue_associate);
int security_msg_queue_associate(struct msg_queue *msq, int msqflg)
{
return call_int_hook(msg_queue_associate, msq, msqflg);
}
+static LIST_HEAD(hooks_msg_queue_msgctl);
int security_msg_queue_msgctl(struct msg_queue *msq, int cmd)
{
return call_int_hook(msg_queue_msgctl, msq, cmd);
}
+static LIST_HEAD(hooks_msg_queue_msgsnd);
int security_msg_queue_msgsnd(struct msg_queue *msq,
struct msg_msg *msg, int msqflg)
{
return call_int_hook(msg_queue_msgsnd, msq, msg, msqflg);
}
+static LIST_HEAD(hooks_msg_queue_msgrcv);
int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
struct task_struct *target, long type, int mode)
{
return call_int_hook(msg_queue_msgrcv, msq, msg, target, type, mode);
}
+static LIST_HEAD(hooks_shm_alloc_security);
int security_shm_alloc(struct shmid_kernel *shp)
{
return call_int_hook(shm_alloc_security, shp);
}
+static LIST_HEAD(hooks_shm_free_security);
void security_shm_free(struct shmid_kernel *shp)
{
call_void_hook(shm_free_security, shp);
}
+static LIST_HEAD(hooks_shm_associate);
int security_shm_associate(struct shmid_kernel *shp, int shmflg)
{
return call_int_hook(shm_associate, shp, shmflg);
}
+static LIST_HEAD(hooks_shm_shmctl);
int security_shm_shmctl(struct shmid_kernel *shp, int cmd)
{
return call_int_hook(shm_shmctl, shp, cmd);
}
+static LIST_HEAD(hooks_shm_shmat);
int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg)
{
return call_int_hook(shm_shmat, shp, shmaddr, shmflg);
}
+static LIST_HEAD(hooks_sem_alloc_security);
int security_sem_alloc(struct sem_array *sma)
{
return call_int_hook(sem_alloc_security, sma);
}
+static LIST_HEAD(hooks_sem_free_security);
void security_sem_free(struct sem_array *sma)
{
call_void_hook(sem_free_security, sma);
}
+static LIST_HEAD(hooks_sem_associate);
int security_sem_associate(struct sem_array *sma, int semflg)
{
return call_int_hook(sem_associate, sma, semflg);
}
+static LIST_HEAD(hooks_sem_semctl);
int security_sem_semctl(struct sem_array *sma, int cmd)
{
return call_int_hook(sem_semctl, sma, cmd);
}
+static LIST_HEAD(hooks_sem_semop);
int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
unsigned nsops, int alter)
{
return call_int_hook(sem_semop, sma, sops, nsops, alter);
}
+static LIST_HEAD(hooks_d_instantiate);
void security_d_instantiate(struct dentry *dentry, struct inode *inode)
{
if (unlikely(inode && IS_PRIVATE(inode)))
@@ -1095,82 +1306,111 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
}
EXPORT_SYMBOL(security_d_instantiate);
+static LIST_HEAD(hooks_getprocattr);
int security_getprocattr(struct task_struct *p, char *name, char **value)
{
+ if (list_empty(&hooks_getprocattr))
+ return -EINVAL;
return call_int_hook(getprocattr, p, name, value);
}
+static LIST_HEAD(hooks_setprocattr);
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
{
+ if (list_empty(&hooks_setprocattr))
+ return -EINVAL;
return call_int_hook(setprocattr, p, name, value, size);
}
+static LIST_HEAD(hooks_netlink_send);
int security_netlink_send(struct sock *sk, struct sk_buff *skb)
{
return call_int_hook(netlink_send, sk, skb);
}
+static LIST_HEAD(hooks_ismaclabel);
int security_ismaclabel(const char *name)
{
return call_int_hook(ismaclabel, name);
}
EXPORT_SYMBOL(security_ismaclabel);
+static LIST_HEAD(hooks_secid_to_secctx);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
+ if (list_empty(&hooks_secid_to_secctx))
+ return -EOPNOTSUPP;
return call_int_hook(secid_to_secctx, secid, secdata, seclen);
}
EXPORT_SYMBOL(security_secid_to_secctx);
+static LIST_HEAD(hooks_secctx_to_secid);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
+ *secid = 0;
return call_int_hook(secctx_to_secid, secdata, seclen, secid);
}
EXPORT_SYMBOL(security_secctx_to_secid);
+static LIST_HEAD(hooks_release_secctx);
void security_release_secctx(char *secdata, u32 seclen)
{
call_void_hook(release_secctx, secdata, seclen);
}
EXPORT_SYMBOL(security_release_secctx);
+static LIST_HEAD(hooks_inode_notifysecctx);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
return call_int_hook(inode_notifysecctx, inode, ctx, ctxlen);
}
EXPORT_SYMBOL(security_inode_notifysecctx);
+static LIST_HEAD(hooks_inode_setsecctx);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
{
return call_int_hook(inode_setsecctx, dentry, ctx, ctxlen);
}
EXPORT_SYMBOL(security_inode_setsecctx);
+static LIST_HEAD(hooks_inode_getsecctx);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
{
- return call_int_hook(inode_getsecctx, inode, ctx, ctxlen);
+ struct security_hook_list *shp;
+ int rc = -EOPNOTSUPP;
+
+ list_for_each_entry(shp, &hooks_inode_getsecurity, shl_head) {
+ rc = shp->shl_ops->inode_getsecctx(inode, ctx, ctxlen);
+ if (rc != 0)
+ break;
+ }
+ return rc;
}
EXPORT_SYMBOL(security_inode_getsecctx);
#ifdef CONFIG_SECURITY_NETWORK
+static LIST_HEAD(hooks_unix_stream_connect);
int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk)
{
return call_int_hook(unix_stream_connect, sock, other, newsk);
}
EXPORT_SYMBOL(security_unix_stream_connect);
+static LIST_HEAD(hooks_unix_may_send);
int security_unix_may_send(struct socket *sock, struct socket *other)
{
return call_int_hook(unix_may_send, sock, other);
}
EXPORT_SYMBOL(security_unix_may_send);
+static LIST_HEAD(hooks_socket_create);
int security_socket_create(int family, int type, int protocol, int kern)
{
return call_int_hook(socket_create, family, type, protocol, kern);
}
+static LIST_HEAD(hooks_socket_post_create);
int security_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
@@ -1178,115 +1418,140 @@ int security_socket_post_create(struct socket *sock, int family,
protocol, kern);
}
+static LIST_HEAD(hooks_socket_bind);
int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
return call_int_hook(socket_bind, sock, address, addrlen);
}
+static LIST_HEAD(hooks_socket_connect);
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
return call_int_hook(socket_connect, sock, address, addrlen);
}
+static LIST_HEAD(hooks_socket_listen);
int security_socket_listen(struct socket *sock, int backlog)
{
return call_int_hook(socket_listen, sock, backlog);
}
+static LIST_HEAD(hooks_socket_accept);
int security_socket_accept(struct socket *sock, struct socket *newsock)
{
return call_int_hook(socket_accept, sock, newsock);
}
+static LIST_HEAD(hooks_socket_sendmsg);
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
return call_int_hook(socket_sendmsg, sock, msg, size);
}
+static LIST_HEAD(hooks_socket_recvmsg);
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags)
{
return call_int_hook(socket_recvmsg, sock, msg, size, flags);
}
+static LIST_HEAD(hooks_socket_getsockname);
int security_socket_getsockname(struct socket *sock)
{
return call_int_hook(socket_getsockname, sock);
}
+static LIST_HEAD(hooks_socket_getpeername);
int security_socket_getpeername(struct socket *sock)
{
return call_int_hook(socket_getpeername, sock);
}
+static LIST_HEAD(hooks_socket_getsockopt);
int security_socket_getsockopt(struct socket *sock, int level, int optname)
{
return call_int_hook(socket_getsockopt, sock, level, optname);
}
+static LIST_HEAD(hooks_socket_setsockopt);
int security_socket_setsockopt(struct socket *sock, int level, int optname)
{
return call_int_hook(socket_setsockopt, sock, level, optname);
}
+static LIST_HEAD(hooks_socket_shutdown);
int security_socket_shutdown(struct socket *sock, int how)
{
return call_int_hook(socket_shutdown, sock, how);
}
+static LIST_HEAD(hooks_socket_sock_rcv_skb);
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
return call_int_hook(socket_sock_rcv_skb, sk, skb);
}
EXPORT_SYMBOL(security_sock_rcv_skb);
+static LIST_HEAD(hooks_socket_getpeersec_stream);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
+ if (list_empty(&hooks_socket_getpeersec_stream))
+ return -ENOPROTOOPT;
return call_int_hook(socket_getpeersec_stream, sock, optval, optlen,
len);
}
+static LIST_HEAD(hooks_socket_getpeersec_dgram);
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
{
+ if (list_empty(&hooks_socket_getpeersec_dgram))
+ return -ENOPROTOOPT;
return call_int_hook(socket_getpeersec_dgram, sock, skb, secid);
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);
+static LIST_HEAD(hooks_sk_alloc_security);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
{
return call_int_hook(sk_alloc_security, sk, family, priority);
}
+static LIST_HEAD(hooks_sk_free_security);
void security_sk_free(struct sock *sk)
{
call_void_hook(sk_free_security, sk);
}
+static LIST_HEAD(hooks_sk_clone_security);
void security_sk_clone(const struct sock *sk, struct sock *newsk)
{
call_void_hook(sk_clone_security, sk, newsk);
}
EXPORT_SYMBOL(security_sk_clone);
+static LIST_HEAD(hooks_sk_getsecid);
void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{
call_void_hook(sk_getsecid, sk, &fl->flowi_secid);
}
EXPORT_SYMBOL(security_sk_classify_flow);
+static LIST_HEAD(hooks_req_classify_flow);
void security_req_classify_flow(const struct request_sock *req, struct flowi *fl)
{
call_void_hook(req_classify_flow, req, fl);
}
EXPORT_SYMBOL(security_req_classify_flow);
+static LIST_HEAD(hooks_sock_graft);
void security_sock_graft(struct sock *sk, struct socket *parent)
{
call_void_hook(sock_graft, sk, parent);
}
EXPORT_SYMBOL(security_sock_graft);
+static LIST_HEAD(hooks_inet_conn_request);
int security_inet_conn_request(struct sock *sk,
struct sk_buff *skb, struct request_sock *req)
{
@@ -1294,72 +1559,84 @@ int security_inet_conn_request(struct sock *sk,
}
EXPORT_SYMBOL(security_inet_conn_request);
+static LIST_HEAD(hooks_inet_csk_clone);
void security_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
call_void_hook(inet_csk_clone, newsk, req);
}
+static LIST_HEAD(hooks_inet_conn_established);
void security_inet_conn_established(struct sock *sk,
struct sk_buff *skb)
{
call_void_hook(inet_conn_established, sk, skb);
}
+static LIST_HEAD(hooks_secmark_relabel_packet);
int security_secmark_relabel_packet(u32 secid)
{
return call_int_hook(secmark_relabel_packet, secid);
}
EXPORT_SYMBOL(security_secmark_relabel_packet);
+static LIST_HEAD(hooks_secmark_refcount_inc);
void security_secmark_refcount_inc(void)
{
call_void_hook(secmark_refcount_inc);
}
EXPORT_SYMBOL(security_secmark_refcount_inc);
+static LIST_HEAD(hooks_secmark_refcount_dec);
void security_secmark_refcount_dec(void)
{
call_void_hook(secmark_refcount_dec);
}
EXPORT_SYMBOL(security_secmark_refcount_dec);
+static LIST_HEAD(hooks_tun_dev_alloc_security);
int security_tun_dev_alloc_security(void **security)
{
return call_int_hook(tun_dev_alloc_security, security);
}
EXPORT_SYMBOL(security_tun_dev_alloc_security);
+static LIST_HEAD(hooks_tun_dev_free_security);
void security_tun_dev_free_security(void *security)
{
call_void_hook(tun_dev_free_security, security);
}
EXPORT_SYMBOL(security_tun_dev_free_security);
+static LIST_HEAD(hooks_tun_dev_create);
int security_tun_dev_create(void)
{
return call_int_hook(tun_dev_create);
}
EXPORT_SYMBOL(security_tun_dev_create);
+static LIST_HEAD(hooks_tun_dev_attach_queue);
int security_tun_dev_attach_queue(void *security)
{
return call_int_hook(tun_dev_attach_queue, security);
}
EXPORT_SYMBOL(security_tun_dev_attach_queue);
+static LIST_HEAD(hooks_tun_dev_attach);
int security_tun_dev_attach(struct sock *sk, void *security)
{
return call_int_hook(tun_dev_attach, sk, security);
}
EXPORT_SYMBOL(security_tun_dev_attach);
+static LIST_HEAD(hooks_tun_dev_open);
int security_tun_dev_open(void *security)
{
return call_int_hook(tun_dev_open, security);
}
EXPORT_SYMBOL(security_tun_dev_open);
+static LIST_HEAD(hooks_skb_owned_by);
void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
{
call_void_hook(skb_owned_by, skb, sk);
@@ -1369,6 +1646,7 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM
+static LIST_HEAD(hooks_xfrm_policy_alloc_security);
int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx,
gfp_t gfp)
@@ -1377,23 +1655,27 @@ int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
}
EXPORT_SYMBOL(security_xfrm_policy_alloc);
+static LIST_HEAD(hooks_xfrm_policy_clone_security);
int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp)
{
return call_int_hook(xfrm_policy_clone_security, old_ctx, new_ctxp);
}
+static LIST_HEAD(hooks_xfrm_policy_free_security);
void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
{
call_void_hook(xfrm_policy_free_security, ctx);
}
EXPORT_SYMBOL(security_xfrm_policy_free);
+static LIST_HEAD(hooks_xfrm_policy_delete_security);
int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{
return call_int_hook(xfrm_policy_delete_security, ctx);
}
+static LIST_HEAD(hooks_xfrm_state_alloc);
int security_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx)
{
@@ -1401,35 +1683,43 @@ int security_xfrm_state_alloc(struct xfrm_state *x,
}
EXPORT_SYMBOL(security_xfrm_state_alloc);
+static LIST_HEAD(hooks_xfrm_state_alloc_acquire);
int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec, u32 secid)
{
return call_int_hook(xfrm_state_alloc_acquire, x, polsec, secid);
}
+static LIST_HEAD(hooks_xfrm_state_delete_security);
int security_xfrm_state_delete(struct xfrm_state *x)
{
return call_int_hook(xfrm_state_delete_security, x);
}
EXPORT_SYMBOL(security_xfrm_state_delete);
+static LIST_HEAD(hooks_xfrm_state_free_security);
void security_xfrm_state_free(struct xfrm_state *x)
{
call_void_hook(xfrm_state_free_security, x);
}
+static LIST_HEAD(hooks_xfrm_policy_lookup);
int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
{
return call_int_hook(xfrm_policy_lookup, ctx, fl_secid, dir);
}
+static LIST_HEAD(hooks_xfrm_state_pol_flow_match);
int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp,
const struct flowi *fl)
{
+ if (list_empty(&hooks_xfrm_state_pol_flow_match))
+ return 1;
return call_int_hook(xfrm_state_pol_flow_match, x, xp, fl);
}
+static LIST_HEAD(hooks_xfrm_decode_session);
int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
{
return call_int_hook(xfrm_decode_session, skb, secid, 1);
@@ -1440,7 +1730,9 @@ int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
*/
void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
{
- int rc = call_int_hook(xfrm_decode_session, skb, &fl->flowi_secid, 0);
+ int rc;
+
+ rc = call_int_hook(xfrm_decode_session, skb, &fl->flowi_secid, 0);
BUG_ON(rc);
}
@@ -1450,25 +1742,30 @@ EXPORT_SYMBOL(security_skb_classify_flow);
#ifdef CONFIG_KEYS
+static LIST_HEAD(hooks_key_alloc);
int security_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
return call_int_hook(key_alloc, key, cred, flags);
}
+static LIST_HEAD(hooks_key_free);
void security_key_free(struct key *key)
{
call_void_hook(key_free, key);
}
+static LIST_HEAD(hooks_key_permission);
int security_key_permission(key_ref_t key_ref,
const struct cred *cred, unsigned perm)
{
return call_int_hook(key_permission, key_ref, cred, perm);
}
+static LIST_HEAD(hooks_key_getsecurity);
int security_key_getsecurity(struct key *key, char **_buffer)
{
+ *_buffer = NULL;
return call_int_hook(key_getsecurity, key, _buffer);
}
@@ -1476,21 +1773,25 @@ int security_key_getsecurity(struct key *key, char **_buffer)
#ifdef CONFIG_AUDIT
+static LIST_HEAD(hooks_audit_rule_init);
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
{
return call_int_hook(audit_rule_init, field, op, rulestr, lsmrule);
}
+static LIST_HEAD(hooks_audit_rule_known);
int security_audit_rule_known(struct audit_krule *krule)
{
return call_int_hook(audit_rule_known, krule);
}
+static LIST_HEAD(hooks_audit_rule_free);
void security_audit_rule_free(void *lsmrule)
{
call_void_hook(audit_rule_free, lsmrule);
}
+static LIST_HEAD(hooks_audit_rule_match);
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
struct audit_context *actx)
{
@@ -1498,3 +1799,736 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
}
#endif /* CONFIG_AUDIT */
+
+static int __init add_hook_to_list(struct list_head *hooklist,
+ void *interesting,
+ struct security_operations *sop)
+{
+ struct security_hook_list *new;
+ struct security_hook_list *shp;
+
+ if (hooklist->next == NULL)
+ INIT_LIST_HEAD(hooklist);
+
+ if (interesting == NULL)
+ return 0;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (new == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&new->shl_head);
+ new->shl_ops = sop;
+
+ shp = list_last_entry(hooklist, struct security_hook_list, shl_head);
+ list_add_rcu(&new->shl_head, &shp->shl_head);
+
+ return 0;
+}
+
+static int __init security_enlist_ops(struct security_operations *sop)
+{
+ pr_info("Security operations for %s initialized\n", sop->name);
+
+ if (add_hook_to_list(&hooks_ptrace_access_check,
+ sop->ptrace_access_check, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_ptrace_traceme, sop->ptrace_traceme, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_capget, sop->capget, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_capset, sop->capset, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_capable, sop->capable, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_quotactl, sop->quotactl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_quota_on, sop->quota_on, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_syslog, sop->syslog, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_settime, sop->settime, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_vm_enough_memory,
+ sop->vm_enough_memory, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_bprm_set_creds, sop->bprm_set_creds, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_bprm_committing_creds,
+ sop->bprm_committing_creds, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_bprm_committed_creds,
+ sop->bprm_committed_creds, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_bprm_check_security,
+ sop->bprm_check_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_bprm_secureexec, sop->bprm_secureexec, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_alloc_security,
+ sop->sb_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_free_security,
+ sop->sb_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_copy_data, sop->sb_copy_data, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_remount, sop->sb_remount, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_kern_mount, sop->sb_kern_mount, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_show_options, sop->sb_show_options, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_statfs, sop->sb_statfs, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_mount, sop->sb_mount, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_umount, sop->sb_umount, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_pivotroot, sop->sb_pivotroot, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_set_mnt_opts, sop->sb_set_mnt_opts, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_clone_mnt_opts,
+ sop->sb_clone_mnt_opts, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sb_parse_opts_str,
+ sop->sb_parse_opts_str, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_dentry_init_security,
+ sop->dentry_init_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_alloc_security,
+ sop->inode_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_free_security,
+ sop->inode_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_init_security,
+ sop->inode_init_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_create, sop->inode_create, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_link, sop->inode_link, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_unlink, sop->inode_unlink, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_symlink, sop->inode_symlink, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_mkdir, sop->inode_mkdir, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_rmdir, sop->inode_rmdir, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_mknod, sop->inode_mknod, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_rename, sop->inode_rename, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_readlink, sop->inode_readlink, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_follow_link,
+ sop->inode_follow_link, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_permission,
+ sop->inode_permission, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_setattr, sop->inode_setattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_getattr, sop->inode_getattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_setxattr, sop->inode_setxattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_post_setxattr,
+ sop->inode_post_setxattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_getxattr, sop->inode_getxattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_listxattr, sop->inode_listxattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_removexattr,
+ sop->inode_removexattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_need_killpriv,
+ sop->inode_need_killpriv, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_killpriv, sop->inode_killpriv, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_getsecurity,
+ sop->inode_getsecurity, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_setsecurity,
+ sop->inode_setsecurity, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_listsecurity,
+ sop->inode_listsecurity, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_getsecid,
+ sop->inode_getsecid, sop))
+ return -ENOMEM;
+#ifdef CONFIG_SECURITY_PATH
+ if (add_hook_to_list(&hooks_path_mknod, sop->path_mknod, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_mkdir, sop->path_mkdir, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_rmdir, sop->path_rmdir, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_unlink, sop->path_unlink, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_symlink, sop->path_symlink, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_link, sop->path_link, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_rename, sop->path_rename, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_truncate, sop->path_truncate, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_chmod, sop->path_chmod, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_chown, sop->path_chown, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_path_chroot, sop->path_chroot, sop))
+ return -ENOMEM;
+#endif
+ if (add_hook_to_list(&hooks_file_permission, sop->file_permission, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_alloc_security,
+ sop->file_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_free_security,
+ sop->file_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_ioctl, sop->file_ioctl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_mmap_addr, sop->mmap_addr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_mmap_file, sop->mmap_file, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_mprotect, sop->file_mprotect, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_lock, sop->file_lock, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_fcntl, sop->file_fcntl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_set_fowner, sop->file_set_fowner, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_send_sigiotask,
+ sop->file_send_sigiotask, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_receive, sop->file_receive, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_file_open, sop->file_open, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_create, sop->task_create, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_free, sop->task_free, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_cred_alloc_blank,
+ sop->cred_alloc_blank, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_cred_free, sop->cred_free, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_cred_prepare, sop->cred_prepare, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_cred_transfer, sop->cred_transfer, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_kernel_act_as, sop->kernel_act_as, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_kernel_create_files_as,
+ sop->kernel_create_files_as, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_kernel_fw_from_file,
+ sop->kernel_fw_from_file, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_kernel_module_request,
+ sop->kernel_module_request, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_kernel_module_from_file,
+ sop->kernel_module_from_file, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_fix_setuid, sop->task_fix_setuid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_setpgid, sop->task_setpgid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_getpgid, sop->task_getpgid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_getsid, sop->task_getsid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_getsecid, sop->task_getsecid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_setnice, sop->task_setnice, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_setioprio, sop->task_setioprio, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_getioprio, sop->task_getioprio, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_setrlimit, sop->task_setrlimit, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_setscheduler,
+ sop->task_setscheduler, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_getscheduler,
+ sop->task_getscheduler, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_movememory, sop->task_movememory, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_wait, sop->task_wait, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_kill, sop->task_kill, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_prctl, sop->task_prctl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_task_to_inode, sop->task_to_inode, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_ipc_permission, sop->ipc_permission, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_ipc_getsecid, sop->ipc_getsecid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_msg_alloc_security,
+ sop->msg_msg_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_msg_free_security,
+ sop->msg_msg_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_alloc_security,
+ sop->msg_queue_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_free_security,
+ sop->msg_queue_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_associate,
+ sop->msg_queue_associate, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_msgctl,
+ sop->msg_queue_msgctl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_msgsnd,
+ sop->msg_queue_msgsnd, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_msg_queue_msgrcv,
+ sop->msg_queue_msgrcv, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_shm_alloc_security,
+ sop->shm_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_shm_free_security,
+ sop->shm_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_shm_associate, sop->shm_associate, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_shm_shmctl, sop->shm_shmctl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_shm_shmat, sop->shm_shmat, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sem_alloc_security,
+ sop->sem_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sem_free_security,
+ sop->sem_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sem_associate, sop->sem_associate, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sem_semctl, sop->sem_semctl, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sem_semop, sop->sem_semop, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_netlink_send, sop->netlink_send, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_d_instantiate, sop->d_instantiate, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_getprocattr, sop->getprocattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_setprocattr, sop->setprocattr, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_ismaclabel, sop->ismaclabel, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_secid_to_secctx, sop->secid_to_secctx, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_secctx_to_secid, sop->secctx_to_secid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_release_secctx, sop->release_secctx, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_notifysecctx,
+ sop->inode_notifysecctx, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_setsecctx, sop->inode_setsecctx, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inode_getsecctx, sop->inode_getsecctx, sop))
+ return -ENOMEM;
+#ifdef CONFIG_SECURITY_NETWORK
+ if (add_hook_to_list(&hooks_unix_stream_connect,
+ sop->unix_stream_connect, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_unix_may_send, sop->unix_may_send, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_create, sop->socket_create, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_post_create,
+ sop->socket_post_create, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_bind, sop->socket_bind, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_connect, sop->socket_connect, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_listen, sop->socket_listen, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_accept, sop->socket_accept, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_sendmsg, sop->socket_sendmsg, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_recvmsg, sop->socket_recvmsg, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_getsockname,
+ sop->socket_getsockname, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_getpeername,
+ sop->socket_getpeername, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_setsockopt,
+ sop->socket_setsockopt, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_getsockopt,
+ sop->socket_getsockopt, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_shutdown, sop->socket_shutdown, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_sock_rcv_skb,
+ sop->socket_sock_rcv_skb, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_getpeersec_stream,
+ sop->socket_getpeersec_stream, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_socket_getpeersec_dgram,
+ sop->socket_getpeersec_dgram, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sk_alloc_security,
+ sop->sk_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sk_free_security,
+ sop->sk_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sk_clone_security,
+ sop->sk_clone_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sk_getsecid, sop->sk_getsecid, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_sock_graft, sop->sock_graft, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inet_conn_request,
+ sop->inet_conn_request, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inet_csk_clone, sop->inet_csk_clone, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_inet_conn_established,
+ sop->inet_conn_established, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_secmark_relabel_packet,
+ sop->secmark_relabel_packet, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_secmark_refcount_inc,
+ sop->secmark_refcount_inc, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_secmark_refcount_dec,
+ sop->secmark_refcount_dec, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_req_classify_flow,
+ sop->req_classify_flow, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_alloc_security,
+ sop->tun_dev_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_free_security,
+ sop->tun_dev_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_create, sop->tun_dev_create, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_open, sop->tun_dev_open, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_attach_queue,
+ sop->tun_dev_attach_queue, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_tun_dev_attach, sop->tun_dev_attach, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_skb_owned_by, sop->skb_owned_by, sop))
+ return -ENOMEM;
+#endif /* CONFIG_SECURITY_NETWORK */
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+ if (add_hook_to_list(&hooks_xfrm_policy_alloc_security,
+ sop->xfrm_policy_alloc_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_policy_clone_security,
+ sop->xfrm_policy_clone_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_policy_free_security,
+ sop->xfrm_policy_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_policy_delete_security,
+ sop->xfrm_policy_delete_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_state_alloc,
+ sop->xfrm_state_alloc, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_state_alloc_acquire,
+ sop->xfrm_state_alloc_acquire, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_state_free_security,
+ sop->xfrm_state_free_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_state_delete_security,
+ sop->xfrm_state_delete_security, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_policy_lookup,
+ sop->xfrm_policy_lookup, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_state_pol_flow_match,
+ sop->xfrm_state_pol_flow_match, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_xfrm_decode_session,
+ sop->xfrm_decode_session, sop))
+ return -ENOMEM;
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+#ifdef CONFIG_KEYS
+ if (add_hook_to_list(&hooks_key_alloc, sop->key_alloc, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_key_free, sop->key_free, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_key_permission, sop->key_permission, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_key_getsecurity, sop->key_getsecurity, sop))
+ return -ENOMEM;
+#endif /* CONFIG_KEYS */
+#ifdef CONFIG_AUDIT
+ if (add_hook_to_list(&hooks_audit_rule_init, sop->audit_rule_init, sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_audit_rule_known, sop->audit_rule_known,
+ sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_audit_rule_match, sop->audit_rule_match,
+ sop))
+ return -ENOMEM;
+ if (add_hook_to_list(&hooks_audit_rule_free, sop->audit_rule_free, sop))
+ return -ENOMEM;
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_SECURITY_SELINUX_DISABLE
+static void clear_hook_entry(struct list_head *head,
+ struct security_operations *sop)
+{
+ struct security_hook_list *shp;
+
+ list_for_each_entry(shp, head, shl_head)
+ if (shp->shl_ops == sop) {
+ list_del_rcu(&shp->shl_head);
+ return;
+ }
+}
+
+void security_module_disable(struct security_operations *sop)
+{
+ pr_info("Security operations for %s disabled.\n", sop->name);
+ clear_hook_entry(&hooks_ptrace_access_check, sop);
+ clear_hook_entry(&hooks_ptrace_traceme, sop);
+ clear_hook_entry(&hooks_capget, sop);
+ clear_hook_entry(&hooks_capset, sop);
+ clear_hook_entry(&hooks_capable, sop);
+ clear_hook_entry(&hooks_quotactl, sop);
+ clear_hook_entry(&hooks_quota_on, sop);
+ clear_hook_entry(&hooks_syslog, sop);
+ clear_hook_entry(&hooks_settime, sop);
+ clear_hook_entry(&hooks_vm_enough_memory, sop);
+ clear_hook_entry(&hooks_bprm_set_creds, sop);
+ clear_hook_entry(&hooks_bprm_committing_creds, sop);
+ clear_hook_entry(&hooks_bprm_committed_creds, sop);
+ clear_hook_entry(&hooks_bprm_check_security, sop);
+ clear_hook_entry(&hooks_bprm_secureexec, sop);
+ clear_hook_entry(&hooks_sb_alloc_security, sop);
+ clear_hook_entry(&hooks_sb_free_security, sop);
+ clear_hook_entry(&hooks_sb_copy_data, sop);
+ clear_hook_entry(&hooks_sb_remount, sop);
+ clear_hook_entry(&hooks_sb_kern_mount, sop);
+ clear_hook_entry(&hooks_sb_show_options, sop);
+ clear_hook_entry(&hooks_sb_statfs, sop);
+ clear_hook_entry(&hooks_sb_mount, sop);
+ clear_hook_entry(&hooks_sb_umount, sop);
+ clear_hook_entry(&hooks_sb_pivotroot, sop);
+ clear_hook_entry(&hooks_sb_set_mnt_opts, sop);
+ clear_hook_entry(&hooks_sb_clone_mnt_opts, sop);
+ clear_hook_entry(&hooks_sb_parse_opts_str, sop);
+ clear_hook_entry(&hooks_dentry_init_security, sop);
+ clear_hook_entry(&hooks_inode_alloc_security, sop);
+ clear_hook_entry(&hooks_inode_free_security, sop);
+ clear_hook_entry(&hooks_inode_init_security, sop);
+ clear_hook_entry(&hooks_inode_create, sop);
+ clear_hook_entry(&hooks_inode_link, sop);
+ clear_hook_entry(&hooks_inode_unlink, sop);
+ clear_hook_entry(&hooks_inode_symlink, sop);
+ clear_hook_entry(&hooks_inode_mkdir, sop);
+ clear_hook_entry(&hooks_inode_rmdir, sop);
+ clear_hook_entry(&hooks_inode_mknod, sop);
+ clear_hook_entry(&hooks_inode_rename, sop);
+ clear_hook_entry(&hooks_inode_readlink, sop);
+ clear_hook_entry(&hooks_inode_follow_link, sop);
+ clear_hook_entry(&hooks_inode_permission, sop);
+ clear_hook_entry(&hooks_inode_setattr, sop);
+ clear_hook_entry(&hooks_inode_getattr, sop);
+ clear_hook_entry(&hooks_inode_setxattr, sop);
+ clear_hook_entry(&hooks_inode_post_setxattr, sop);
+ clear_hook_entry(&hooks_inode_getxattr, sop);
+ clear_hook_entry(&hooks_inode_listxattr, sop);
+ clear_hook_entry(&hooks_inode_removexattr, sop);
+ clear_hook_entry(&hooks_inode_need_killpriv, sop);
+ clear_hook_entry(&hooks_inode_killpriv, sop);
+ clear_hook_entry(&hooks_inode_getsecurity, sop);
+ clear_hook_entry(&hooks_inode_setsecurity, sop);
+ clear_hook_entry(&hooks_inode_listsecurity, sop);
+ clear_hook_entry(&hooks_inode_getsecid, sop);
+#ifdef CONFIG_SECURITY_PATH
+ clear_hook_entry(&hooks_path_mknod, sop);
+ clear_hook_entry(&hooks_path_mkdir, sop);
+ clear_hook_entry(&hooks_path_rmdir, sop);
+ clear_hook_entry(&hooks_path_unlink, sop);
+ clear_hook_entry(&hooks_path_symlink, sop);
+ clear_hook_entry(&hooks_path_link, sop);
+ clear_hook_entry(&hooks_path_rename, sop);
+ clear_hook_entry(&hooks_path_truncate, sop);
+ clear_hook_entry(&hooks_path_chmod, sop);
+ clear_hook_entry(&hooks_path_chown, sop);
+ clear_hook_entry(&hooks_path_chroot, sop);
+#endif
+ clear_hook_entry(&hooks_file_permission, sop);
+ clear_hook_entry(&hooks_file_alloc_security, sop);
+ clear_hook_entry(&hooks_file_free_security, sop);
+ clear_hook_entry(&hooks_file_ioctl, sop);
+ clear_hook_entry(&hooks_mmap_addr, sop);
+ clear_hook_entry(&hooks_mmap_file, sop);
+ clear_hook_entry(&hooks_file_mprotect, sop);
+ clear_hook_entry(&hooks_file_lock, sop);
+ clear_hook_entry(&hooks_file_fcntl, sop);
+ clear_hook_entry(&hooks_file_set_fowner, sop);
+ clear_hook_entry(&hooks_file_send_sigiotask, sop);
+ clear_hook_entry(&hooks_file_receive, sop);
+ clear_hook_entry(&hooks_file_open, sop);
+ clear_hook_entry(&hooks_task_create, sop);
+ clear_hook_entry(&hooks_task_free, sop);
+ clear_hook_entry(&hooks_cred_alloc_blank, sop);
+ clear_hook_entry(&hooks_cred_free, sop);
+ clear_hook_entry(&hooks_cred_prepare, sop);
+ clear_hook_entry(&hooks_cred_transfer, sop);
+ clear_hook_entry(&hooks_kernel_act_as, sop);
+ clear_hook_entry(&hooks_kernel_create_files_as, sop);
+ clear_hook_entry(&hooks_kernel_fw_from_file, sop);
+ clear_hook_entry(&hooks_kernel_module_request, sop);
+ clear_hook_entry(&hooks_kernel_module_from_file, sop);
+ clear_hook_entry(&hooks_task_fix_setuid, sop);
+ clear_hook_entry(&hooks_task_setpgid, sop);
+ clear_hook_entry(&hooks_task_getpgid, sop);
+ clear_hook_entry(&hooks_task_getsid, sop);
+ clear_hook_entry(&hooks_task_getsecid, sop);
+ clear_hook_entry(&hooks_task_setnice, sop);
+ clear_hook_entry(&hooks_task_setioprio, sop);
+ clear_hook_entry(&hooks_task_getioprio, sop);
+ clear_hook_entry(&hooks_task_setrlimit, sop);
+ clear_hook_entry(&hooks_task_setscheduler, sop);
+ clear_hook_entry(&hooks_task_getscheduler, sop);
+ clear_hook_entry(&hooks_task_movememory, sop);
+ clear_hook_entry(&hooks_task_wait, sop);
+ clear_hook_entry(&hooks_task_kill, sop);
+ clear_hook_entry(&hooks_task_prctl, sop);
+ clear_hook_entry(&hooks_task_to_inode, sop);
+ clear_hook_entry(&hooks_ipc_permission, sop);
+ clear_hook_entry(&hooks_ipc_getsecid, sop);
+ clear_hook_entry(&hooks_msg_msg_alloc_security, sop);
+ clear_hook_entry(&hooks_msg_msg_free_security, sop);
+ clear_hook_entry(&hooks_msg_queue_alloc_security, sop);
+ clear_hook_entry(&hooks_msg_queue_free_security, sop);
+ clear_hook_entry(&hooks_msg_queue_associate, sop);
+ clear_hook_entry(&hooks_msg_queue_msgctl, sop);
+ clear_hook_entry(&hooks_msg_queue_msgsnd, sop);
+ clear_hook_entry(&hooks_msg_queue_msgrcv, sop);
+ clear_hook_entry(&hooks_shm_alloc_security, sop);
+ clear_hook_entry(&hooks_shm_free_security, sop);
+ clear_hook_entry(&hooks_shm_associate, sop);
+ clear_hook_entry(&hooks_shm_shmctl, sop);
+ clear_hook_entry(&hooks_shm_shmat, sop);
+ clear_hook_entry(&hooks_sem_alloc_security, sop);
+ clear_hook_entry(&hooks_sem_free_security, sop);
+ clear_hook_entry(&hooks_sem_associate, sop);
+ clear_hook_entry(&hooks_sem_semctl, sop);
+ clear_hook_entry(&hooks_sem_semop, sop);
+ clear_hook_entry(&hooks_netlink_send, sop);
+ clear_hook_entry(&hooks_d_instantiate, sop);
+ clear_hook_entry(&hooks_getprocattr, sop);
+ clear_hook_entry(&hooks_setprocattr, sop);
+ clear_hook_entry(&hooks_ismaclabel, sop);
+ clear_hook_entry(&hooks_secid_to_secctx, sop);
+ clear_hook_entry(&hooks_secctx_to_secid, sop);
+ clear_hook_entry(&hooks_release_secctx, sop);
+ clear_hook_entry(&hooks_inode_notifysecctx, sop);
+ clear_hook_entry(&hooks_inode_setsecctx, sop);
+ clear_hook_entry(&hooks_inode_getsecctx, sop);
+#ifdef CONFIG_SECURITY_NETWORK
+ clear_hook_entry(&hooks_unix_stream_connect, sop);
+ clear_hook_entry(&hooks_unix_may_send, sop);
+ clear_hook_entry(&hooks_socket_create, sop);
+ clear_hook_entry(&hooks_socket_post_create, sop);
+ clear_hook_entry(&hooks_socket_bind, sop);
+ clear_hook_entry(&hooks_socket_connect, sop);
+ clear_hook_entry(&hooks_socket_listen, sop);
+ clear_hook_entry(&hooks_socket_accept, sop);
+ clear_hook_entry(&hooks_socket_sendmsg, sop);
+ clear_hook_entry(&hooks_socket_recvmsg, sop);
+ clear_hook_entry(&hooks_socket_getsockname, sop);
+ clear_hook_entry(&hooks_socket_getpeername, sop);
+ clear_hook_entry(&hooks_socket_setsockopt, sop);
+ clear_hook_entry(&hooks_socket_getsockopt, sop);
+ clear_hook_entry(&hooks_socket_shutdown, sop);
+ clear_hook_entry(&hooks_socket_sock_rcv_skb, sop);
+ clear_hook_entry(&hooks_socket_getpeersec_stream, sop);
+ clear_hook_entry(&hooks_socket_getpeersec_dgram, sop);
+ clear_hook_entry(&hooks_sk_alloc_security, sop);
+ clear_hook_entry(&hooks_sk_free_security, sop);
+ clear_hook_entry(&hooks_sk_clone_security, sop);
+ clear_hook_entry(&hooks_sk_getsecid, sop);
+ clear_hook_entry(&hooks_sock_graft, sop);
+ clear_hook_entry(&hooks_inet_conn_request, sop);
+ clear_hook_entry(&hooks_inet_csk_clone, sop);
+ clear_hook_entry(&hooks_inet_conn_established, sop);
+ clear_hook_entry(&hooks_secmark_relabel_packet, sop);
+ clear_hook_entry(&hooks_secmark_refcount_inc, sop);
+ clear_hook_entry(&hooks_secmark_refcount_dec, sop);
+ clear_hook_entry(&hooks_req_classify_flow, sop);
+ clear_hook_entry(&hooks_tun_dev_alloc_security, sop);
+ clear_hook_entry(&hooks_tun_dev_free_security, sop);
+ clear_hook_entry(&hooks_tun_dev_create, sop);
+ clear_hook_entry(&hooks_tun_dev_open, sop);
+ clear_hook_entry(&hooks_tun_dev_attach_queue, sop);
+ clear_hook_entry(&hooks_tun_dev_attach, sop);
+ clear_hook_entry(&hooks_skb_owned_by, sop);
+#endif /* CONFIG_SECURITY_NETWORK */
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+ clear_hook_entry(&hooks_xfrm_policy_alloc_security, sop);
+ clear_hook_entry(&hooks_xfrm_policy_clone_security, sop);
+ clear_hook_entry(&hooks_xfrm_policy_free_security, sop);
+ clear_hook_entry(&hooks_xfrm_policy_delete_security, sop);
+ clear_hook_entry(&hooks_xfrm_state_alloc, sop);
+ clear_hook_entry(&hooks_xfrm_state_alloc_acquire, sop);
+ clear_hook_entry(&hooks_xfrm_state_free_security, sop);
+ clear_hook_entry(&hooks_xfrm_state_delete_security, sop);
+ clear_hook_entry(&hooks_xfrm_policy_lookup, sop);
+ clear_hook_entry(&hooks_xfrm_state_pol_flow_match, sop);
+ clear_hook_entry(&hooks_xfrm_decode_session, sop);
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+#ifdef CONFIG_KEYS
+ clear_hook_entry(&hooks_key_alloc, sop);
+ clear_hook_entry(&hooks_key_free, sop);
+ clear_hook_entry(&hooks_key_permission, sop);
+ clear_hook_entry(&hooks_key_getsecurity, sop);
+#endif /* CONFIG_KEYS */
+#ifdef CONFIG_AUDIT
+ clear_hook_entry(&hooks_audit_rule_init, sop);
+ clear_hook_entry(&hooks_audit_rule_known, sop);
+ clear_hook_entry(&hooks_audit_rule_match, sop);
+ clear_hook_entry(&hooks_audit_rule_free, sop);
+#endif
+}
+#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b0e9404..9530124 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1938,12 +1938,6 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int rc;
-
- rc = cap_ptrace_access_check(child, mode);
- if (rc)
- return rc;
-
if (mode & PTRACE_MODE_READ) {
u32 sid = current_sid();
u32 csid = task_sid(child);
@@ -1955,12 +1949,6 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- int rc;
-
- rc = cap_ptrace_traceme(parent);
- if (rc)
- return rc;
-
return task_has_perm(parent, current, PROCESS__PTRACE);
}
@@ -2004,12 +1992,6 @@ static int selinux_capset(struct cred *new, const struct cred *old,
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit)
{
- int rc;
-
- rc = cap_capable(cred, ns, cap, audit);
- if (rc)
- return rc;
-
return cred_has_capability(cred, cap, audit);
}
@@ -2087,12 +2069,12 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{
int rc, cap_sys_admin = 0;
- rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
- SECURITY_CAP_NOAUDIT);
+ rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
+ SECURITY_CAP_NOAUDIT);
if (rc == 0)
cap_sys_admin = 1;
- return __vm_enough_memory(mm, pages, cap_sys_admin);
+ return cap_sys_admin;
}
/* binprm security operations */
@@ -2106,10 +2088,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file);
int rc;
- rc = cap_bprm_set_creds(bprm);
- if (rc)
- return rc;
-
/* SELinux context only depends on initial program or script and not
* the script interpreter */
if (bprm->cred_prepared)
@@ -2233,7 +2211,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
PROCESS__NOATSECURE, NULL);
}
- return (atsecure || cap_bprm_secureexec(bprm));
+ return atsecure;
}
static int match_file(const void *p, struct file *file, unsigned fd)
@@ -3051,8 +3029,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
* and lack of permission just means that we fall back to the
* in-core context value, not a denial.
*/
- error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
- SECURITY_CAP_NOAUDIT);
+ error = cred_has_capability(current_cred(), CAP_MAC_ADMIN,
+ SECURITY_CAP_NOAUDIT);
if (!error)
error = security_sid_to_context_force(isec->sid, &context,
&size);
@@ -3237,12 +3215,7 @@ error:
static int selinux_mmap_addr(unsigned long addr)
{
- int rc;
-
- /* do DAC check on address space usage */
- rc = cap_mmap_addr(addr);
- if (rc)
- return rc;
+ int rc = 0;
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid();
@@ -3560,23 +3533,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- int rc;
-
- rc = cap_task_setnice(p, nice);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- int rc;
-
- rc = cap_task_setioprio(p, ioprio);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
@@ -3602,12 +3563,6 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
- int rc;
-
- rc = cap_task_setscheduler(p);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
@@ -5029,12 +4984,6 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- int err;
-
- err = cap_netlink_send(sk, skb);
- if (err)
- return err;
-
return selinux_nlmsg_perm(sk, skb);
}
@@ -6145,7 +6094,7 @@ int selinux_disable(void)
selinux_disabled = 1;
selinux_enabled = 0;
- reset_security_ops();
+ security_module_disable(&selinux_ops);
/* Try to destroy the avc node cache */
avc_disable();
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e6ab307..53660f9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -244,10 +244,6 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
int rc;
struct smack_known *skp;
- rc = cap_ptrace_access_check(ctp, mode);
- if (rc != 0)
- return rc;
-
skp = smk_of_task(task_security(ctp));
rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
@@ -267,10 +263,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
int rc;
struct smack_known *skp;
- rc = cap_ptrace_traceme(ptp);
- if (rc != 0)
- return rc;
-
skp = smk_of_task(current_security());
rc = smk_ptrace_rule_check(ptp, skp->smk_known,
@@ -525,12 +517,9 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file);
struct task_smack *bsp = bprm->cred->security;
struct inode_smack *isp;
+ struct task_struct *tracer;
int rc;
- rc = cap_bprm_set_creds(bprm);
- if (rc != 0)
- return rc;
-
if (bprm->cred_prepared)
return 0;
@@ -539,7 +528,6 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
return 0;
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
- struct task_struct *tracer;
rc = 0;
rcu_read_lock();
@@ -585,12 +573,11 @@ static void smack_bprm_committing_creds(struct linux_binprm *bprm)
static int smack_bprm_secureexec(struct linux_binprm *bprm)
{
struct task_smack *tsp = current_security();
- int ret = cap_bprm_secureexec(bprm);
- if (!ret && (tsp->smk_task != tsp->smk_forked))
- ret = 1;
+ if (tsp->smk_task != tsp->smk_forked)
+ return 1;
- return ret;
+ return 0;
}
/*
@@ -1703,12 +1690,7 @@ static void smack_task_getsecid(struct task_struct *p, u32 *secid)
*/
static int smack_task_setnice(struct task_struct *p, int nice)
{
- int rc;
-
- rc = cap_task_setnice(p, nice);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1720,12 +1702,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
*/
static int smack_task_setioprio(struct task_struct *p, int ioprio)
{
- int rc;
-
- rc = cap_task_setioprio(p, ioprio);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1749,12 +1726,7 @@ static int smack_task_getioprio(struct task_struct *p)
*/
static int smack_task_setscheduler(struct task_struct *p)
{
- int rc;
-
- rc = cap_task_setscheduler(p);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -3892,7 +3864,6 @@ struct security_operations smack_ops = {
.file_lock = smack_file_lock,
.file_fcntl = smack_file_fcntl,
.mmap_file = smack_mmap_file,
- .mmap_addr = cap_mmap_addr,
.file_set_fowner = smack_file_set_fowner,
.file_send_sigiotask = smack_file_send_sigiotask,
.file_receive = smack_file_receive,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index f0b756e..92d2230 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -72,12 +72,6 @@ static void tomoyo_cred_free(struct cred *cred)
*/
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
- int rc;
-
- rc = cap_bprm_set_creds(bprm);
- if (rc)
- return rc;
-
/*
* Do only if this function is called for the first time of an execve
* operation.
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 13c88fbc..8fa7e30 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -135,7 +135,7 @@ static void yama_ptracer_del(struct task_struct *tracer,
* yama_task_free - check for task_pid to remove from exception list
* @task: task being removed
*/
-void yama_task_free(struct task_struct *task)
+static void yama_task_free(struct task_struct *task)
{
yama_ptracer_del(task, task);
}
@@ -151,16 +151,12 @@ void yama_task_free(struct task_struct *task)
* Return 0 on success, -ve on error. -ENOSYS is returned when Yama
* does not handle the given option.
*/
-int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- int rc;
+ int rc = 0;
struct task_struct *myself = current;
- rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
- if (rc != -ENOSYS)
- return rc;
-
switch (option) {
case PR_SET_PTRACER:
/* Since a thread can call prctl(), find the group leader
@@ -279,18 +275,11 @@ static int ptracer_exception_found(struct task_struct *tracer,
*
* Returns 0 if following the ptrace is allowed, -ve on error.
*/
-int yama_ptrace_access_check(struct task_struct *child,
+static int yama_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
int rc;
- /* If standard caps disallows it, so does Yama. We should
- * only tighten restrictions further.
- */
- rc = cap_ptrace_access_check(child, mode);
- if (rc)
- return rc;
-
/* require ptrace target be a child of ptracer on attach */
if (mode == PTRACE_MODE_ATTACH) {
switch (ptrace_scope) {
@@ -333,16 +322,9 @@ int yama_ptrace_access_check(struct task_struct *child,
*
* Returns 0 if following the ptrace is allowed, -ve on error.
*/
-int yama_ptrace_traceme(struct task_struct *parent)
+static int yama_ptrace_traceme(struct task_struct *parent)
{
- int rc;
-
- /* If standard caps disallows it, so does Yama. We should
- * only tighten restrictions further.
- */
- rc = cap_ptrace_traceme(parent);
- if (rc)
- return rc;
+ int rc = 0;
/* Only disallow PTRACE_TRACEME on more aggressive settings. */
switch (ptrace_scope) {
@@ -364,8 +346,7 @@ int yama_ptrace_traceme(struct task_struct *parent)
return rc;
}
-#ifndef CONFIG_SECURITY_YAMA_STACKED
-static struct security_operations yama_ops = {
+struct security_operations yama_ops = {
.name = "yama",
.ptrace_access_check = yama_ptrace_access_check,
@@ -373,7 +354,6 @@ static struct security_operations yama_ops = {
.task_prctl = yama_task_prctl,
.task_free = yama_task_free,
};
-#endif
#ifdef CONFIG_SYSCTL
static int yama_dointvec_minmax(struct ctl_table *table, int write,
@@ -421,17 +401,17 @@ static struct ctl_table yama_sysctl_table[] = {
static __init int yama_init(void)
{
#ifndef CONFIG_SECURITY_YAMA_STACKED
+ /*
+ * If yama is being stacked this is already taken care of.
+ */
if (!security_module_enable(&yama_ops))
return 0;
-#endif
-
- printk(KERN_INFO "Yama: becoming mindful.\n");
-
-#ifndef CONFIG_SECURITY_YAMA_STACKED
if (register_security(&yama_ops))
panic("Yama: kernel registration failed.\n");
#endif
+ pr_info("Yama: becoming mindful.\n");
+
#ifdef CONFIG_SYSCTL
if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
panic("Yama: sysctl registration failed.\n");
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html