Commit b1d9e6b0 authored by Casey Schaufler's avatar Casey Schaufler Committed by James Morris

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: default avatarCasey Schaufler <casey@schaufler-ca.com>
Acked-by: default avatarJohn Johansen <john.johansen@canonical.com>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Acked-by: default avatarPaul Moore <paul@paul-moore.com>
Acked-by: default avatarStephen Smalley <sds@tycho.nsa.gov>
Acked-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <james.l.morris@oracle.com>
parent e20b043a
...@@ -25,21 +25,10 @@ ...@@ -25,21 +25,10 @@
#define __LINUX_LSM_HOOKS_H #define __LINUX_LSM_HOOKS_H
#include <linux/security.h> #include <linux/security.h>
#include <linux/init.h>
/* Maximum number of letters for an LSM name string */ #include <linux/rculist.h>
#define SECURITY_NAME_MAX 10
#ifdef CONFIG_SECURITY
/** /**
* 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. * Security hooks for program execution operations.
* *
* @bprm_set_creds: * @bprm_set_creds:
...@@ -1310,9 +1299,7 @@ ...@@ -1310,9 +1299,7 @@
* This is the main security structure. * This is the main security structure.
*/ */
struct security_operations { union security_list_options {
char name[SECURITY_NAME_MAX + 1];
int (*binder_set_context_mgr)(struct task_struct *mgr); int (*binder_set_context_mgr)(struct task_struct *mgr);
int (*binder_transaction)(struct task_struct *from, int (*binder_transaction)(struct task_struct *from,
struct task_struct *to); struct task_struct *to);
...@@ -1837,21 +1824,63 @@ struct security_hook_heads { ...@@ -1837,21 +1824,63 @@ struct security_hook_heads {
#endif /* CONFIG_AUDIT */ #endif /* CONFIG_AUDIT */
}; };
/*
* 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 * Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes * up a lot of space in a source file. This macro takes
* care of the common case and reduces the amount of * care of the common case and reduces the amount of
* text involved. * 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 } }
extern struct security_hook_heads security_hook_heads;
static inline void security_add_hooks(struct security_hook_list *hooks,
int count)
{
int i;
/* prototypes */ for (i = 0; i < count; i++)
extern int security_module_enable(struct security_operations *ops); list_add_tail_rcu(&hooks[i].list, hooks[i].head);
extern int register_security(struct security_operations *ops); }
extern void __init security_fixup_ops(struct security_operations *ops);
extern void reset_security_ops(void);
#endif /* CONFIG_SECURITY */ #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 */ #endif /* ! __LINUX_LSM_HOOKS_H */
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/mm.h>
struct linux_binprm; struct linux_binprm;
struct cred; struct cred;
...@@ -54,9 +55,6 @@ struct xattr; ...@@ -54,9 +55,6 @@ struct xattr;
struct xfrm_sec_ctx; struct xfrm_sec_ctx;
struct mm_struct; struct mm_struct;
/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
/* If capable should audit the security request */ /* If capable should audit the security request */
#define SECURITY_CAP_NOAUDIT 0 #define SECURITY_CAP_NOAUDIT 0
#define SECURITY_CAP_AUDIT 1 #define SECURITY_CAP_AUDIT 1
...@@ -69,10 +67,7 @@ struct audit_krule; ...@@ -69,10 +67,7 @@ struct audit_krule;
struct user_namespace; struct user_namespace;
struct timezone; struct timezone;
/* /* These functions are in security/commoncap.c */
* These functions are in security/capability.c and are used
* as the default capabilities functions
*/
extern int cap_capable(const struct cred *cred, struct user_namespace *ns, extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit); int cap, int audit);
extern int cap_settime(const struct timespec *ts, const struct timezone *tz); extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
...@@ -114,8 +109,6 @@ struct xfrm_state; ...@@ -114,8 +109,6 @@ struct xfrm_state;
struct xfrm_user_sec_ctx; struct xfrm_user_sec_ctx;
struct seq_file; struct seq_file;
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
extern unsigned long mmap_min_addr; extern unsigned long mmap_min_addr;
extern unsigned long dac_mmap_min_addr; extern unsigned long dac_mmap_min_addr;
...@@ -472,7 +465,7 @@ static inline int security_settime(const struct timespec *ts, ...@@ -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) 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) 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 * ...@@ -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) 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) static inline int security_ismaclabel(const char *name)
...@@ -1643,36 +1636,5 @@ static inline void free_secdata(void *secdata) ...@@ -1643,36 +1636,5 @@ static inline void free_secdata(void *secdata)
{ } { }
#endif /* CONFIG_SECURITY */ #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 */ #endif /* ! __LINUX_SECURITY_H */
...@@ -14,7 +14,7 @@ obj-y += commoncap.o ...@@ -14,7 +14,7 @@ obj-y += commoncap.o
obj-$(CONFIG_MMU) += min_addr.o obj-$(CONFIG_MMU) += min_addr.o
# Object file lists # Object file lists
obj-$(CONFIG_SECURITY) += security.o capability.o obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITYFS) += inode.o obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/ obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/ obj-$(CONFIG_SECURITY_SMACK) += smack/
......
...@@ -347,9 +347,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -347,9 +347,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
file_inode(bprm->file)->i_mode file_inode(bprm->file)->i_mode
}; };
const char *name = NULL, *target = NULL, *info = NULL; const char *name = NULL, *target = NULL, *info = NULL;
int error = cap_bprm_set_creds(bprm); int error = 0;
if (error)
return error;
if (bprm->cred_prepared) if (bprm->cred_prepared)
return 0; return 0;
...@@ -531,15 +529,13 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ...@@ -531,15 +529,13 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
*/ */
int apparmor_bprm_secureexec(struct linux_binprm *bprm) 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 /* the decision to use secure exec is computed in set_creds
* and stored in bprm->unsafe. * and stored in bprm->unsafe.
*/ */
if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED)) if (bprm->unsafe & AA_SECURE_X_NEEDED)
ret = 1; return 1;
return ret; return 0;
} }
/** /**
......
...@@ -96,19 +96,11 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) ...@@ -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, static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode) unsigned int mode)
{ {
int error = cap_ptrace_access_check(child, mode);
if (error)
return error;
return aa_ptrace(current, child, mode); return aa_ptrace(current, child, mode);
} }
static int apparmor_ptrace_traceme(struct task_struct *parent) 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); return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
} }
...@@ -123,10 +115,10 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, ...@@ -123,10 +115,10 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
cred = __task_cred(target); cred = __task_cred(target);
profile = aa_cred_profile(cred); profile = aa_cred_profile(cred);
*effective = cred->cap_effective; /*
*inheritable = cred->cap_inheritable; * cap_capget is stacked ahead of this and will
*permitted = cred->cap_permitted; * initialize effective and permitted.
*/
if (!unconfined(profile) && !COMPLAIN_MODE(profile)) { if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow); *effective = cap_intersect(*effective, profile->caps.allow);
*permitted = cap_intersect(*permitted, 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, ...@@ -140,13 +132,11 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit) int cap, int audit)
{ {
struct aa_profile *profile; struct aa_profile *profile;
/* cap_capable returns 0 on success, else -EPERM */ int error = 0;
int error = cap_capable(cred, ns, cap, audit);
if (!error) {
profile = aa_cred_profile(cred); profile = aa_cred_profile(cred);
if (!unconfined(profile)) if (!unconfined(profile))
error = aa_capable(profile, cap, audit); error = aa_capable(profile, cap, audit);
}
return error; return error;
} }
...@@ -615,9 +605,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, ...@@ -615,9 +605,7 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error; return error;
} }
static struct security_operations apparmor_ops = { static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(name, "apparmor"),
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
LSM_HOOK_INIT(capget, apparmor_capget), LSM_HOOK_INIT(capget, apparmor_capget),
...@@ -640,7 +628,6 @@ static struct security_operations apparmor_ops = { ...@@ -640,7 +628,6 @@ static struct security_operations apparmor_ops = {
LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security), LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security),
LSM_HOOK_INIT(file_free_security, apparmor_file_free_security), LSM_HOOK_INIT(file_free_security, apparmor_file_free_security),
LSM_HOOK_INIT(mmap_file, apparmor_mmap_file), 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_mprotect, apparmor_file_mprotect),
LSM_HOOK_INIT(file_lock, apparmor_file_lock), LSM_HOOK_INIT(file_lock, apparmor_file_lock),
...@@ -898,7 +885,7 @@ static int __init apparmor_init(void) ...@@ -898,7 +885,7 @@ static int __init apparmor_init(void)
{ {
int error; 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"); aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = 0; apparmor_enabled = 0;
return 0; return 0;
...@@ -913,17 +900,10 @@ static int __init apparmor_init(void) ...@@ -913,17 +900,10 @@ static int __init apparmor_init(void)
error = set_init_cxt(); error = set_init_cxt();
if (error) { if (error) {
AA_ERROR("Failed to set context on init task\n"); AA_ERROR("Failed to set context on init task\n");
goto register_security_out; aa_free_root_ns();
} goto alloc_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;
} }
security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
/* Report that AppArmor successfully initialized */ /* Report that AppArmor successfully initialized */
apparmor_initialized = 1; apparmor_initialized = 1;
...@@ -936,9 +916,6 @@ static int __init apparmor_init(void) ...@@ -936,9 +916,6 @@ static int __init apparmor_init(void)
return error; return error;
register_security_out:
aa_free_root_ns();
alloc_out: alloc_out:
aa_destroy_aafs(); aa_destroy_aafs();
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/security.h> #include <linux/lsm_hooks.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
...@@ -53,11 +53,6 @@ static void warn_setuid_and_fcaps_mixed(const char *fname) ...@@ -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 * cap_capable - Determine whether a task has a particular effective capability
* @cred: The credentials to use * @cred: The credentials to use
...@@ -941,7 +936,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, ...@@ -941,7 +936,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* @pages: The size of the mapping * @pages: The size of the mapping
* *
* Determine whether the allocation of a new virtual mapping by the current * 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) 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) ...@@ -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, if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
SECURITY_CAP_NOAUDIT) == 0) SECURITY_CAP_NOAUDIT) == 0)
cap_sys_admin = 1; 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, ...@@ -981,3 +976,33 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,
{ {
return 0; 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 */
This diff is collapsed.
...@@ -1990,12 +1990,6 @@ static int selinux_binder_transfer_file(struct task_struct *from, ...@@ -1990,12 +1990,6 @@ static int selinux_binder_transfer_file(struct task_struct *from,
static int selinux_ptrace_access_check(struct task_struct *child, static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode) unsigned int mode)
{ {
int rc;
rc = cap_ptrace_access_check(child, mode);
if (rc)
return rc;
if (mode & PTRACE_MODE_READ) { if (mode & PTRACE_MODE_READ) {
u32 sid = current_sid(); u32 sid = current_sid();
u32 csid = task_sid(child); u32 csid = task_sid(child);
...@@ -2007,25 +2001,13 @@ static int selinux_ptrace_access_check(struct task_struct *child, ...@@ -2007,25 +2001,13 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent) 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); return task_has_perm(parent, current, PROCESS__PTRACE);
} }
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
int error; return current_has_perm(target, PROCESS__GETCAP);
error = current_has_perm(target, PROCESS__GETCAP);
if (error)
return error;
return cap_capget(target, effective, inheritable, permitted);
} }
static int selinux_capset(struct cred *new, const struct cred *old, 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, ...@@ -2033,13 +2015,6 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable, const kernel_cap_t *inheritable,
const kernel_cap_t *permitted) 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); return cred_has_perm(old, new, PROCESS__SETCAP);
} }
...@@ -2056,12 +2031,6 @@ static int selinux_capset(struct cred *new, const struct cred *old, ...@@ -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, static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit) int cap, int audit)
{ {
int rc;
rc = cap_capable(cred, ns, cap, audit);
if (rc)
return rc;
return cred_has_capability(cred, cap, audit); return cred_has_capability(cred, cap, audit);
} }
...@@ -2139,12 +2108,12 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) ...@@ -2139,12 +2108,12 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{ {
int rc, cap_sys_admin = 0; int rc, cap_sys_admin = 0;
rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
SECURITY_CAP_NOAUDIT); SECURITY_CAP_NOAUDIT);
if (rc == 0) if (rc == 0)
cap_sys_admin = 1; cap_sys_admin = 1;
return __vm_enough_memory(mm, pages, cap_sys_admin); return cap_sys_admin;
} }
/* binprm security operations */ /* binprm security operations */
...@@ -2193,10 +2162,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) ...@@ -2193,10 +2162,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file); struct inode *inode = file_inode(bprm->file);
int rc; int rc;
rc = cap_bprm_set_creds(bprm);
if (rc)
return rc;
/* SELinux context only depends on initial program or script and not /* SELinux context only depends on initial program or script and not
* the script interpreter */ * the script interpreter */
if (bprm->cred_prepared) if (bprm->cred_prepared)
...@@ -2320,7 +2285,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm) ...@@ -2320,7 +2285,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
PROCESS__NOATSECURE, NULL); PROCESS__NOATSECURE, NULL);
} }
return (atsecure || cap_bprm_secureexec(bprm)); return !!atsecure;
} }
static int match_file(const void *p, struct file *file, unsigned fd) static int match_file(const void *p, struct file *file, unsigned fd)
...@@ -3132,7 +3097,10 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name ...@@ -3132,7 +3097,10 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
* and lack of permission just means that we fall back to the * and lack of permission just means that we fall back to the
* in-core context value, not a denial. * in-core context value, not a denial.
*/ */
error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN, 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); SECURITY_CAP_NOAUDIT);
if (!error) if (!error)
error = security_sid_to_context_force(isec->sid, &context, error = security_sid_to_context_force(isec->sid, &context,
...@@ -3318,12 +3286,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared ...@@ -3318,12 +3286,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
static int selinux_mmap_addr(unsigned long addr) static int selinux_mmap_addr(unsigned long addr)
{ {
int rc; int rc = 0;
/* do DAC check on address space usage */
rc = cap_mmap_addr(addr);
if (rc)
return rc;
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid(); u32 sid = current_sid();
...@@ -3639,23 +3602,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) ...@@ -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) 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); return current_has_perm(p, PROCESS__SETSCHED);
} }
static int selinux_task_setioprio(struct task_struct *p, int ioprio) 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); return current_has_perm(p, PROCESS__SETSCHED);
} }
...@@ -3681,12 +3632,6 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, ...@@ -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) 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); return current_has_perm(p, PROCESS__SETSCHED);
} }
...@@ -5097,12 +5042,6 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops, ...@@ -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) 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); return selinux_nlmsg_perm(sk, skb);
} }
...@@ -5840,9 +5779,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) ...@@ -5840,9 +5779,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
#endif #endif
static struct security_operations selinux_ops = { static struct security_hook_list selinux_hooks[] = {
LSM_HOOK_INIT(name, "selinux"),
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
...@@ -6055,7 +5992,7 @@ static struct security_operations selinux_ops = { ...@@ -6055,7 +5992,7 @@ static struct security_operations selinux_ops = {
static __init int selinux_init(void) static __init int selinux_init(void)
{ {
if (!security_module_enable(&selinux_ops)) { if (!security_module_enable("selinux")) {
selinux_enabled = 0; selinux_enabled = 0;
return 0; return 0;
} }
...@@ -6077,8 +6014,7 @@ static __init int selinux_init(void) ...@@ -6077,8 +6014,7 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
avc_init(); avc_init();
if (register_security(&selinux_ops)) security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
panic("SELinux: Unable to register with kernel.\n");
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n"); panic("SELinux: Unable to register AVC netcache callback\n");
...@@ -6206,7 +6142,7 @@ int selinux_disable(void) ...@@ -6206,7 +6142,7 @@ int selinux_disable(void)
selinux_disabled = 1; selinux_disabled = 1;
selinux_enabled = 0; selinux_enabled = 0;
reset_security_ops(); security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
/* Try to destroy the avc node cache */ /* Try to destroy the avc node cache */
avc_disable(); avc_disable();
......
...@@ -276,8 +276,6 @@ extern struct mutex smack_known_lock; ...@@ -276,8 +276,6 @@ extern struct mutex smack_known_lock;
extern struct list_head smack_known_list; extern struct list_head smack_known_list;
extern struct list_head smk_netlbladdr_list; extern struct list_head smk_netlbladdr_list;
extern struct security_operations smack_ops;
#define SMACK_HASH_SLOTS 16 #define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
......
...@@ -436,17 +436,11 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, ...@@ -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) static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{ {
int rc;
struct smack_known *skp; struct smack_known *skp;
rc = cap_ptrace_access_check(ctp, mode);
if (rc != 0)
return rc;
skp = smk_of_task_struct(ctp); skp = smk_of_task_struct(ctp);
rc = smk_ptrace_rule_check(current, skp, mode, __func__); return smk_ptrace_rule_check(current, skp, mode, __func__);
return rc;
} }
/** /**
...@@ -462,10 +456,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp) ...@@ -462,10 +456,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
int rc; int rc;
struct smack_known *skp; struct smack_known *skp;
rc = cap_ptrace_traceme(ptp);
if (rc != 0)
return rc;
skp = smk_of_task(current_security()); skp = smk_of_task(current_security());
rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); 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) ...@@ -721,10 +711,6 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
struct inode_smack *isp; struct inode_smack *isp;
int rc; int rc;
rc = cap_bprm_set_creds(bprm);
if (rc != 0)
return rc;
if (bprm->cred_prepared) if (bprm->cred_prepared)
return 0; return 0;
...@@ -779,12 +765,11 @@ static void smack_bprm_committing_creds(struct linux_binprm *bprm) ...@@ -779,12 +765,11 @@ static void smack_bprm_committing_creds(struct linux_binprm *bprm)
static int smack_bprm_secureexec(struct linux_binprm *bprm) static int smack_bprm_secureexec(struct linux_binprm *bprm)
{ {
struct task_smack *tsp = current_security(); struct task_smack *tsp = current_security();
int ret = cap_bprm_secureexec(bprm);
if (!ret && (tsp->smk_task != tsp->smk_forked)) if (tsp->smk_task != tsp->smk_forked)
ret = 1; return 1;
return ret; return 0;
} }
/* /*
...@@ -1934,12 +1919,7 @@ static void smack_task_getsecid(struct task_struct *p, u32 *secid) ...@@ -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) static int smack_task_setnice(struct task_struct *p, int nice)
{ {
int rc; return smk_curacc_on_task(p, MAY_WRITE, __func__);
rc = cap_task_setnice(p, nice);
if (rc == 0)
rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
} }
/** /**
...@@ -1951,12 +1931,7 @@ static int smack_task_setnice(struct task_struct *p, int nice) ...@@ -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) static int smack_task_setioprio(struct task_struct *p, int ioprio)
{ {
int rc; return smk_curacc_on_task(p, MAY_WRITE, __func__);
rc = cap_task_setioprio(p, ioprio);
if (rc == 0)
rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
} }
/** /**
...@@ -1980,12 +1955,7 @@ static int smack_task_getioprio(struct task_struct *p) ...@@ -1980,12 +1955,7 @@ static int smack_task_getioprio(struct task_struct *p)
*/ */
static int smack_task_setscheduler(struct task_struct *p) static int smack_task_setscheduler(struct task_struct *p)
{ {
int rc; return smk_curacc_on_task(p, MAY_WRITE, __func__);
rc = cap_task_setscheduler(p);
if (rc == 0)
rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
return rc;
} }
/** /**
...@@ -4266,9 +4236,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) ...@@ -4266,9 +4236,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
return 0; return 0;
} }
struct security_operations smack_ops = { struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT(name, "smack"),
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog), LSM_HOOK_INIT(syslog, smack_syslog),
...@@ -4451,7 +4419,7 @@ static __init int smack_init(void) ...@@ -4451,7 +4419,7 @@ static __init int smack_init(void)
struct cred *cred; struct cred *cred;
struct task_smack *tsp; struct task_smack *tsp;
if (!security_module_enable(&smack_ops)) if (!security_module_enable("smack"))
return 0; return 0;
smack_enabled = 1; smack_enabled = 1;
...@@ -4481,8 +4449,7 @@ static __init int smack_init(void) ...@@ -4481,8 +4449,7 @@ static __init int smack_init(void)
/* /*
* Register with LSM * Register with LSM
*/ */
if (register_security(&smack_ops)) security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
panic("smack: Unable to register with kernel.\n");
return 0; return 0;
} }
......
...@@ -2547,7 +2547,7 @@ static int __init init_smk_fs(void) ...@@ -2547,7 +2547,7 @@ static int __init init_smk_fs(void)
int err; int err;
int rc; int rc;
if (!security_module_enable(&smack_ops)) if (!security_module_enable("smack"))
return 0; return 0;
err = smk_init_sysfs(); err = smk_init_sysfs();
......
...@@ -72,12 +72,6 @@ static void tomoyo_cred_free(struct cred *cred) ...@@ -72,12 +72,6 @@ static void tomoyo_cred_free(struct cred *cred)
*/ */
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) 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 * Do only if this function is called for the first time of an execve
* operation. * operation.
...@@ -502,8 +496,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -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 * tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO. * registering TOMOYO.
*/ */
static struct security_operations tomoyo_security_ops = { static struct security_hook_list tomoyo_hooks[] = {
LSM_HOOK_INIT(name, "tomoyo"),
LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank), LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer), LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
...@@ -546,11 +539,10 @@ static int __init tomoyo_init(void) ...@@ -546,11 +539,10 @@ static int __init tomoyo_init(void)
{ {
struct cred *cred = (struct cred *) current_cred(); struct cred *cred = (struct cred *) current_cred();
if (!security_module_enable(&tomoyo_security_ops)) if (!security_module_enable("tomoyo"))
return 0; return 0;
/* register ourselves with the security framework */ /* register ourselves with the security framework */
if (register_security(&tomoyo_security_ops)) security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n"); printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain; cred->security = &tomoyo_kernel_domain;
tomoyo_mm_init(); tomoyo_mm_init();
......
...@@ -154,13 +154,9 @@ void yama_task_free(struct task_struct *task) ...@@ -154,13 +154,9 @@ void yama_task_free(struct task_struct *task)
int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5) unsigned long arg4, unsigned long arg5)
{ {
int rc; int rc = -ENOSYS;
struct task_struct *myself = current; struct task_struct *myself = current;
rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
if (rc != -ENOSYS)
return rc;
switch (option) { switch (option) {
case PR_SET_PTRACER: case PR_SET_PTRACER:
/* Since a thread can call prctl(), find the group leader /* Since a thread can call prctl(), find the group leader
...@@ -279,17 +275,10 @@ static int ptracer_exception_found(struct task_struct *tracer, ...@@ -279,17 +275,10 @@ static int ptracer_exception_found(struct task_struct *tracer,
* *
* Returns 0 if following the ptrace is allowed, -ve on error. * 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) unsigned int mode)
{ {
int rc; int rc = 0;
/* If standard caps disallows it, so does Yama. We should
* only tighten restrictions further.
*/
rc = cap_ptrace_access_check(child, mode);
if (rc)
return rc;
/* require ptrace target be a child of ptracer on attach */ /* require ptrace target be a child of ptracer on attach */
if (mode == PTRACE_MODE_ATTACH) { if (mode == PTRACE_MODE_ATTACH) {
...@@ -335,14 +324,7 @@ int yama_ptrace_access_check(struct task_struct *child, ...@@ -335,14 +324,7 @@ int yama_ptrace_access_check(struct task_struct *child,
*/ */
int yama_ptrace_traceme(struct task_struct *parent) int yama_ptrace_traceme(struct task_struct *parent)
{ {
int rc; int rc = 0;
/* If standard caps disallows it, so does Yama. We should
* only tighten restrictions further.
*/
rc = cap_ptrace_traceme(parent);
if (rc)
return rc;
/* Only disallow PTRACE_TRACEME on more aggressive settings. */ /* Only disallow PTRACE_TRACEME on more aggressive settings. */
switch (ptrace_scope) { switch (ptrace_scope) {
...@@ -364,16 +346,17 @@ int yama_ptrace_traceme(struct task_struct *parent) ...@@ -364,16 +346,17 @@ int yama_ptrace_traceme(struct task_struct *parent)
return rc; return rc;
} }
#ifndef CONFIG_SECURITY_YAMA_STACKED static struct security_hook_list yama_hooks[] = {
static struct security_operations yama_ops = {
LSM_HOOK_INIT(name, "yama"),
LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check), LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme), LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
LSM_HOOK_INIT(task_prctl, yama_task_prctl), LSM_HOOK_INIT(task_prctl, yama_task_prctl),
LSM_HOOK_INIT(task_free, yama_task_free), 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 #ifdef CONFIG_SYSCTL
static int yama_dointvec_minmax(struct ctl_table *table, int write, static int yama_dointvec_minmax(struct ctl_table *table, int write,
...@@ -418,16 +401,13 @@ static struct ctl_table yama_sysctl_table[] = { ...@@ -418,16 +401,13 @@ static struct ctl_table yama_sysctl_table[] = {
static __init int yama_init(void) static __init int yama_init(void)
{ {
#ifndef CONFIG_SECURITY_YAMA_STACKED #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; return 0;
#endif #endif
pr_info("Yama: becoming mindful.\n");
printk(KERN_INFO "Yama: becoming mindful.\n");
#ifndef CONFIG_SECURITY_YAMA_STACKED
if (register_security(&yama_ops))
panic("Yama: kernel registration failed.\n");
#endif
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment