Skip to content

Commit b1d9e6b

Browse files
cschauflerJames Morris
authored andcommitted
LSM: Switch to lists of hooks
Instead of using a vector of security operations with explicit, special case stacking of the capability and yama hooks use lists of hooks with capability and yama hooks included as appropriate. The security_operations structure is no longer required. Instead, there is a union of the function pointers that allows all the hooks lists to use a common mechanism for list management while retaining typing. Each module supplies an array describing the hooks it provides instead of a sparsely populated security_operations structure. The description includes the element that gets put on the hook list, avoiding the issues surrounding individual element allocation. The method for registering security modules is changed to reflect the information available. The method for removing a module, currently only used by SELinux, has also changed. It should be generic now, however if there are potential race conditions based on ordering of hook removal that needs to be addressed by the calling module. The security hooks are called from the lists and the first failure is returned. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> Acked-by: John Johansen <john.johansen@canonical.com> Acked-by: Kees Cook <keescook@chromium.org> Acked-by: Paul Moore <paul@paul-moore.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <james.l.morris@oracle.com>
1 parent e20b043 commit b1d9e6b

File tree

13 files changed

+627
-387
lines changed

13 files changed

+627
-387
lines changed

include/linux/lsm_hooks.h

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,10 @@
2525
#define __LINUX_LSM_HOOKS_H
2626

2727
#include <linux/security.h>
28-
29-
/* Maximum number of letters for an LSM name string */
30-
#define SECURITY_NAME_MAX 10
31-
32-
#ifdef CONFIG_SECURITY
28+
#include <linux/init.h>
29+
#include <linux/rculist.h>
3330

3431
/**
35-
* struct security_operations - main security structure
36-
*
37-
* Security module identifier.
38-
*
39-
* @name:
40-
* A string that acts as a unique identifier for the LSM with max number
41-
* of characters = SECURITY_NAME_MAX.
42-
*
4332
* Security hooks for program execution operations.
4433
*
4534
* @bprm_set_creds:
@@ -1310,9 +1299,7 @@
13101299
* This is the main security structure.
13111300
*/
13121301

1313-
struct security_operations {
1314-
char name[SECURITY_NAME_MAX + 1];
1315-
1302+
union security_list_options {
13161303
int (*binder_set_context_mgr)(struct task_struct *mgr);
13171304
int (*binder_transaction)(struct task_struct *from,
13181305
struct task_struct *to);
@@ -1837,21 +1824,63 @@ struct security_hook_heads {
18371824
#endif /* CONFIG_AUDIT */
18381825
};
18391826

1827+
/*
1828+
* Security module hook list structure.
1829+
* For use with generic list macros for common operations.
1830+
*/
1831+
struct security_hook_list {
1832+
struct list_head list;
1833+
struct list_head *head;
1834+
union security_list_options hook;
1835+
};
1836+
18401837
/*
18411838
* Initializing a security_hook_list structure takes
18421839
* up a lot of space in a source file. This macro takes
18431840
* care of the common case and reduces the amount of
18441841
* text involved.
1845-
* Casey says: Comment is true in the next patch.
18461842
*/
1847-
#define LSM_HOOK_INIT(HEAD, HOOK) .HEAD = HOOK
1843+
#define LSM_HOOK_INIT(HEAD, HOOK) \
1844+
{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
1845+
1846+
extern struct security_hook_heads security_hook_heads;
1847+
1848+
static inline void security_add_hooks(struct security_hook_list *hooks,
1849+
int count)
1850+
{
1851+
int i;
18481852

1849-
/* prototypes */
1850-
extern int security_module_enable(struct security_operations *ops);
1851-
extern int register_security(struct security_operations *ops);
1852-
extern void __init security_fixup_ops(struct security_operations *ops);
1853-
extern void reset_security_ops(void);
1853+
for (i = 0; i < count; i++)
1854+
list_add_tail_rcu(&hooks[i].list, hooks[i].head);
1855+
}
18541856

1855-
#endif /* CONFIG_SECURITY */
1857+
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
1858+
/*
1859+
* Assuring the safety of deleting a security module is up to
1860+
* the security module involved. This may entail ordering the
1861+
* module's hook list in a particular way, refusing to disable
1862+
* the module once a policy is loaded or any number of other
1863+
* actions better imagined than described.
1864+
*
1865+
* The name of the configuration option reflects the only module
1866+
* that currently uses the mechanism. Any developer who thinks
1867+
* disabling their module is a good idea needs to be at least as
1868+
* careful as the SELinux team.
1869+
*/
1870+
static inline void security_delete_hooks(struct security_hook_list *hooks,
1871+
int count)
1872+
{
1873+
int i;
1874+
1875+
for (i = 0; i < count; i++)
1876+
list_del_rcu(&hooks[i].list);
1877+
}
1878+
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
1879+
1880+
extern int __init security_module_enable(const char *module);
1881+
extern void __init capability_add_hooks(void);
1882+
#ifdef CONFIG_SECURITY_YAMA_STACKED
1883+
void __init yama_add_hooks(void);
1884+
#endif
18561885

18571886
#endif /* ! __LINUX_LSM_HOOKS_H */

include/linux/security.h

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/slab.h>
2828
#include <linux/err.h>
2929
#include <linux/string.h>
30+
#include <linux/mm.h>
3031

3132
struct linux_binprm;
3233
struct cred;
@@ -54,9 +55,6 @@ struct xattr;
5455
struct xfrm_sec_ctx;
5556
struct mm_struct;
5657

57-
/* Maximum number of letters for an LSM name string */
58-
#define SECURITY_NAME_MAX 10
59-
6058
/* If capable should audit the security request */
6159
#define SECURITY_CAP_NOAUDIT 0
6260
#define SECURITY_CAP_AUDIT 1
@@ -69,10 +67,7 @@ struct audit_krule;
6967
struct user_namespace;
7068
struct timezone;
7169

72-
/*
73-
* These functions are in security/capability.c and are used
74-
* as the default capabilities functions
75-
*/
70+
/* These functions are in security/commoncap.c */
7671
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
7772
int cap, int audit);
7873
extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
@@ -114,8 +109,6 @@ struct xfrm_state;
114109
struct xfrm_user_sec_ctx;
115110
struct seq_file;
116111

117-
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
118-
119112
#ifdef CONFIG_MMU
120113
extern unsigned long mmap_min_addr;
121114
extern unsigned long dac_mmap_min_addr;
@@ -472,7 +465,7 @@ static inline int security_settime(const struct timespec *ts,
472465

473466
static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
474467
{
475-
return cap_vm_enough_memory(mm, pages);
468+
return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages));
476469
}
477470

478471
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 *
10751068

10761069
static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
10771070
{
1078-
return cap_netlink_send(sk, skb);
1071+
return 0;
10791072
}
10801073

10811074
static inline int security_ismaclabel(const char *name)
@@ -1643,36 +1636,5 @@ static inline void free_secdata(void *secdata)
16431636
{ }
16441637
#endif /* CONFIG_SECURITY */
16451638

1646-
#ifdef CONFIG_SECURITY_YAMA
1647-
extern int yama_ptrace_access_check(struct task_struct *child,
1648-
unsigned int mode);
1649-
extern int yama_ptrace_traceme(struct task_struct *parent);
1650-
extern void yama_task_free(struct task_struct *task);
1651-
extern int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
1652-
unsigned long arg4, unsigned long arg5);
1653-
#else
1654-
static inline int yama_ptrace_access_check(struct task_struct *child,
1655-
unsigned int mode)
1656-
{
1657-
return 0;
1658-
}
1659-
1660-
static inline int yama_ptrace_traceme(struct task_struct *parent)
1661-
{
1662-
return 0;
1663-
}
1664-
1665-
static inline void yama_task_free(struct task_struct *task)
1666-
{
1667-
}
1668-
1669-
static inline int yama_task_prctl(int option, unsigned long arg2,
1670-
unsigned long arg3, unsigned long arg4,
1671-
unsigned long arg5)
1672-
{
1673-
return -ENOSYS;
1674-
}
1675-
#endif /* CONFIG_SECURITY_YAMA */
1676-
16771639
#endif /* ! __LINUX_SECURITY_H */
16781640

security/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ obj-y += commoncap.o
1414
obj-$(CONFIG_MMU) += min_addr.o
1515

1616
# Object file lists
17-
obj-$(CONFIG_SECURITY) += security.o capability.o
17+
obj-$(CONFIG_SECURITY) += security.o
1818
obj-$(CONFIG_SECURITYFS) += inode.o
1919
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
2020
obj-$(CONFIG_SECURITY_SMACK) += smack/

security/apparmor/domain.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
347347
file_inode(bprm->file)->i_mode
348348
};
349349
const char *name = NULL, *target = NULL, *info = NULL;
350-
int error = cap_bprm_set_creds(bprm);
351-
if (error)
352-
return error;
350+
int error = 0;
353351

354352
if (bprm->cred_prepared)
355353
return 0;
@@ -531,15 +529,13 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
531529
*/
532530
int apparmor_bprm_secureexec(struct linux_binprm *bprm)
533531
{
534-
int ret = cap_bprm_secureexec(bprm);
535-
536532
/* the decision to use secure exec is computed in set_creds
537533
* and stored in bprm->unsafe.
538534
*/
539-
if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
540-
ret = 1;
535+
if (bprm->unsafe & AA_SECURE_X_NEEDED)
536+
return 1;
541537

542-
return ret;
538+
return 0;
543539
}
544540

545541
/**

security/apparmor/lsm.c

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,11 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
9696
static int apparmor_ptrace_access_check(struct task_struct *child,
9797
unsigned int mode)
9898
{
99-
int error = cap_ptrace_access_check(child, mode);
100-
if (error)
101-
return error;
102-
10399
return aa_ptrace(current, child, mode);
104100
}
105101

106102
static int apparmor_ptrace_traceme(struct task_struct *parent)
107103
{
108-
int error = cap_ptrace_traceme(parent);
109-
if (error)
110-
return error;
111-
112104
return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
113105
}
114106

@@ -123,10 +115,10 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
123115
cred = __task_cred(target);
124116
profile = aa_cred_profile(cred);
125117

126-
*effective = cred->cap_effective;
127-
*inheritable = cred->cap_inheritable;
128-
*permitted = cred->cap_permitted;
129-
118+
/*
119+
* cap_capget is stacked ahead of this and will
120+
* initialize effective and permitted.
121+
*/
130122
if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
131123
*effective = cap_intersect(*effective, profile->caps.allow);
132124
*permitted = cap_intersect(*permitted, profile->caps.allow);
@@ -140,13 +132,11 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
140132
int cap, int audit)
141133
{
142134
struct aa_profile *profile;
143-
/* cap_capable returns 0 on success, else -EPERM */
144-
int error = cap_capable(cred, ns, cap, audit);
145-
if (!error) {
146-
profile = aa_cred_profile(cred);
147-
if (!unconfined(profile))
148-
error = aa_capable(profile, cap, audit);
149-
}
135+
int error = 0;
136+
137+
profile = aa_cred_profile(cred);
138+
if (!unconfined(profile))
139+
error = aa_capable(profile, cap, audit);
150140
return error;
151141
}
152142

@@ -615,9 +605,7 @@ static int apparmor_task_setrlimit(struct task_struct *task,
615605
return error;
616606
}
617607

618-
static struct security_operations apparmor_ops = {
619-
LSM_HOOK_INIT(name, "apparmor"),
620-
608+
static struct security_hook_list apparmor_hooks[] = {
621609
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
622610
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
623611
LSM_HOOK_INIT(capget, apparmor_capget),
@@ -640,7 +628,6 @@ static struct security_operations apparmor_ops = {
640628
LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security),
641629
LSM_HOOK_INIT(file_free_security, apparmor_file_free_security),
642630
LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
643-
LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
644631
LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
645632
LSM_HOOK_INIT(file_lock, apparmor_file_lock),
646633

@@ -898,7 +885,7 @@ static int __init apparmor_init(void)
898885
{
899886
int error;
900887

901-
if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
888+
if (!apparmor_enabled || !security_module_enable("apparmor")) {
902889
aa_info_message("AppArmor disabled by boot time parameter");
903890
apparmor_enabled = 0;
904891
return 0;
@@ -913,17 +900,10 @@ static int __init apparmor_init(void)
913900
error = set_init_cxt();
914901
if (error) {
915902
AA_ERROR("Failed to set context on init task\n");
916-
goto register_security_out;
917-
}
918-
919-
error = register_security(&apparmor_ops);
920-
if (error) {
921-
struct cred *cred = (struct cred *)current->real_cred;
922-
aa_free_task_context(cred_cxt(cred));
923-
cred_cxt(cred) = NULL;
924-
AA_ERROR("Unable to register AppArmor\n");
925-
goto register_security_out;
903+
aa_free_root_ns();
904+
goto alloc_out;
926905
}
906+
security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
927907

928908
/* Report that AppArmor successfully initialized */
929909
apparmor_initialized = 1;
@@ -936,9 +916,6 @@ static int __init apparmor_init(void)
936916

937917
return error;
938918

939-
register_security_out:
940-
aa_free_root_ns();
941-
942919
alloc_out:
943920
aa_destroy_aafs();
944921

0 commit comments

Comments
 (0)