lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2188083.9YNqd7aYQ3@sifl>
Date:	Thu, 07 May 2015 17:05:38 -0400
From:	Paul Moore <pmoore@...hat.com>
To:	Casey Schaufler <casey@...aufler-ca.com>
Cc:	James Morris <jmorris@...ei.org>,
	James Morris <james.l.morris@...cle.com>,
	LSM <linux-security-module@...r.kernel.org>,
	LKLM <linux-kernel@...r.kernel.org>,
	John Johansen <john.johansen@...onical.com>,
	Tetsuo Handa <penguin-kernel@...ove.sakura.ne.jp>,
	Stephen Smalley <sds@...ho.nsa.gov>,
	Eric Paris <eparis@...hat.com>,
	Kees Cook <keescook@...omium.org>
Subject: Re: [PATCH 6/7 v22] LSM: Switch to lists of hooks

On Saturday, May 02, 2015 03:11:42 PM Casey Schaufler wrote:
> Subject: [PATCH 6/7 v22] LSM: Switch to lists of hooks
> 
> Instead of using a vector of security operations
> with explicit, special case stacking of the capability
> and yama hooks use lists of hooks with capability and
> yama hooks included as appropriate.
> 
> The security_operations structure is no longer required.
> Instead, there is a union of the function pointers that
> allows all the hooks lists to use a common mechanism for
> list management while retaining typing. Each module
> supplies an array describing the hooks it provides instead
> of a sparsely populated security_operations structure.
> The description includes the element that gets put on
> the hook list, avoiding the issues surrounding individual
> element allocation.
> 
> The method for registering security modules is changed to
> reflect the information available. The method for removing
> a module, currently only used by SELinux, has also changed.
> It should be generic now, however if there are potential
> race conditions based on ordering of hook removal that needs
> to be addressed by the calling module.
> 
> The security hooks are called from the lists and the first
> failure is returned.
> 
> Signed-off-by: Casey Schaufler <casey@...aufler-ca.com>

Ah, here is the tricky one :)

It all looks very reasonable to me, in the interest of full disclosure I 
didn't verify each and every hook but I know Stephen did previously so I trust 
it - Stephen's much smarter about these things than I am anyway ;).

Acked-by: Paul Moore <paul@...l-moore.com>

> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index bbbf6fe..f014f25 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -25,21 +25,10 @@
>  #define __LINUX_LSM_HOOKS_H
> 
>  #include <linux/security.h>
> -
> -/* Maximum number of letters for an LSM name string */
> -#define SECURITY_NAME_MAX	10
> -
> -#ifdef CONFIG_SECURITY
> +#include <linux/init.h>
> +#include <linux/rculist.h>
> 
>  /**
> - * struct security_operations - main security structure
> - *
> - * Security module identifier.
> - *
> - * @name:
> - *	A string that acts as a unique identifier for the LSM with max number
> - *	of characters = SECURITY_NAME_MAX.
> - *
>   * Security hooks for program execution operations.
>   *
>   * @bprm_set_creds:
> @@ -1310,9 +1299,7 @@
>   * This is the main security structure.
>   */
> 
> -struct security_operations {
> -	char name[SECURITY_NAME_MAX + 1];
> -
> +union security_list_options {
>  	int (*binder_set_context_mgr)(struct task_struct *mgr);
>  	int (*binder_transaction)(struct task_struct *from,
>  					struct task_struct *to);
> @@ -1838,21 +1825,62 @@ struct security_hook_heads {
>  };
> 
>  /*
> + * Security module hook list structure.
> + * For use with generic list macros for common operations.
> + */
> +struct security_hook_list {
> +	struct list_head		list;
> +	struct list_head		*head;
> +	union security_list_options	hook;
> +};
> +
> +/*
>   * Initializing a security_hook_list structure takes
>   * up a lot of space in a source file. This macro takes
>   * care of the common case and reduces the amount of
>   * text involved.
> - * Casey says: Comment is true in the next patch.
>   */
> -#define LSM_HOOK_INIT(HEAD, HOOK)	.HEAD = HOOK
> +#define LSM_HOOK_INIT(HEAD, HOOK) \
> +	{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
> 
> -/* prototypes */
> -extern int security_module_enable(struct security_operations *ops);
> -extern int register_security(struct security_operations *ops);
> -extern void __init security_fixup_ops(struct security_operations *ops);
> -extern void reset_security_ops(void);
> +extern struct security_hook_heads security_hook_heads;
> 
> -#endif /* CONFIG_SECURITY */
> +static inline void security_add_hooks(struct security_hook_list *hooks,
> +				      int count)
> +{
> +	int i;
> 
> -#endif /* ! __LINUX_LSM_HOOKS_H */
> +	for (i = 0; i < count; i++)
> +		list_add_tail_rcu(&hooks[i].list, hooks[i].head);
> +}
> +
> +#ifdef CONFIG_SECURITY_SELINUX_DISABLE
> +/*
> + * Assuring the safety of deleting a security module is up to
> + * the security module involved. This may entail ordering the
> + * module's hook list in a particular way, refusing to disable
> + * the module once a policy is loaded or any number of other
> + * actions better imagined than described.
> + *
> + * The name of the configuration option reflects the only module
> + * that currently uses the mechanism. Any developer who thinks
> + * disabling their module is a good idea needs to be at least as
> + * careful as the SELinux team.
> + */
> +static inline void security_delete_hooks(struct security_hook_list *hooks,
> +						int count)
> +{
> +	int i;
> 
> +	for (i = 0; i < count; i++)
> +		list_del_rcu(&hooks[i].list);
> +}
> +#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
> +
> +extern int __init security_module_enable(const char *module);
> +extern void __init capability_add_hooks(void);
> +#ifdef CONFIG_SECURITY_YAMA_STACKED
> +void __init yama_add_hooks(void);
> +#endif
> +
> +#endif /* ! __LINUX_LSM_HOOKS_H */
> diff --git a/include/linux/security.h b/include/linux/security.h
> index a2a100e..8c8175d 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -27,6 +27,7 @@
>  #include <linux/slab.h>
>  #include <linux/err.h>
>  #include <linux/string.h>
> +#include <linux/mm.h>
> 
>  struct linux_binprm;
>  struct cred;
> @@ -54,9 +55,6 @@ struct xattr;
>  struct xfrm_sec_ctx;
>  struct mm_struct;
> 
> -/* Maximum number of letters for an LSM name string */
> -#define SECURITY_NAME_MAX	10
> -
>  /* If capable should audit the security request */
>  #define SECURITY_CAP_NOAUDIT 0
>  #define SECURITY_CAP_AUDIT 1
> @@ -69,10 +67,7 @@ struct audit_krule;
>  struct user_namespace;
>  struct timezone;
> 
> -/*
> - * These functions are in security/capability.c and are used
> - * as the default capabilities functions
> - */
> +/* These functions are in security/commoncap.c */
>  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
>  		       int cap, int audit);
>  extern int cap_settime(const struct timespec *ts, const struct timezone
> *tz); @@ -114,8 +109,6 @@ struct xfrm_state;
>  struct xfrm_user_sec_ctx;
>  struct seq_file;
> 
> -extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
> -
>  #ifdef CONFIG_MMU
>  extern unsigned long mmap_min_addr;
>  extern unsigned long dac_mmap_min_addr;
> @@ -472,7 +465,7 @@ static inline int security_settime(const struct timespec
> *ts,
> 
>  static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long
> pages) {
> -	return cap_vm_enough_memory(mm, pages);
> +	return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages));
>  }
> 
>  static inline int security_bprm_set_creds(struct linux_binprm *bprm)
> @@ -1075,7 +1068,7 @@ static inline int security_setprocattr(struct
> task_struct *p, char *name, void *
> 
>  static inline int security_netlink_send(struct sock *sk, struct sk_buff
> *skb) {
> -	return cap_netlink_send(sk, skb);
> +	return 0;
>  }
> 
>  static inline int security_ismaclabel(const char *name)
> @@ -1643,36 +1636,5 @@ 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 */
> -
>  #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..dc0027b 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;
> @@ -531,15 +529,13 @@ cleanup:
>   */
>  int apparmor_bprm_secureexec(struct linux_binprm *bprm)
>  {
> -	int ret = cap_bprm_secureexec(bprm);
> -
>  	/* the decision to use secure exec is computed in set_creds
>  	 * and stored in bprm->unsafe.
>  	 */
> -	if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
> -		ret = 1;
> +	if (bprm->unsafe & AA_SECURE_X_NEEDED)
> +		return 1;
> 
> -	return ret;
> +	return 0;
>  }
> 
>  /**
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index f542532..5696874 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);
>  }
> 
> @@ -123,10 +115,10 @@ static int apparmor_capget(struct task_struct *target,
> kernel_cap_t *effective, cred = __task_cred(target);
>  	profile = aa_cred_profile(cred);
> 
> -	*effective = cred->cap_effective;
> -	*inheritable = cred->cap_inheritable;
> -	*permitted = cred->cap_permitted;
> -
> +	/*
> +	 * cap_capget is stacked ahead of this and will
> +	 * initialize effective and permitted.
> +	 */
>  	if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
>  		*effective = cap_intersect(*effective, profile->caps.allow);
>  		*permitted = cap_intersect(*permitted, profile->caps.allow);
> @@ -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;
>  }
> 
> @@ -615,9 +605,7 @@ static int apparmor_task_setrlimit(struct task_struct
> *task, return error;
>  }
> 
> -static struct security_operations apparmor_ops = {
> -	LSM_HOOK_INIT(name, "apparmor"),
> -
> +static struct security_hook_list apparmor_hooks[] = {
>  	LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
>  	LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
>  	LSM_HOOK_INIT(capget, apparmor_capget),
> @@ -640,7 +628,6 @@ static struct security_operations apparmor_ops = {
>  	LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security),
>  	LSM_HOOK_INIT(file_free_security, apparmor_file_free_security),
>  	LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
> -	LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
>  	LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
>  	LSM_HOOK_INIT(file_lock, apparmor_file_lock),
> 
> @@ -898,7 +885,7 @@ static int __init apparmor_init(void)
>  {
>  	int error;
> 
> -	if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
> +	if (!apparmor_enabled || !security_module_enable("apparmor")) {
>  		aa_info_message("AppArmor disabled by boot time parameter");
>  		apparmor_enabled = 0;
>  		return 0;
> @@ -913,17 +900,10 @@ static int __init apparmor_init(void)
>  	error = set_init_cxt();
>  	if (error) {
>  		AA_ERROR("Failed to set context on init task\n");
> -		goto register_security_out;
> -	}
> -
> -	error = register_security(&apparmor_ops);
> -	if (error) {
> -		struct cred *cred = (struct cred *)current->real_cred;
> -		aa_free_task_context(cred_cxt(cred));
> -		cred_cxt(cred) = NULL;
> -		AA_ERROR("Unable to register AppArmor\n");
> -		goto register_security_out;
> +		aa_free_root_ns();
> +		goto alloc_out;
>  	}
> +	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
> 
>  	/* Report that AppArmor successfully initialized */
>  	apparmor_initialized = 1;
> @@ -936,9 +916,6 @@ static int __init apparmor_init(void)
> 
>  	return error;
> 
> -register_security_out:
> -	aa_free_root_ns();
> -
>  alloc_out:
>  	aa_destroy_aafs();
> 
> diff --git a/security/commoncap.c b/security/commoncap.c
> index f2875cd..d103f5a4 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -12,7 +12,7 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> -#include <linux/security.h>
> +#include <linux/lsm_hooks.h>
>  #include <linux/file.h>
>  #include <linux/mm.h>
>  #include <linux/mman.h>
> @@ -53,11 +53,6 @@ static void warn_setuid_and_fcaps_mixed(const char
> *fname) }
>  }
> 
> -int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
> -{
> -	return 0;
> -}
> -
>  /**
>   * cap_capable - Determine whether a task has a particular effective
> capability * @cred: The credentials to use
> @@ -941,7 +936,7 @@ int cap_task_prctl(int option, unsigned long arg2,
> unsigned long arg3, * @pages: The size of the mapping
>   *
>   * Determine whether the allocation of a new virtual mapping by the current
> - * task is permitted, returning 0 if permission is granted, -ve if not. +
> * task is permitted, returning 1 if permission is granted, 0 if not. */
>  int cap_vm_enough_memory(struct mm_struct *mm, long pages)
>  {
> @@ -950,7 +945,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;
>  }
> 
>  /*
> @@ -981,3 +976,33 @@ int cap_mmap_file(struct file *file, unsigned long
> reqprot, {
>  	return 0;
>  }
> +
> +#ifdef CONFIG_SECURITY
> +
> +struct security_hook_list capability_hooks[] = {
> +	LSM_HOOK_INIT(capable, cap_capable),
> +	LSM_HOOK_INIT(settime, cap_settime),
> +	LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
> +	LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme),
> +	LSM_HOOK_INIT(capget, cap_capget),
> +	LSM_HOOK_INIT(capset, cap_capset),
> +	LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds),
> +	LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec),
> +	LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv),
> +	LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv),
> +	LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
> +	LSM_HOOK_INIT(mmap_file, cap_mmap_file),
> +	LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid),
> +	LSM_HOOK_INIT(task_prctl, cap_task_prctl),
> +	LSM_HOOK_INIT(task_setscheduler, cap_task_setscheduler),
> +	LSM_HOOK_INIT(task_setioprio, cap_task_setioprio),
> +	LSM_HOOK_INIT(task_setnice, cap_task_setnice),
> +	LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
> +};
> +
> +void __init capability_add_hooks(void)
> +{
> +	security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks));
> +}
> +
> +#endif /* CONFIG_SECURITY */
> diff --git a/security/security.c b/security/security.c
> index 02dc720..bd4c5f6 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -29,24 +29,13 @@
> 
>  #define MAX_LSM_EVM_XATTR	2
> 
> +/* Maximum number of letters for an LSM name string */
> +#define SECURITY_NAME_MAX	10
> +
>  /* 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;
> @@ -64,20 +53,27 @@ static void __init do_security_initcalls(void)
>   */
>  int __init security_init(void)
>  {
> -	printk(KERN_INFO "Security Framework initialized\n");
> +	pr_info("Security Framework initialized\n");
> 
> -	security_fixup_ops(&default_security_ops);
> -	security_ops = &default_security_ops;
> +	/*
> +	 * Always load the capability module.
> +	 */
> +	capability_add_hooks();
> +#ifdef CONFIG_SECURITY_YAMA_STACKED
> +	/*
> +	 * If Yama is configured for stacking load it next.
> +	 */
> +	yama_add_hooks();
> +#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)
>  {
> @@ -88,7 +84,7 @@ __setup("security=", choose_lsm);
> 
>  /**
>   * security_module_enable - Load given security module on boot ?
> - * @ops: a pointer to the struct security_operations that is to be checked.
> + * @module: the name of the module
>   *
>   * Each LSM must pass this method before registering its own operations
>   * to avoid security registration races. This method may also be used
> @@ -100,41 +96,13 @@ __setup("security=", choose_lsm);
>   *	 choose an alternate LSM at boot time.
>   * Otherwise, return false.
>   */
> -int __init security_module_enable(struct security_operations *ops)
> +int __init security_module_enable(const char *module)
>  {
> -	return !strcmp(ops->name, chosen_lsm);
> -}
> -
> -/**
> - * register_security - registers a security framework with the kernel
> - * @ops: a pointer to the struct security_options that is to be registered
> - *
> - * This function allows a security module to register itself with the
> - * kernel security subsystem.  Some rudimentary checking is done on the
> @ops - * value passed to this function. You'll need to check first if your
> LSM - * is allowed to register its @ops by calling
> security_module_enable(@ops). - *
> - * If there is already a security module registered with the kernel,
> - * an error will be returned.  Otherwise %0 is returned on success.
> - */
> -int __init register_security(struct security_operations *ops)
> -{
> -	if (verify(ops)) {
> -		printk(KERN_DEBUG "%s could not verify "
> -		       "security_operations structure.\n", __func__);
> -		return -EINVAL;
> -	}
> -
> -	if (security_ops != &default_security_ops)
> -		return -EAGAIN;
> -
> -	security_ops = ops;
> -
> -	return 0;
> +	return !strcmp(module, chosen_lsm);
>  }
> 
>  /*
> - * Hook operation macros.
> + * Hook list operation macros.
>   *
>   * call_void_hook:
>   *	This is a hook that does not return a value.
> @@ -143,8 +111,27 @@ int __init register_security(struct security_operations
> *ops) *	This is a hook that returns a value.
>   */
> 
> -#define call_void_hook(FUNC, ...)	security_ops->FUNC(__VA_ARGS__)
> -#define call_int_hook(FUNC, IRC, ...)	security_ops->FUNC(__VA_ARGS__)
> +#define call_void_hook(FUNC, ...)				\
> +	do {							\
> +		struct security_hook_list *P;			\
> +								\
> +		list_for_each_entry(P, &security_hook_heads.FUNC, list)	\
> +			P->hook.FUNC(__VA_ARGS__);		\
> +	} while (0)
> +
> +#define call_int_hook(FUNC, IRC, ...) ({			\
> +	int RC = IRC;						\
> +	do {							\
> +		struct security_hook_list *P;			\
> +								\
> +		list_for_each_entry(P, &security_hook_heads.FUNC, list) { \
> +			RC = P->hook.FUNC(__VA_ARGS__);		\
> +			if (RC != 0)				\
> +				break;				\
> +		}						\
> +	} while (0);						\
> +	RC;							\
> +})
> 
>  /* Security operations */
> 
> @@ -173,23 +160,11 @@ int security_binder_transfer_file(struct task_struct
> *from,
> 
>  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, 0, child, mode);
>  }
> 
>  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, 0, parent);
>  }
> 
> @@ -245,7 +220,25 @@ int security_settime(const struct timespec *ts, const
> struct timezone *tz)
> 
>  int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
>  {
> -	return call_int_hook(vm_enough_memory, 0, mm, pages);
> +	struct security_hook_list *hp;
> +	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(hp, &security_hook_heads.vm_enough_memory, list) {
> +		rc = hp->hook.vm_enough_memory(mm, pages);
> +		if (rc <= 0) {
> +			cap_sys_admin = 0;
> +			break;
> +		}
> +	}
> +	return __vm_enough_memory(mm, pages, cap_sys_admin);
>  }
> 
>  int security_bprm_set_creds(struct linux_binprm *bprm)
> @@ -335,8 +328,9 @@ int security_sb_set_mnt_opts(struct super_block *sb,
>  				unsigned long kern_flags,
>  				unsigned long *set_kern_flags)
>  {
> -	return call_int_hook(sb_set_mnt_opts, 0, sb, opts, kern_flags,
> -						set_kern_flags);
> +	return call_int_hook(sb_set_mnt_opts,
> +				opts->num_mnt_opts ? -EOPNOTSUPP : 0, sb,
> +				opts, kern_flags, set_kern_flags);
>  }
>  EXPORT_SYMBOL(security_sb_set_mnt_opts);
> 
> @@ -369,8 +363,8 @@ int security_dentry_init_security(struct dentry *dentry,
> int mode, struct qstr *name, void **ctx,
>  					u32 *ctxlen)
>  {
> -	return call_int_hook(dentry_init_security, 0, dentry, mode, name,
> -							ctx, ctxlen);
> +	return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
> +				name, ctx, ctxlen);
>  }
>  EXPORT_SYMBOL(security_dentry_init_security);
> 
> @@ -390,7 +384,7 @@ int security_inode_init_security(struct inode *inode,
> struct inode *dir, NULL, NULL, NULL);
>  	memset(new_xattrs, 0, sizeof(new_xattrs));
>  	lsm_xattr = new_xattrs;
> -	ret = call_int_hook(inode_init_security, 0, inode, dir, qstr,
> +	ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr,
>  						&lsm_xattr->name,
>  						&lsm_xattr->value,
>  						&lsm_xattr->value_len);
> @@ -636,8 +630,15 @@ int security_inode_setxattr(struct dentry *dentry,
> const char *name,
> 
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
> -	ret = call_int_hook(inode_setxattr, 0, dentry, name, value, size,
> +	/*
> +	 * SELinux and Smack integrate the cap call,
> +	 * so assume that all LSMs supplying this call do so.
> +	 */
> +	ret = call_int_hook(inode_setxattr, 1, dentry, name, value, size,
>  				flags);
> +
> +	if (ret == 1)
> +		ret = cap_inode_setxattr(dentry, name, value, size, flags);
>  	if (ret)
>  		return ret;
>  	ret = ima_inode_setxattr(dentry, name, value, size);
> @@ -675,7 +676,13 @@ int security_inode_removexattr(struct dentry *dentry,
> const char *name)
> 
>  	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>  		return 0;
> -	ret = call_int_hook(inode_removexattr, 0, dentry, name);
> +	/*
> +	 * SELinux and Smack integrate the cap call,
> +	 * so assume that all LSMs supplying this call do so.
> +	 */
> +	ret = call_int_hook(inode_removexattr, 1, dentry, name);
> +	if (ret == 1)
> +		ret = cap_inode_removexattr(dentry, name);
>  	if (ret)
>  		return ret;
>  	ret = ima_inode_removexattr(dentry, name);
> @@ -698,15 +705,16 @@ int security_inode_getsecurity(const struct inode
> *inode, const char *name, void {
>  	if (unlikely(IS_PRIVATE(inode)))
>  		return -EOPNOTSUPP;
> -	return call_int_hook(inode_getsecurity, 0, inode, name, buffer, alloc);
> +	return call_int_hook(inode_getsecurity, -EOPNOTSUPP, inode, name,
> +				buffer, alloc);
>  }
> 
>  int security_inode_setsecurity(struct inode *inode, const char *name, const
> void *value, size_t size, int flags) {
>  	if (unlikely(IS_PRIVATE(inode)))
>  		return -EOPNOTSUPP;
> -	return call_int_hook(inode_setsecurity, 0, inode, name, value, size,
> -				flags);
> +	return call_int_hook(inode_setsecurity, -EOPNOTSUPP, inode, name,
> +				value, size, flags);
>  }
> 
>  int security_inode_listsecurity(struct inode *inode, char *buffer, size_t
> buffer_size) @@ -847,9 +855,6 @@ int security_task_create(unsigned long
> clone_flags)
> 
>  void security_task_free(struct task_struct *task)
>  {
> -#ifdef CONFIG_SECURITY_YAMA_STACKED
> -	yama_task_free(task);
> -#endif
>  	call_void_hook(task_free, task);
>  }
> 
> @@ -932,6 +937,7 @@ int security_task_getsid(struct task_struct *p)
> 
>  void security_task_getsecid(struct task_struct *p, u32 *secid)
>  {
> +	*secid = 0;
>  	call_void_hook(task_getsecid, p, secid);
>  }
>  EXPORT_SYMBOL(security_task_getsecid);
> @@ -986,13 +992,19 @@ int security_task_wait(struct task_struct *p)
>  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, 0, option, arg2, arg3, arg4, arg5);
> +	int thisrc;
> +	int rc = -ENOSYS;
> +	struct security_hook_list *hp;
> +
> +	list_for_each_entry(hp, &security_hook_heads.task_prctl, list) {
> +		thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5);
> +		if (thisrc != -ENOSYS) {
> +			rc = thisrc;
> +			if (thisrc != 0)
> +				break;
> +		}
> +	}
> +	return rc;
>  }
> 
>  void security_task_to_inode(struct task_struct *p, struct inode *inode)
> @@ -1007,6 +1019,7 @@ int security_ipc_permission(struct kern_ipc_perm
> *ipcp, short flag)
> 
>  void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
>  {
> +	*secid = 0;
>  	call_void_hook(ipc_getsecid, ipcp, secid);
>  }
> 
> @@ -1113,12 +1126,12 @@ EXPORT_SYMBOL(security_d_instantiate);
> 
>  int security_getprocattr(struct task_struct *p, char *name, char **value)
>  {
> -	return call_int_hook(getprocattr, 0, p, name, value);
> +	return call_int_hook(getprocattr, -EINVAL, p, name, value);
>  }
> 
>  int security_setprocattr(struct task_struct *p, char *name, void *value,
> size_t size) {
> -	return call_int_hook(setprocattr, 0, p, name, value, size);
> +	return call_int_hook(setprocattr, -EINVAL, p, name, value, size);
>  }
> 
>  int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> @@ -1134,12 +1147,14 @@ EXPORT_SYMBOL(security_ismaclabel);
> 
>  int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>  {
> -	return call_int_hook(secid_to_secctx, 0, secid, secdata, seclen);
> +	return call_int_hook(secid_to_secctx, -EOPNOTSUPP, secid, secdata,
> +				seclen);
>  }
>  EXPORT_SYMBOL(security_secid_to_secctx);
> 
>  int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
>  {
> +	*secid = 0;
>  	return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid);
>  }
>  EXPORT_SYMBOL(security_secctx_to_secid);
> @@ -1164,7 +1179,7 @@ EXPORT_SYMBOL(security_inode_setsecctx);
> 
>  int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
>  {
> -	return call_int_hook(inode_getsecctx, 0, inode, ctx, ctxlen);
> +	return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
>  }
>  EXPORT_SYMBOL(security_inode_getsecctx);
> 
> @@ -1259,8 +1274,8 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
>  int security_socket_getpeersec_stream(struct socket *sock, char __user
> *optval, int __user *optlen, unsigned len)
>  {
> -	return call_int_hook(socket_getpeersec_stream, 0, sock, optval,
> -				optlen, len);
> +	return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
> +				optval, optlen, len);
>  }
> 
>  int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff
> *skb, u32 *secid) @@ -1438,7 +1453,24 @@ int
> security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy
> *xp,
>  				       const struct flowi *fl)
>  {
> -	return call_int_hook(xfrm_state_pol_flow_match, 0, x, xp, fl);
> +	struct security_hook_list *hp;
> +	int rc = 1;
> +
> +	/*
> +	 * Since this function is expected to return 0 or 1, the judgment
> +	 * becomes difficult if multiple LSMs supply this call. Fortunately,
> +	 * we can use the first LSM's judgment because currently only SELinux
> +	 * supplies this call.
> +	 *
> +	 * For speed optimization, we explicitly break the loop rather than
> +	 * using the macro
> +	 */
> +	list_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match,
> +				list) {
> +		rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
> +		break;
> +	}
> +	return rc;
>  }
> 
>  int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
> @@ -1478,6 +1510,7 @@ int security_key_permission(key_ref_t key_ref,
> 
>  int security_key_getsecurity(struct key *key, char **_buffer)
>  {
> +	*_buffer = NULL;
>  	return call_int_hook(key_getsecurity, 0, key, _buffer);
>  }
> 
> @@ -1506,5 +1539,350 @@ int security_audit_rule_match(u32 secid, u32 field,
> u32 op, void *lsmrule, return call_int_hook(audit_rule_match, 0, secid,
> field, op, lsmrule, actx);
>  }
> +#endif /* CONFIG_AUDIT */
> 
> +struct security_hook_heads security_hook_heads = {
> +	.binder_set_context_mgr =
> +		LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
> +	.binder_transaction =
> +		LIST_HEAD_INIT(security_hook_heads.binder_transaction),
> +	.binder_transfer_binder =
> +		LIST_HEAD_INIT(security_hook_heads.binder_transfer_binder),
> +	.binder_transfer_file =
> +		LIST_HEAD_INIT(security_hook_heads.binder_transfer_file),
> +
> +	.ptrace_access_check =
> +		LIST_HEAD_INIT(security_hook_heads.ptrace_access_check),
> +	.ptrace_traceme =
> +		LIST_HEAD_INIT(security_hook_heads.ptrace_traceme),
> +	.capget =	LIST_HEAD_INIT(security_hook_heads.capget),
> +	.capset =	LIST_HEAD_INIT(security_hook_heads.capset),
> +	.capable =	LIST_HEAD_INIT(security_hook_heads.capable),
> +	.quotactl =	LIST_HEAD_INIT(security_hook_heads.quotactl),
> +	.quota_on =	LIST_HEAD_INIT(security_hook_heads.quota_on),
> +	.syslog =	LIST_HEAD_INIT(security_hook_heads.syslog),
> +	.settime =	LIST_HEAD_INIT(security_hook_heads.settime),
> +	.vm_enough_memory =
> +		LIST_HEAD_INIT(security_hook_heads.vm_enough_memory),
> +	.bprm_set_creds =
> +		LIST_HEAD_INIT(security_hook_heads.bprm_set_creds),
> +	.bprm_check_security =
> +		LIST_HEAD_INIT(security_hook_heads.bprm_check_security),
> +	.bprm_secureexec =
> +		LIST_HEAD_INIT(security_hook_heads.bprm_secureexec),
> +	.bprm_committing_creds =
> +		LIST_HEAD_INIT(security_hook_heads.bprm_committing_creds),
> +	.bprm_committed_creds =
> +		LIST_HEAD_INIT(security_hook_heads.bprm_committed_creds),
> +	.sb_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.sb_alloc_security),
> +	.sb_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.sb_free_security),
> +	.sb_copy_data =	LIST_HEAD_INIT(security_hook_heads.sb_copy_data),
> +	.sb_remount =	LIST_HEAD_INIT(security_hook_heads.sb_remount),
> +	.sb_kern_mount =
> +		LIST_HEAD_INIT(security_hook_heads.sb_kern_mount),
> +	.sb_show_options =
> +		LIST_HEAD_INIT(security_hook_heads.sb_show_options),
> +	.sb_statfs =	LIST_HEAD_INIT(security_hook_heads.sb_statfs),
> +	.sb_mount =	LIST_HEAD_INIT(security_hook_heads.sb_mount),
> +	.sb_umount =	LIST_HEAD_INIT(security_hook_heads.sb_umount),
> +	.sb_pivotroot =	LIST_HEAD_INIT(security_hook_heads.sb_pivotroot),
> +	.sb_set_mnt_opts =
> +		LIST_HEAD_INIT(security_hook_heads.sb_set_mnt_opts),
> +	.sb_clone_mnt_opts =
> +		LIST_HEAD_INIT(security_hook_heads.sb_clone_mnt_opts),
> +	.sb_parse_opts_str =
> +		LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str),
> +	.dentry_init_security =
> +		LIST_HEAD_INIT(security_hook_heads.dentry_init_security),
> +#ifdef CONFIG_SECURITY_PATH
> +	.path_unlink =	LIST_HEAD_INIT(security_hook_heads.path_unlink),
> +	.path_mkdir =	LIST_HEAD_INIT(security_hook_heads.path_mkdir),
> +	.path_rmdir =	LIST_HEAD_INIT(security_hook_heads.path_rmdir),
> +	.path_mknod =	LIST_HEAD_INIT(security_hook_heads.path_mknod),
> +	.path_truncate =
> +		LIST_HEAD_INIT(security_hook_heads.path_truncate),
> +	.path_symlink =	LIST_HEAD_INIT(security_hook_heads.path_symlink),
> +	.path_link =	LIST_HEAD_INIT(security_hook_heads.path_link),
> +	.path_rename =	LIST_HEAD_INIT(security_hook_heads.path_rename),
> +	.path_chmod =	LIST_HEAD_INIT(security_hook_heads.path_chmod),
> +	.path_chown =	LIST_HEAD_INIT(security_hook_heads.path_chown),
> +	.path_chroot =	LIST_HEAD_INIT(security_hook_heads.path_chroot),
> +#endif
> +	.inode_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.inode_alloc_security),
> +	.inode_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.inode_free_security),
> +	.inode_init_security =
> +		LIST_HEAD_INIT(security_hook_heads.inode_init_security),
> +	.inode_create =	LIST_HEAD_INIT(security_hook_heads.inode_create),
> +	.inode_link =	LIST_HEAD_INIT(security_hook_heads.inode_link),
> +	.inode_unlink =	LIST_HEAD_INIT(security_hook_heads.inode_unlink),
> +	.inode_symlink =
> +		LIST_HEAD_INIT(security_hook_heads.inode_symlink),
> +	.inode_mkdir =	LIST_HEAD_INIT(security_hook_heads.inode_mkdir),
> +	.inode_rmdir =	LIST_HEAD_INIT(security_hook_heads.inode_rmdir),
> +	.inode_mknod =	LIST_HEAD_INIT(security_hook_heads.inode_mknod),
> +	.inode_rename =	LIST_HEAD_INIT(security_hook_heads.inode_rename),
> +	.inode_readlink =
> +		LIST_HEAD_INIT(security_hook_heads.inode_readlink),
> +	.inode_follow_link =
> +		LIST_HEAD_INIT(security_hook_heads.inode_follow_link),
> +	.inode_permission =
> +		LIST_HEAD_INIT(security_hook_heads.inode_permission),
> +	.inode_setattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_setattr),
> +	.inode_getattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_getattr),
> +	.inode_setxattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_setxattr),
> +	.inode_post_setxattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_post_setxattr),
> +	.inode_getxattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_getxattr),
> +	.inode_listxattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_listxattr),
> +	.inode_removexattr =
> +		LIST_HEAD_INIT(security_hook_heads.inode_removexattr),
> +	.inode_need_killpriv =
> +		LIST_HEAD_INIT(security_hook_heads.inode_need_killpriv),
> +	.inode_killpriv =
> +		LIST_HEAD_INIT(security_hook_heads.inode_killpriv),
> +	.inode_getsecurity =
> +		LIST_HEAD_INIT(security_hook_heads.inode_getsecurity),
> +	.inode_setsecurity =
> +		LIST_HEAD_INIT(security_hook_heads.inode_setsecurity),
> +	.inode_listsecurity =
> +		LIST_HEAD_INIT(security_hook_heads.inode_listsecurity),
> +	.inode_getsecid =
> +		LIST_HEAD_INIT(security_hook_heads.inode_getsecid),
> +	.file_permission =
> +		LIST_HEAD_INIT(security_hook_heads.file_permission),
> +	.file_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.file_alloc_security),
> +	.file_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.file_free_security),
> +	.file_ioctl =	LIST_HEAD_INIT(security_hook_heads.file_ioctl),
> +	.mmap_addr =	LIST_HEAD_INIT(security_hook_heads.mmap_addr),
> +	.mmap_file =	LIST_HEAD_INIT(security_hook_heads.mmap_file),
> +	.file_mprotect =
> +		LIST_HEAD_INIT(security_hook_heads.file_mprotect),
> +	.file_lock =	LIST_HEAD_INIT(security_hook_heads.file_lock),
> +	.file_fcntl =	LIST_HEAD_INIT(security_hook_heads.file_fcntl),
> +	.file_set_fowner =
> +		LIST_HEAD_INIT(security_hook_heads.file_set_fowner),
> +	.file_send_sigiotask =
> +		LIST_HEAD_INIT(security_hook_heads.file_send_sigiotask),
> +	.file_receive =	LIST_HEAD_INIT(security_hook_heads.file_receive),
> +	.file_open =	LIST_HEAD_INIT(security_hook_heads.file_open),
> +	.task_create =	LIST_HEAD_INIT(security_hook_heads.task_create),
> +	.task_free =	LIST_HEAD_INIT(security_hook_heads.task_free),
> +	.cred_alloc_blank =
> +		LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
> +	.cred_free =	LIST_HEAD_INIT(security_hook_heads.cred_free),
> +	.cred_prepare =	LIST_HEAD_INIT(security_hook_heads.cred_prepare),
> +	.cred_transfer =
> +		LIST_HEAD_INIT(security_hook_heads.cred_transfer),
> +	.kernel_act_as =
> +		LIST_HEAD_INIT(security_hook_heads.kernel_act_as),
> +	.kernel_create_files_as =
> +		LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as),
> +	.kernel_fw_from_file =
> +		LIST_HEAD_INIT(security_hook_heads.kernel_fw_from_file),
> +	.kernel_module_request =
> +		LIST_HEAD_INIT(security_hook_heads.kernel_module_request),
> +	.kernel_module_from_file =
> +		LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file),
> +	.task_fix_setuid =
> +		LIST_HEAD_INIT(security_hook_heads.task_fix_setuid),
> +	.task_setpgid =	LIST_HEAD_INIT(security_hook_heads.task_setpgid),
> +	.task_getpgid =	LIST_HEAD_INIT(security_hook_heads.task_getpgid),
> +	.task_getsid =	LIST_HEAD_INIT(security_hook_heads.task_getsid),
> +	.task_getsecid =
> +		LIST_HEAD_INIT(security_hook_heads.task_getsecid),
> +	.task_setnice =	LIST_HEAD_INIT(security_hook_heads.task_setnice),
> +	.task_setioprio =
> +		LIST_HEAD_INIT(security_hook_heads.task_setioprio),
> +	.task_getioprio =
> +		LIST_HEAD_INIT(security_hook_heads.task_getioprio),
> +	.task_setrlimit =
> +		LIST_HEAD_INIT(security_hook_heads.task_setrlimit),
> +	.task_setscheduler =
> +		LIST_HEAD_INIT(security_hook_heads.task_setscheduler),
> +	.task_getscheduler =
> +		LIST_HEAD_INIT(security_hook_heads.task_getscheduler),
> +	.task_movememory =
> +		LIST_HEAD_INIT(security_hook_heads.task_movememory),
> +	.task_kill =	LIST_HEAD_INIT(security_hook_heads.task_kill),
> +	.task_wait =	LIST_HEAD_INIT(security_hook_heads.task_wait),
> +	.task_prctl =	LIST_HEAD_INIT(security_hook_heads.task_prctl),
> +	.task_to_inode =
> +		LIST_HEAD_INIT(security_hook_heads.task_to_inode),
> +	.ipc_permission =
> +		LIST_HEAD_INIT(security_hook_heads.ipc_permission),
> +	.ipc_getsecid =	LIST_HEAD_INIT(security_hook_heads.ipc_getsecid),
> +	.msg_msg_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.msg_msg_alloc_security),
> +	.msg_msg_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.msg_msg_free_security),
> +	.msg_queue_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_alloc_security),
> +	.msg_queue_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_free_security),
> +	.msg_queue_associate =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_associate),
> +	.msg_queue_msgctl =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_msgctl),
> +	.msg_queue_msgsnd =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_msgsnd),
> +	.msg_queue_msgrcv =
> +		LIST_HEAD_INIT(security_hook_heads.msg_queue_msgrcv),
> +	.shm_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.shm_alloc_security),
> +	.shm_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.shm_free_security),
> +	.shm_associate =
> +		LIST_HEAD_INIT(security_hook_heads.shm_associate),
> +	.shm_shmctl =	LIST_HEAD_INIT(security_hook_heads.shm_shmctl),
> +	.shm_shmat =	LIST_HEAD_INIT(security_hook_heads.shm_shmat),
> +	.sem_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.sem_alloc_security),
> +	.sem_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.sem_free_security),
> +	.sem_associate =
> +		LIST_HEAD_INIT(security_hook_heads.sem_associate),
> +	.sem_semctl =	LIST_HEAD_INIT(security_hook_heads.sem_semctl),
> +	.sem_semop =	LIST_HEAD_INIT(security_hook_heads.sem_semop),
> +	.netlink_send =	LIST_HEAD_INIT(security_hook_heads.netlink_send),
> +	.d_instantiate =
> +		LIST_HEAD_INIT(security_hook_heads.d_instantiate),
> +	.getprocattr =	LIST_HEAD_INIT(security_hook_heads.getprocattr),
> +	.setprocattr =	LIST_HEAD_INIT(security_hook_heads.setprocattr),
> +	.ismaclabel =	LIST_HEAD_INIT(security_hook_heads.ismaclabel),
> +	.secid_to_secctx =
> +		LIST_HEAD_INIT(security_hook_heads.secid_to_secctx),
> +	.secctx_to_secid =
> +		LIST_HEAD_INIT(security_hook_heads.secctx_to_secid),
> +	.release_secctx =
> +		LIST_HEAD_INIT(security_hook_heads.release_secctx),
> +	.inode_notifysecctx =
> +		LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx),
> +	.inode_setsecctx =
> +		LIST_HEAD_INIT(security_hook_heads.inode_setsecctx),
> +	.inode_getsecctx =
> +		LIST_HEAD_INIT(security_hook_heads.inode_getsecctx),
> +#ifdef CONFIG_SECURITY_NETWORK
> +	.unix_stream_connect =
> +		LIST_HEAD_INIT(security_hook_heads.unix_stream_connect),
> +	.unix_may_send =
> +		LIST_HEAD_INIT(security_hook_heads.unix_may_send),
> +	.socket_create =
> +		LIST_HEAD_INIT(security_hook_heads.socket_create),
> +	.socket_post_create =
> +		LIST_HEAD_INIT(security_hook_heads.socket_post_create),
> +	.socket_bind =	LIST_HEAD_INIT(security_hook_heads.socket_bind),
> +	.socket_connect =
> +		LIST_HEAD_INIT(security_hook_heads.socket_connect),
> +	.socket_listen =
> +		LIST_HEAD_INIT(security_hook_heads.socket_listen),
> +	.socket_accept =
> +		LIST_HEAD_INIT(security_hook_heads.socket_accept),
> +	.socket_sendmsg =
> +		LIST_HEAD_INIT(security_hook_heads.socket_sendmsg),
> +	.socket_recvmsg =
> +		LIST_HEAD_INIT(security_hook_heads.socket_recvmsg),
> +	.socket_getsockname =
> +		LIST_HEAD_INIT(security_hook_heads.socket_getsockname),
> +	.socket_getpeername =
> +		LIST_HEAD_INIT(security_hook_heads.socket_getpeername),
> +	.socket_getsockopt =
> +		LIST_HEAD_INIT(security_hook_heads.socket_getsockopt),
> +	.socket_setsockopt =
> +		LIST_HEAD_INIT(security_hook_heads.socket_setsockopt),
> +	.socket_shutdown =
> +		LIST_HEAD_INIT(security_hook_heads.socket_shutdown),
> +	.socket_sock_rcv_skb =
> +		LIST_HEAD_INIT(security_hook_heads.socket_sock_rcv_skb),
> +	.socket_getpeersec_stream =
> +		LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_stream),
> +	.socket_getpeersec_dgram =
> +		LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_dgram),
> +	.sk_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.sk_alloc_security),
> +	.sk_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.sk_free_security),
> +	.sk_clone_security =
> +		LIST_HEAD_INIT(security_hook_heads.sk_clone_security),
> +	.sk_getsecid =	LIST_HEAD_INIT(security_hook_heads.sk_getsecid),
> +	.sock_graft =	LIST_HEAD_INIT(security_hook_heads.sock_graft),
> +	.inet_conn_request =
> +		LIST_HEAD_INIT(security_hook_heads.inet_conn_request),
> +	.inet_csk_clone =
> +		LIST_HEAD_INIT(security_hook_heads.inet_csk_clone),
> +	.inet_conn_established =
> +		LIST_HEAD_INIT(security_hook_heads.inet_conn_established),
> +	.secmark_relabel_packet =
> +		LIST_HEAD_INIT(security_hook_heads.secmark_relabel_packet),
> +	.secmark_refcount_inc =
> +		LIST_HEAD_INIT(security_hook_heads.secmark_refcount_inc),
> +	.secmark_refcount_dec =
> +		LIST_HEAD_INIT(security_hook_heads.secmark_refcount_dec),
> +	.req_classify_flow =
> +		LIST_HEAD_INIT(security_hook_heads.req_classify_flow),
> +	.tun_dev_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.tun_dev_alloc_security),
> +	.tun_dev_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.tun_dev_free_security),
> +	.tun_dev_create =
> +		LIST_HEAD_INIT(security_hook_heads.tun_dev_create),
> +	.tun_dev_attach_queue =
> +		LIST_HEAD_INIT(security_hook_heads.tun_dev_attach_queue),
> +	.tun_dev_attach =
> +		LIST_HEAD_INIT(security_hook_heads.tun_dev_attach),
> +	.tun_dev_open =	LIST_HEAD_INIT(security_hook_heads.tun_dev_open),
> +	.skb_owned_by =	LIST_HEAD_INIT(security_hook_heads.skb_owned_by),
> +#endif	/* CONFIG_SECURITY_NETWORK */
> +#ifdef CONFIG_SECURITY_NETWORK_XFRM
> +	.xfrm_policy_alloc_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_policy_alloc_security),
> +	.xfrm_policy_clone_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_policy_clone_security),
> +	.xfrm_policy_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_policy_free_security),
> +	.xfrm_policy_delete_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_policy_delete_security),
> +	.xfrm_state_alloc =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc),
> +	.xfrm_state_alloc_acquire =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc_acquire),
> +	.xfrm_state_free_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_state_free_security),
> +	.xfrm_state_delete_security =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_state_delete_security),
> +	.xfrm_policy_lookup =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_policy_lookup),
> +	.xfrm_state_pol_flow_match =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_state_pol_flow_match),
> +	.xfrm_decode_session =
> +		LIST_HEAD_INIT(security_hook_heads.xfrm_decode_session),
> +#endif	/* CONFIG_SECURITY_NETWORK_XFRM */
> +#ifdef CONFIG_KEYS
> +	.key_alloc =	LIST_HEAD_INIT(security_hook_heads.key_alloc),
> +	.key_free =	LIST_HEAD_INIT(security_hook_heads.key_free),
> +	.key_permission =
> +		LIST_HEAD_INIT(security_hook_heads.key_permission),
> +	.key_getsecurity =
> +		LIST_HEAD_INIT(security_hook_heads.key_getsecurity),
> +#endif	/* CONFIG_KEYS */
> +#ifdef CONFIG_AUDIT
> +	.audit_rule_init =
> +		LIST_HEAD_INIT(security_hook_heads.audit_rule_init),
> +	.audit_rule_known =
> +		LIST_HEAD_INIT(security_hook_heads.audit_rule_known),
> +	.audit_rule_match =
> +		LIST_HEAD_INIT(security_hook_heads.audit_rule_match),
> +	.audit_rule_free =
> +		LIST_HEAD_INIT(security_hook_heads.audit_rule_free),
>  #endif /* CONFIG_AUDIT */
> +};
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 0cf105f..06c9dd9 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -1990,12 +1990,6 @@ static int selinux_binder_transfer_file(struct
> task_struct *from, 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);
> @@ -2007,25 +2001,13 @@ 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);
>  }
> 
>  static int selinux_capget(struct task_struct *target, kernel_cap_t
> *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted)
>  {
> -	int error;
> -
> -	error = current_has_perm(target, PROCESS__GETCAP);
> -	if (error)
> -		return error;
> -
> -	return cap_capget(target, effective, inheritable, permitted);
> +	return current_has_perm(target, PROCESS__GETCAP);
>  }
> 
>  static int selinux_capset(struct cred *new, const struct cred *old,
> @@ -2033,13 +2015,6 @@ static int selinux_capset(struct cred *new, const
> struct cred *old, const kernel_cap_t *inheritable,
>  			  const kernel_cap_t *permitted)
>  {
> -	int error;
> -
> -	error = cap_capset(new, old,
> -				      effective, inheritable, permitted);
> -	if (error)
> -		return error;
> -
>  	return cred_has_perm(old, new, PROCESS__SETCAP);
>  }
> 
> @@ -2056,12 +2031,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);
>  }
> 
> @@ -2139,12 +2108,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 */
> @@ -2193,10 +2162,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)
> @@ -2320,7 +2285,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)
> @@ -3132,8 +3097,11 @@ 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 = cap_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
> +			    SECURITY_CAP_NOAUDIT);
> +	if (!error)
> +		error = cred_has_capability(current_cred(), CAP_MAC_ADMIN,
> +					    SECURITY_CAP_NOAUDIT);
>  	if (!error)
>  		error = security_sid_to_context_force(isec->sid, &context,
>  						      &size);
> @@ -3318,12 +3286,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();
> @@ -3639,23 +3602,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);
>  }
> 
> @@ -3681,12 +3632,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);
>  }
> 
> @@ -5097,12 +5042,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);
>  }
> 
> @@ -5840,9 +5779,7 @@ static int selinux_key_getsecurity(struct key *key,
> char **_buffer)
> 
>  #endif
> 
> -static struct security_operations selinux_ops = {
> -	LSM_HOOK_INIT(name, "selinux"),
> -
> +static struct security_hook_list selinux_hooks[] = {
>  	LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
>  	LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
>  	LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
> @@ -6055,7 +5992,7 @@ static struct security_operations selinux_ops = {
> 
>  static __init int selinux_init(void)
>  {
> -	if (!security_module_enable(&selinux_ops)) {
> +	if (!security_module_enable("selinux")) {
>  		selinux_enabled = 0;
>  		return 0;
>  	}
> @@ -6077,8 +6014,7 @@ static __init int selinux_init(void)
>  					    0, SLAB_PANIC, NULL);
>  	avc_init();
> 
> -	if (register_security(&selinux_ops))
> -		panic("SELinux: Unable to register with kernel.\n");
> +	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
> 
>  	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
>  		panic("SELinux: Unable to register AVC netcache callback\n");
> @@ -6206,7 +6142,7 @@ int selinux_disable(void)
>  	selinux_disabled = 1;
>  	selinux_enabled = 0;
> 
> -	reset_security_ops();
> +	security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
> 
>  	/* Try to destroy the avc node cache */
>  	avc_disable();
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index 262dad8..b8c1a86 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -276,8 +276,6 @@ extern struct mutex	smack_known_lock;
>  extern struct list_head smack_known_list;
>  extern struct list_head smk_netlbladdr_list;
> 
> -extern struct security_operations smack_ops;
> -
>  #define SMACK_HASH_SLOTS 16
>  extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
> 
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 4313bf4..5eae42c 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -436,17 +436,11 @@ static int smk_ptrace_rule_check(struct task_struct
> *tracer, */
>  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_struct(ctp);
> 
> -	rc = smk_ptrace_rule_check(current, skp, mode, __func__);
> -	return rc;
> +	return smk_ptrace_rule_check(current, skp, mode, __func__);
>  }
> 
>  /**
> @@ -462,10 +456,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, PTRACE_MODE_ATTACH, __func__);
> @@ -721,10 +711,6 @@ static int smack_bprm_set_creds(struct linux_binprm
> *bprm) struct inode_smack *isp;
>  	int rc;
> 
> -	rc = cap_bprm_set_creds(bprm);
> -	if (rc != 0)
> -		return rc;
> -
>  	if (bprm->cred_prepared)
>  		return 0;
> 
> @@ -779,12 +765,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;
>  }
> 
>  /*
> @@ -1934,12 +1919,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__);
>  }
> 
>  /**
> @@ -1951,12 +1931,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__);
>  }
> 
>  /**
> @@ -1980,12 +1955,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__);
>  }
> 
>  /**
> @@ -4266,9 +4236,7 @@ static int smack_inode_getsecctx(struct inode *inode,
> void **ctx, u32 *ctxlen) return 0;
>  }
> 
> -struct security_operations smack_ops = {
> -	LSM_HOOK_INIT(name, "smack"),
> -
> +struct security_hook_list smack_hooks[] = {
>  	LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
>  	LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
>  	LSM_HOOK_INIT(syslog, smack_syslog),
> @@ -4451,7 +4419,7 @@ static __init int smack_init(void)
>  	struct cred *cred;
>  	struct task_smack *tsp;
> 
> -	if (!security_module_enable(&smack_ops))
> +	if (!security_module_enable("smack"))
>  		return 0;
> 
>  	smack_enabled = 1;
> @@ -4481,8 +4449,7 @@ static __init int smack_init(void)
>  	/*
>  	 * Register with LSM
>  	 */
> -	if (register_security(&smack_ops))
> -		panic("smack: Unable to register with kernel.\n");
> +	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
> 
>  	return 0;
>  }
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index d968298..4aa12c8 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -2547,7 +2547,7 @@ static int __init init_smk_fs(void)
>  	int err;
>  	int rc;
> 
> -	if (!security_module_enable(&smack_ops))
> +	if (!security_module_enable("smack"))
>  		return 0;
> 
>  	err = smk_init_sysfs();
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index bce1358..cbf3df4 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.
> @@ -502,8 +496,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock,
> struct msghdr *msg, * tomoyo_security_ops is a "struct security_operations"
> which is used for * registering TOMOYO.
>   */
> -static struct security_operations tomoyo_security_ops = {
> -	LSM_HOOK_INIT(name, "tomoyo"),
> +static struct security_hook_list tomoyo_hooks[] = {
>  	LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
>  	LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
>  	LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
> @@ -546,11 +539,10 @@ static int __init tomoyo_init(void)
>  {
>  	struct cred *cred = (struct cred *) current_cred();
> 
> -	if (!security_module_enable(&tomoyo_security_ops))
> +	if (!security_module_enable("tomoyo"))
>  		return 0;
>  	/* register ourselves with the security framework */
> -	if (register_security(&tomoyo_security_ops))
> -		panic("Failure registering TOMOYO Linux");
> +	security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
>  	printk(KERN_INFO "TOMOYO Linux initialized\n");
>  	cred->security = &tomoyo_kernel_domain;
>  	tomoyo_mm_init();
> diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
> index 23dd4c6..9ed3250 100644
> --- a/security/yama/yama_lsm.c
> +++ b/security/yama/yama_lsm.c
> @@ -154,13 +154,9 @@ void yama_task_free(struct task_struct *task)
>  int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
>  			   unsigned long arg4, unsigned long arg5)
>  {
> -	int rc;
> +	int rc = -ENOSYS;
>  	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,17 +275,10 @@ 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;
> +	int rc = 0;
> 
>  	/* require ptrace target be a child of ptracer on attach */
>  	if (mode == PTRACE_MODE_ATTACH) {
> @@ -335,14 +324,7 @@ int yama_ptrace_access_check(struct task_struct *child,
> */
>  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,16 +346,17 @@ int yama_ptrace_traceme(struct task_struct *parent)
>  	return rc;
>  }
> 
> -#ifndef CONFIG_SECURITY_YAMA_STACKED
> -static struct security_operations yama_ops = {
> -	LSM_HOOK_INIT(name, "yama"),
> -
> +static struct security_hook_list yama_hooks[] = {
>  	LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
>  	LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
>  	LSM_HOOK_INIT(task_prctl, yama_task_prctl),
>  	LSM_HOOK_INIT(task_free, yama_task_free),
>  };
> -#endif
> +
> +void __init yama_add_hooks(void)
> +{
> +	security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks));
> +}
> 
>  #ifdef CONFIG_SYSCTL
>  static int yama_dointvec_minmax(struct ctl_table *table, int write,
> @@ -418,16 +401,13 @@ static struct ctl_table yama_sysctl_table[] = {
>  static __init int yama_init(void)
>  {
>  #ifndef CONFIG_SECURITY_YAMA_STACKED
> -	if (!security_module_enable(&yama_ops))
> +	/*
> +	 * If yama is being stacked this is already taken care of.
> +	 */
> +	if (!security_module_enable("yama"))
>  		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))
> 
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in the body of a message to
> majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
paul moore
security @ redhat

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ