Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751977AbbEGVFp (ORCPT ); Thu, 7 May 2015 17:05:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57674 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751460AbbEGVFk (ORCPT ); Thu, 7 May 2015 17:05:40 -0400 From: Paul Moore To: Casey Schaufler Cc: James Morris , James Morris , LSM , LKLM , John Johansen , Tetsuo Handa , Stephen Smalley , Eric Paris , Kees Cook Subject: Re: [PATCH 6/7 v22] LSM: Switch to lists of hooks Date: Thu, 07 May 2015 17:05:38 -0400 Message-ID: <2188083.9YNqd7aYQ3@sifl> Organization: Red Hat User-Agent: KMail/4.14.6 (Linux/3.16.7-gentoo; KDE/4.14.7; x86_64; ; ) In-Reply-To: <55454B9E.4020205@schaufler-ca.com> References: <55454539.9020204@schaufler-ca.com> <55454B9E.4020205@schaufler-ca.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 63140 Lines: 1819 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 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 > 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 > - > -/* Maximum number of letters for an LSM name string */ > -#define SECURITY_NAME_MAX 10 > - > -#ifdef CONFIG_SECURITY > +#include > +#include > > /** > - * 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 > #include > #include > +#include > > 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 > #include > #include > -#include > +#include > #include > #include > #include > @@ -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@vger.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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/