2018-04-01 05:44:34

by Sargun Dhillon

[permalink] [raw]
Subject: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

The biggest security benefit of this patchset is the introduction of
read-only hooks, even if some security modules have mutable hooks.
Currently, if you have any LSMs with mutable hooks it will render all heads, and
list nodes mutable. These are a prime place to attack, because being able to
manipulate those hooks is a way to bypass all LSMs easily, and to create a
persistent, covert channel to intercept nearly all calls.


If LSMs have a model to be unloaded, or are compled as modules, they should mark
themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE macro
instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
chain.

In order to provide safe code-unloading, there is a shared SRCU between
all security hooks. This SRCU is very cheap for runtime overhead on
reads, but there is synchronization around it for unloads. There is
only a cost to pay at unload time, which is based on the execution time
of longest chain of callbacks after synchronization begins.

Because of all of this, we can now load LSMs at runtime, so those APIs
are exposed. It is up to the module author to check if
CONFIG_SECURITY_WRITABLE_HOOKS is enabled prior to trying to load.

Thanks to Casey to providing great feedback on the patchset.

Changes since:
v3:
* Instead of taking the approach of a "null hook", using the approach of
a second set of hooks -- this was mostly done through the
FOR_EACH_SECURITY_HOOK_MUTABLE macro, which gets compiled out if
CONFIG_SECURITY_WRITABLE_HOOKS is disabled.
v2:
* Split out hlist_head patch
* Apply Tetsuo's changes to clean up functions which are not
covered by call_int_hook / call_void_hook
* Disable NULL hook checking when uneeded
v1:
* Add SRCU to allow for code-unloading
* Add concurrency control around hook mutation


Sargun Dhillon (1):
security: Add mechanism to safely (un)load LSMs after boot time

include/linux/lsm_hooks.h | 24 +--
security/Kconfig | 2 +-
security/security.c | 206 ++++++++++++++++++---
security/selinux/hooks.c | 451 ++++++++++++++++++++++++----------------------
4 files changed, 424 insertions(+), 259 deletions(-)

--
2.14.1



2018-04-01 05:44:34

by Sargun Dhillon

[permalink] [raw]
Subject: [PATCH v4 1/1] security: Add mechanism to safely (un)load LSMs after boot time

This patch introduces a mechanism to add mutable hooks and immutable
hooks to the callback chain. It adds an intermediary item to the
chain which separates mutable and immutable hooks. Immutable hooks
are then marked as read-only, as well as the hook heads. This does
not preclude some hooks being able to be mutated (removed).

It also wraps the hook unloading, and execution with an SRCU. One
SRCU is used across all hooks, as the SRCU struct can be memory
intensive, and hook execution time in general should be relatively
short.

Signed-off-by: Sargun Dhillon <[email protected]>
Signed-off-by: Tetsuo Handa <[email protected]>
---
include/linux/lsm_hooks.h | 24 +--
security/Kconfig | 2 +-
security/security.c | 206 ++++++++++++++++++---
security/selinux/hooks.c | 451 ++++++++++++++++++++++++----------------------
4 files changed, 424 insertions(+), 259 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index fbd50fd9e687..29787548c75b 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -78,14 +78,18 @@ struct security_hook_list {
*/
#define LSM_HOOK_INIT(HEAD, HOOK) \
{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
-
extern struct security_hook_heads security_hook_heads;
extern char *lsm_names;

extern void security_add_hooks(struct security_hook_list *hooks, int count,
char *lsm);

-#ifdef CONFIG_SECURITY_SELINUX_DISABLE
+#define __lsm_ro_after_init __ro_after_init
+/* Currently required to handle SELinux runtime hook disable. */
+#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
+#define LSM_HOOK_INIT_MUTABLE(HEAD, HOOK) \
+ { .head = &security_hook_heads_mutable.HEAD, .hook = { .HEAD = HOOK } }
+extern struct security_hook_heads security_hook_heads_mutable;
/*
* Assuring the safety of deleting a security module is up to
* the security module involved. This may entail ordering the
@@ -98,21 +102,7 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count,
* 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++)
- hlist_del_rcu(&hooks[i].list);
-}
-#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
-
-/* Currently required to handle SELinux runtime hook disable. */
-#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
-#define __lsm_ro_after_init
-#else
-#define __lsm_ro_after_init __ro_after_init
+extern void security_delete_hooks(struct security_hook_list *hooks, int count);
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */

extern int __init security_module_enable(const char *module);
diff --git a/security/Kconfig b/security/Kconfig
index c4302067a3ad..a3b8b1142e6f 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -32,7 +32,7 @@ config SECURITY
If you are unsure how to answer this question, answer N.

config SECURITY_WRITABLE_HOOKS
- depends on SECURITY
+ depends on SECURITY && SRCU
bool
default n

diff --git a/security/security.c b/security/security.c
index 04b0b8ce6c00..e3ca80ed763b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -29,6 +29,11 @@
#include <linux/backing-dev.h>
#include <linux/string.h>
#include <net/flow.h>
+#include <linux/srcu.h>
+#include <linux/mutex.h>
+
+#define SECURITY_HOOK_COUNT \
+ (sizeof(security_hook_heads) / sizeof(struct hlist_head))

#define MAX_LSM_EVM_XATTR 2

@@ -36,7 +41,9 @@
#define SECURITY_NAME_MAX 10

struct security_hook_heads security_hook_heads __lsm_ro_after_init;
+
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
+static DEFINE_MUTEX(security_hook_mutex);

char *lsm_names;
/* Boot-time LSM user choice */
@@ -52,6 +59,59 @@ static void __init do_security_initcalls(void)
call++;
}
}
+#define FOR_EACH_SECURITY_HOOK(ITERATOR, HEAD) \
+ hlist_for_each_entry(ITERATOR, &security_hook_heads.HEAD, list)
+
+#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
+/*
+ * If mutable security hooks are enables, it exposes a second set of
+ * security_hook_heads. These security_hook_heads will only be executed
+ * if all immutable hooks are executed.
+ */
+struct security_hook_heads security_hook_heads_mutable;
+EXPORT_SYMBOL_GPL(security_hook_heads_mutable);
+DEFINE_STATIC_SRCU(security_hook_srcu);
+
+static inline int lock_lsm(void)
+{
+ return srcu_read_lock(&security_hook_srcu);
+}
+
+static inline void unlock_lsm(int idx)
+{
+ srcu_read_unlock(&security_hook_srcu, idx);
+}
+
+void security_delete_hooks(struct security_hook_list *hooks, int count)
+{
+ int i;
+
+ mutex_lock(&security_hook_mutex);
+ for (i = 0; i < count; i++)
+ hlist_del_rcu(&hooks[i].list);
+ mutex_unlock(&security_hook_mutex);
+
+ synchronize_srcu(&security_hook_srcu);
+}
+EXPORT_SYMBOL_GPL(security_delete_hooks);
+
+#define FOR_EACH_SECURITY_HOOK_MUTABLE(ITERATOR, HEAD) \
+ hlist_for_each_entry(ITERATOR, &security_hook_heads_mutable.HEAD, list)
+#else
+static inline bool is_null_hook(struct security_hook_list *shl)
+{
+ return false;
+}
+
+static inline int lock_lsm(void)
+{
+ return 0;
+}
+
+static inline void unlock_lsm(int idx) {}
+
+#define FOR_EACH_SECURITY_HOOK_MUTABLE(ITERATOR, HEAD) while (0)
+#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */

/**
* security_init - initializes the security framework
@@ -60,12 +120,6 @@ static void __init do_security_initcalls(void)
*/
int __init security_init(void)
{
- int i;
- struct hlist_head *list = (struct hlist_head *) &security_hook_heads;
-
- for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);
- i++)
- INIT_HLIST_HEAD(&list[i]);
pr_info("Security Framework initialized\n");

/*
@@ -156,18 +210,21 @@ int __init security_module_enable(const char *module)
*
* Each LSM has to register its hooks with the infrastructure.
*/
-void __init security_add_hooks(struct security_hook_list *hooks, int count,
- char *lsm)
+void security_add_hooks(struct security_hook_list *hooks, int count, char *lsm)
{
int i;

+ mutex_lock(&security_hook_mutex);
for (i = 0; i < count; i++) {
hooks[i].lsm = lsm;
hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
}
+ mutex_unlock(&security_hook_mutex);
+
if (lsm_append(lsm, &lsm_names) < 0)
panic("%s - Cannot get early memory.\n", __func__);
}
+EXPORT_SYMBOL_GPL(security_add_hooks);

int call_lsm_notifier(enum lsm_event event, void *data)
{
@@ -200,25 +257,48 @@ EXPORT_SYMBOL(unregister_lsm_notifier);
#define call_void_hook(FUNC, ...) \
do { \
struct security_hook_list *P; \
+ int srcu_idx; \
\
- hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
+ FOR_EACH_SECURITY_HOOK(P, FUNC) \
+ P->hook.FUNC(__VA_ARGS__); \
+ srcu_idx = lock_lsm(); \
+ FOR_EACH_SECURITY_HOOK_MUTABLE(P, FUNC) \
P->hook.FUNC(__VA_ARGS__); \
+ unlock_lsm(srcu_idx); \
} while (0)

-#define call_int_hook(FUNC, IRC, ...) ({ \
+#define call_int_hook2(LABEL, FUNC, IRC, ...) ({ \
int RC = IRC; \
+ \
do { \
struct security_hook_list *P; \
+ int srcu_idx; \
\
- hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \
+ FOR_EACH_SECURITY_HOOK(P, FUNC) { \
+ RC = P->hook.FUNC(__VA_ARGS__); \
+ if (RC != 0) \
+ goto LABEL; \
+ } \
+ srcu_idx = lock_lsm(); \
+ FOR_EACH_SECURITY_HOOK_MUTABLE(P, FUNC) { \
RC = P->hook.FUNC(__VA_ARGS__); \
if (RC != 0) \
break; \
} \
+ unlock_lsm(srcu_idx); \
} while (0); \
+LABEL: \
RC; \
})

+/*
+ * The label for each instance of call_int_hook as it can be
+ * invoked multiple times in a single function definition.
+ */
+#define call_int_hook(FUNC, IRC, ...) \
+ call_int_hook2(__UNIQUE_ID(FUNC), FUNC, IRC, __VA_ARGS__)
+
+
/* Security operations */

int security_binder_set_context_mgr(struct task_struct *mgr)
@@ -308,6 +388,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
{
struct security_hook_list *hp;
int cap_sys_admin = 1;
+ int srcu_idx;
int rc;

/*
@@ -317,13 +398,25 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
* agree that it should be set it will. If any module
* thinks it should not be set it won't.
*/
- hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) {
+ FOR_EACH_SECURITY_HOOK(hp, vm_enough_memory) {
+ rc = hp->hook.vm_enough_memory(mm, pages);
+ if (rc <= 0) {
+ cap_sys_admin = 0;
+ goto out;
+ }
+ }
+
+ srcu_idx = lock_lsm();
+ FOR_EACH_SECURITY_HOOK_MUTABLE(hp, vm_enough_memory) {
rc = hp->hook.vm_enough_memory(mm, pages);
if (rc <= 0) {
cap_sys_admin = 0;
break;
}
}
+ unlock_lsm(srcu_idx);
+
+out:
return __vm_enough_memory(mm, pages, cap_sys_admin);
}

@@ -795,43 +888,71 @@ int security_inode_killpriv(struct dentry *dentry)
return call_int_hook(inode_killpriv, 0, dentry);
}

-int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
+int security_inode_getsecurity(struct inode *inode, const char *name,
+ void **buffer, bool alloc)
{
struct security_hook_list *hp;
- int rc;
+ int rc = -EOPNOTSUPP;
+ int srcu_idx;

if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
/*
* Only one module will provide an attribute with a given name.
*/
- hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) {
+ FOR_EACH_SECURITY_HOOK(hp, inode_getsecurity) {
rc = hp->hook.inode_getsecurity(inode, name, buffer, alloc);
if (rc != -EOPNOTSUPP)
- return rc;
+ goto out;
}
- return -EOPNOTSUPP;
+
+ srcu_idx = lock_lsm();
+ FOR_EACH_SECURITY_HOOK_MUTABLE(hp, inode_getsecurity) {
+ rc = hp->hook.inode_getsecurity(inode, name, buffer, alloc);
+ if (rc != -EOPNOTSUPP)
+ break;
+ }
+ unlock_lsm(srcu_idx);
+
+out:
+ return rc;
}

-int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
+int security_inode_setsecurity(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
{
struct security_hook_list *hp;
- int rc;
+ int rc = -EOPNOTSUPP;
+ int srcu_idx;

if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
/*
* Only one module will provide an attribute with a given name.
*/
- hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) {
+
+ FOR_EACH_SECURITY_HOOK(hp, inode_setsecurity) {
rc = hp->hook.inode_setsecurity(inode, name, value, size,
- flags);
+ flags);
if (rc != -EOPNOTSUPP)
- return rc;
+ goto out;
}
- return -EOPNOTSUPP;
+
+ srcu_idx = lock_lsm();
+ FOR_EACH_SECURITY_HOOK_MUTABLE(hp, inode_setsecurity) {
+ rc = hp->hook.inode_setsecurity(inode, name, value, size,
+ flags);
+ if (rc != -EOPNOTSUPP)
+ break;
+ }
+ unlock_lsm(srcu_idx);
+
+out:
+ return rc;
}

+
+
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{
if (unlikely(IS_PRIVATE(inode)))
@@ -1120,13 +1241,26 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
}

int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5)
+ unsigned long arg4, unsigned long arg5)
{
int thisrc;
int rc = -ENOSYS;
struct security_hook_list *hp;
+ int srcu_idx;
+
+
+ FOR_EACH_SECURITY_HOOK(hp, task_prctl) {
+ thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5);
+ if (thisrc != -ENOSYS) {
+ rc = thisrc;
+ if (thisrc != 0)
+ goto out;
+ }
+
+ }

- hlist_for_each_entry(hp, &security_hook_heads.task_prctl, list) {
+ srcu_idx = lock_lsm();
+ FOR_EACH_SECURITY_HOOK_MUTABLE(hp, task_prctl) {
thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5);
if (thisrc != -ENOSYS) {
rc = thisrc;
@@ -1134,6 +1268,9 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
break;
}
}
+ unlock_lsm(srcu_idx);
+
+out:
return rc;
}

@@ -1614,10 +1751,11 @@ int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
}

int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
- struct xfrm_policy *xp,
- const struct flowi *fl)
+ struct xfrm_policy *xp,
+ const struct flowi *fl)
{
struct security_hook_list *hp;
+ int srcu_idx;
int rc = 1;

/*
@@ -1629,11 +1767,21 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
* For speed optimization, we explicitly break the loop rather than
* using the macro
*/
- hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match,
- list) {
+
+
+ FOR_EACH_SECURITY_HOOK(hp, xfrm_state_pol_flow_match) {
+ rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
+ goto out;
+ }
+
+ srcu_idx = lock_lsm();
+ FOR_EACH_SECURITY_HOOK_MUTABLE(hp, xfrm_state_pol_flow_match) {
rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
break;
}
+ unlock_lsm(srcu_idx);
+
+out:
return rc;
}

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8644d864e3c1..33e939d76e15 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6393,234 +6393,260 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif

-static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
- 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),
- LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
-
- LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
- LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
- LSM_HOOK_INIT(capget, selinux_capget),
- LSM_HOOK_INIT(capset, selinux_capset),
- LSM_HOOK_INIT(capable, selinux_capable),
- LSM_HOOK_INIT(quotactl, selinux_quotactl),
- LSM_HOOK_INIT(quota_on, selinux_quota_on),
- LSM_HOOK_INIT(syslog, selinux_syslog),
- LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
-
- LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
-
- LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
- LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
- LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
-
- LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
- LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
- LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
- LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
- LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
- LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
- LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
- LSM_HOOK_INIT(sb_mount, selinux_mount),
- LSM_HOOK_INIT(sb_umount, selinux_umount),
- LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
- LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
- LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),
-
- LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
- LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
-
- LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
- LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
- LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
- LSM_HOOK_INIT(inode_create, selinux_inode_create),
- LSM_HOOK_INIT(inode_link, selinux_inode_link),
- LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
- LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
- LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
- LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
- LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
- LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
- LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
- LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
- LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
- LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
- LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
- LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
- LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
- LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
- LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
- LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
- LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
- LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
- LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
- LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
- LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
- LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
-
- LSM_HOOK_INIT(file_permission, selinux_file_permission),
- LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
- LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
- LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
- LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
- LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
- LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
- LSM_HOOK_INIT(file_lock, selinux_file_lock),
- LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
- LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
- LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
- LSM_HOOK_INIT(file_receive, selinux_file_receive),
-
- LSM_HOOK_INIT(file_open, selinux_file_open),
-
- LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
- LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
- LSM_HOOK_INIT(cred_free, selinux_cred_free),
- LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
- LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
- LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
- LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
- LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
- LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
- LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
- LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
- LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
- LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
- LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
- LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
- LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
- LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit),
- LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
- LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
- LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
- LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
- LSM_HOOK_INIT(task_kill, selinux_task_kill),
- LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
-
- LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
- LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
-
- LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
- LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
-
- LSM_HOOK_INIT(msg_queue_alloc_security,
+#ifdef CONFIG_SECURITY_SELINUX_DISABLE
+#define __selinux_ro_after_init
+#define SELINUX_HOOK_INIT LSM_HOOK_INIT_MUTABLE
+#else
+#define __selinux_ro_after_init __lsm_ro_after_init
+#define SELINUX_HOOK_INIT LSM_HOOK_INIT
+#endif
+
+static struct security_hook_list selinux_hooks[] __selinux_ro_after_init = {
+ SELINUX_HOOK_INIT(binder_set_context_mgr,
+ selinux_binder_set_context_mgr),
+ SELINUX_HOOK_INIT(binder_transaction, selinux_binder_transaction),
+ SELINUX_HOOK_INIT(binder_transfer_binder,
+ selinux_binder_transfer_binder),
+ SELINUX_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
+
+ SELINUX_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
+ SELINUX_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
+ SELINUX_HOOK_INIT(capget, selinux_capget),
+ SELINUX_HOOK_INIT(capset, selinux_capset),
+ SELINUX_HOOK_INIT(capable, selinux_capable),
+ SELINUX_HOOK_INIT(quotactl, selinux_quotactl),
+ SELINUX_HOOK_INIT(quota_on, selinux_quota_on),
+ SELINUX_HOOK_INIT(syslog, selinux_syslog),
+ SELINUX_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
+
+ SELINUX_HOOK_INIT(netlink_send, selinux_netlink_send),
+
+ SELINUX_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
+ SELINUX_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
+ SELINUX_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
+
+ SELINUX_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
+ SELINUX_HOOK_INIT(sb_free_security, selinux_sb_free_security),
+ SELINUX_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
+ SELINUX_HOOK_INIT(sb_remount, selinux_sb_remount),
+ SELINUX_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
+ SELINUX_HOOK_INIT(sb_show_options, selinux_sb_show_options),
+ SELINUX_HOOK_INIT(sb_statfs, selinux_sb_statfs),
+ SELINUX_HOOK_INIT(sb_mount, selinux_mount),
+ SELINUX_HOOK_INIT(sb_umount, selinux_umount),
+ SELINUX_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
+ SELINUX_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
+ SELINUX_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),
+
+ SELINUX_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
+ SELINUX_HOOK_INIT(dentry_create_files_as,
+ selinux_dentry_create_files_as),
+
+ SELINUX_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
+ SELINUX_HOOK_INIT(inode_free_security, selinux_inode_free_security),
+ SELINUX_HOOK_INIT(inode_init_security, selinux_inode_init_security),
+ SELINUX_HOOK_INIT(inode_create, selinux_inode_create),
+ SELINUX_HOOK_INIT(inode_link, selinux_inode_link),
+ SELINUX_HOOK_INIT(inode_unlink, selinux_inode_unlink),
+ SELINUX_HOOK_INIT(inode_symlink, selinux_inode_symlink),
+ SELINUX_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
+ SELINUX_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
+ SELINUX_HOOK_INIT(inode_mknod, selinux_inode_mknod),
+ SELINUX_HOOK_INIT(inode_rename, selinux_inode_rename),
+ SELINUX_HOOK_INIT(inode_readlink, selinux_inode_readlink),
+ SELINUX_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
+ SELINUX_HOOK_INIT(inode_permission, selinux_inode_permission),
+ SELINUX_HOOK_INIT(inode_setattr, selinux_inode_setattr),
+ SELINUX_HOOK_INIT(inode_getattr, selinux_inode_getattr),
+ SELINUX_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
+ SELINUX_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
+ SELINUX_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
+ SELINUX_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
+ SELINUX_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
+ SELINUX_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
+ SELINUX_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
+ SELINUX_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
+ SELINUX_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+ SELINUX_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
+ SELINUX_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
+
+ SELINUX_HOOK_INIT(file_permission, selinux_file_permission),
+ SELINUX_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
+ SELINUX_HOOK_INIT(file_free_security, selinux_file_free_security),
+ SELINUX_HOOK_INIT(file_ioctl, selinux_file_ioctl),
+ SELINUX_HOOK_INIT(mmap_file, selinux_mmap_file),
+ SELINUX_HOOK_INIT(mmap_addr, selinux_mmap_addr),
+ SELINUX_HOOK_INIT(file_mprotect, selinux_file_mprotect),
+ SELINUX_HOOK_INIT(file_lock, selinux_file_lock),
+ SELINUX_HOOK_INIT(file_fcntl, selinux_file_fcntl),
+ SELINUX_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
+ SELINUX_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
+ SELINUX_HOOK_INIT(file_receive, selinux_file_receive),
+
+ SELINUX_HOOK_INIT(file_open, selinux_file_open),
+
+ SELINUX_HOOK_INIT(task_alloc, selinux_task_alloc),
+ SELINUX_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
+ SELINUX_HOOK_INIT(cred_free, selinux_cred_free),
+ SELINUX_HOOK_INIT(cred_prepare, selinux_cred_prepare),
+ SELINUX_HOOK_INIT(cred_transfer, selinux_cred_transfer),
+ SELINUX_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
+ SELINUX_HOOK_INIT(kernel_create_files_as,
+ selinux_kernel_create_files_as),
+ SELINUX_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
+ SELINUX_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
+ SELINUX_HOOK_INIT(task_setpgid, selinux_task_setpgid),
+ SELINUX_HOOK_INIT(task_getpgid, selinux_task_getpgid),
+ SELINUX_HOOK_INIT(task_getsid, selinux_task_getsid),
+ SELINUX_HOOK_INIT(task_getsecid, selinux_task_getsecid),
+ SELINUX_HOOK_INIT(task_setnice, selinux_task_setnice),
+ SELINUX_HOOK_INIT(task_setioprio, selinux_task_setioprio),
+ SELINUX_HOOK_INIT(task_getioprio, selinux_task_getioprio),
+ SELINUX_HOOK_INIT(task_prlimit, selinux_task_prlimit),
+ SELINUX_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
+ SELINUX_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
+ SELINUX_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
+ SELINUX_HOOK_INIT(task_movememory, selinux_task_movememory),
+ SELINUX_HOOK_INIT(task_kill, selinux_task_kill),
+ SELINUX_HOOK_INIT(task_to_inode, selinux_task_to_inode),
+
+ SELINUX_HOOK_INIT(ipc_permission, selinux_ipc_permission),
+ SELINUX_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
+
+ SELINUX_HOOK_INIT(msg_msg_alloc_security,
+ selinux_msg_msg_alloc_security),
+ SELINUX_HOOK_INIT(msg_msg_free_security,
+ selinux_msg_msg_free_security),
+
+ SELINUX_HOOK_INIT(msg_queue_alloc_security,
selinux_msg_queue_alloc_security),
- LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
- LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
- LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
- LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
- LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
-
- LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
- LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
- LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
- LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
- LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
-
- LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
- LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
- LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
- LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
- LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
-
- LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
-
- LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
- LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
-
- LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
- LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
- LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
- LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
- LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
- LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
- LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
- LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
-
- LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
- LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
-
- LSM_HOOK_INIT(socket_create, selinux_socket_create),
- LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
- LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
- LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
- LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
- LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
- LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
- LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
- LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
- LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
- LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
- LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
- LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
- LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
- LSM_HOOK_INIT(socket_getpeersec_stream,
+ SELINUX_HOOK_INIT(msg_queue_free_security,
+ selinux_msg_queue_free_security),
+ SELINUX_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
+ SELINUX_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
+ SELINUX_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
+ SELINUX_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
+
+ SELINUX_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
+ SELINUX_HOOK_INIT(shm_free_security, selinux_shm_free_security),
+ SELINUX_HOOK_INIT(shm_associate, selinux_shm_associate),
+ SELINUX_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
+ SELINUX_HOOK_INIT(shm_shmat, selinux_shm_shmat),
+
+ SELINUX_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
+ SELINUX_HOOK_INIT(sem_free_security, selinux_sem_free_security),
+ SELINUX_HOOK_INIT(sem_associate, selinux_sem_associate),
+ SELINUX_HOOK_INIT(sem_semctl, selinux_sem_semctl),
+ SELINUX_HOOK_INIT(sem_semop, selinux_sem_semop),
+
+ SELINUX_HOOK_INIT(d_instantiate, selinux_d_instantiate),
+
+ SELINUX_HOOK_INIT(getprocattr, selinux_getprocattr),
+ SELINUX_HOOK_INIT(setprocattr, selinux_setprocattr),
+
+ SELINUX_HOOK_INIT(ismaclabel, selinux_ismaclabel),
+ SELINUX_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
+ SELINUX_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
+ SELINUX_HOOK_INIT(release_secctx, selinux_release_secctx),
+ SELINUX_HOOK_INIT(inode_invalidate_secctx,
+ selinux_inode_invalidate_secctx),
+ SELINUX_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
+ SELINUX_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
+ SELINUX_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
+
+ SELINUX_HOOK_INIT(unix_stream_connect,
+ selinux_socket_unix_stream_connect),
+ SELINUX_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
+
+ SELINUX_HOOK_INIT(socket_create, selinux_socket_create),
+ SELINUX_HOOK_INIT(socket_post_create, selinux_socket_post_create),
+ SELINUX_HOOK_INIT(socket_bind, selinux_socket_bind),
+ SELINUX_HOOK_INIT(socket_connect, selinux_socket_connect),
+ SELINUX_HOOK_INIT(socket_listen, selinux_socket_listen),
+ SELINUX_HOOK_INIT(socket_accept, selinux_socket_accept),
+ SELINUX_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
+ SELINUX_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
+ SELINUX_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
+ SELINUX_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
+ SELINUX_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
+ SELINUX_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
+ SELINUX_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
+ SELINUX_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
+ SELINUX_HOOK_INIT(socket_getpeersec_stream,
selinux_socket_getpeersec_stream),
- LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
- LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
- LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
- LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
- LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
- LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
- LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
- LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
- LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
- LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
- LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
- LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
- LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
- LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
- LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
- LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
- LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
- LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
- LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
+ SELINUX_HOOK_INIT(socket_getpeersec_dgram,
+ selinux_socket_getpeersec_dgram),
+ SELINUX_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
+ SELINUX_HOOK_INIT(sk_free_security, selinux_sk_free_security),
+ SELINUX_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
+ SELINUX_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
+ SELINUX_HOOK_INIT(sock_graft, selinux_sock_graft),
+ SELINUX_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
+ SELINUX_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
+ SELINUX_HOOK_INIT(inet_conn_established,
+ selinux_inet_conn_established),
+ SELINUX_HOOK_INIT(secmark_relabel_packet,
+ selinux_secmark_relabel_packet),
+ SELINUX_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
+ SELINUX_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
+ SELINUX_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
+ SELINUX_HOOK_INIT(tun_dev_alloc_security,
+ selinux_tun_dev_alloc_security),
+ SELINUX_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
+ SELINUX_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
+ SELINUX_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
+ SELINUX_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
+ SELINUX_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
#ifdef CONFIG_SECURITY_INFINIBAND
- LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
- LSM_HOOK_INIT(ib_endport_manage_subnet,
+ SELINUX_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
+ SELINUX_HOOK_INIT(ib_endport_manage_subnet,
selinux_ib_endport_manage_subnet),
- LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
- LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
+ SELINUX_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
+ SELINUX_HOOK_INIT(ib_free_security, selinux_ib_free_security),
#endif
#ifdef CONFIG_SECURITY_NETWORK_XFRM
- LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
- LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
- LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
- LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
- LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
- LSM_HOOK_INIT(xfrm_state_alloc_acquire,
+ SELINUX_HOOK_INIT(xfrm_policy_alloc_security,
+ selinux_xfrm_policy_alloc),
+ SELINUX_HOOK_INIT(xfrm_policy_clone_security,
+ selinux_xfrm_policy_clone),
+ SELINUX_HOOK_INIT(xfrm_policy_free_security,
+ selinux_xfrm_policy_free),
+ SELINUX_HOOK_INIT(xfrm_policy_delete_security,
+ selinux_xfrm_policy_delete),
+ SELINUX_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
+ SELINUX_HOOK_INIT(xfrm_state_alloc_acquire,
selinux_xfrm_state_alloc_acquire),
- LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
- LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
- LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
- LSM_HOOK_INIT(xfrm_state_pol_flow_match,
+ SELINUX_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
+ SELINUX_HOOK_INIT(xfrm_state_delete_security,
+ selinux_xfrm_state_delete),
+ SELINUX_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
+ SELINUX_HOOK_INIT(xfrm_state_pol_flow_match,
selinux_xfrm_state_pol_flow_match),
- LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
+ SELINUX_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
#endif

#ifdef CONFIG_KEYS
- LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
- LSM_HOOK_INIT(key_free, selinux_key_free),
- LSM_HOOK_INIT(key_permission, selinux_key_permission),
- LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
+ SELINUX_HOOK_INIT(key_alloc, selinux_key_alloc),
+ SELINUX_HOOK_INIT(key_free, selinux_key_free),
+ SELINUX_HOOK_INIT(key_permission, selinux_key_permission),
+ SELINUX_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#endif

#ifdef CONFIG_AUDIT
- LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
- LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
- LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
- LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
+ SELINUX_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
+ SELINUX_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
+ SELINUX_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
+ SELINUX_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
#endif

#ifdef CONFIG_BPF_SYSCALL
- LSM_HOOK_INIT(bpf, selinux_bpf),
- LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
- LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
- LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
- LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
- LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
- LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+ SELINUX_HOOK_INIT(bpf, selinux_bpf),
+ SELINUX_HOOK_INIT(bpf_map, selinux_bpf_map),
+ SELINUX_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+ SELINUX_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+ SELINUX_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+ SELINUX_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+ SELINUX_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
#endif
};

@@ -6651,7 +6677,8 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();

- security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
+ security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
+ "selinux");

if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n");
--
2.14.1


2018-04-05 09:58:27

by Igor Stoppa

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On 01/04/18 08:41, Sargun Dhillon wrote:
> The biggest security benefit of this patchset is the introduction of
> read-only hooks, even if some security modules have mutable hooks.
> Currently, if you have any LSMs with mutable hooks it will render all heads, and
> list nodes mutable. These are a prime place to attack, because being able to
> manipulate those hooks is a way to bypass all LSMs easily, and to create a
> persistent, covert channel to intercept nearly all calls.
>
>
> If LSMs have a model to be unloaded, or are compled as modules, they should mark
> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE macro
> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
> chain.


I'd rather consider these types of hooks:

A) hooks that are either const or marked as RO after init

B) hooks that are writable for a short time, long enough to load
additional, non built-in modules, but then get locked down
I provided an example some time ago [1]

C) hooks that are unloadable (and therefore always attackable?)

Maybe type-A could be dropped and used only as type-B, if it's
acceptable that type-A hooks are vulnerable before lock-down of type-B
hooks.

I have some doubts about the usefulness of type-C, though.
The benefit I see htat it brings is that it avoids having to reboot when
a mutable LSM is changed, at the price of leaving it attackable.

Do you have any specific case in mind where this trade-off would be
acceptable?


[1] https://lkml.org/lkml/2017/7/10/403

--
igor

2018-04-05 10:32:53

by Peter Dolding

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]> wrote:
> On 01/04/18 08:41, Sargun Dhillon wrote:
>> The biggest security benefit of this patchset is the introduction of
>> read-only hooks, even if some security modules have mutable hooks.
>> Currently, if you have any LSMs with mutable hooks it will render all heads, and
>> list nodes mutable. These are a prime place to attack, because being able to
>> manipulate those hooks is a way to bypass all LSMs easily, and to create a
>> persistent, covert channel to intercept nearly all calls.
>>
>>
>> If LSMs have a model to be unloaded, or are compled as modules, they should mark
>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE macro
>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
>> chain.
>
>
> I'd rather consider these types of hooks:
>
> A) hooks that are either const or marked as RO after init
>
> B) hooks that are writable for a short time, long enough to load
> additional, non built-in modules, but then get locked down
> I provided an example some time ago [1]
>
> C) hooks that are unloadable (and therefore always attackable?)
>
> Maybe type-A could be dropped and used only as type-B, if it's
> acceptable that type-A hooks are vulnerable before lock-down of type-B
> hooks.
>
> I have some doubts about the usefulness of type-C, though.
> The benefit I see htat it brings is that it avoids having to reboot when
> a mutable LSM is changed, at the price of leaving it attackable.
>
> Do you have any specific case in mind where this trade-off would be
> acceptable?
>

A useful case for loadable/unloadable LSM is development automate QA.

So you have built a new program and you you want to test it against a
list of different LSM configurations without having to reboot the
system. So a run testsuite with LSM off then enabled LSM1 run
testsuite again disable LSM1 enable LSM2. run testsuite disable
LSM2... Basically repeating process.

I would say normal production machines being able to swap LSM like
this does not have much use.

Sometimes for productivity it makes sense to be able to breach
security. The fact you need to test with LSM disabled to know if any
of the defects you are seeing is LSM configuration related that
instance is already in the camp of non secure anyhow..

There is a shade of grey between something being a security hazard and
something being a useful feature.

If development people are not testing that LSM configuration are clean
because they don't really have enough machined to boot up individual
instances with each LSM and this results in broken LSM configuration
being shipped resulting in end users turning LSM off completely.
Then a little security risk from providing unload-able LSM hooks when
particularly requested is not that high really.

With all the different LSM options how do application/distribution
makers validate all the different LSM configurations effectively is a
question that does need to be answered. In answering this question
allowing this form of compromised security as a option might be quite
a valid move.

Peter Dolding

2018-04-05 11:36:12

by Igor Stoppa

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks



On 05/04/18 13:31, Peter Dolding wrote:
> On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]> wrote:

[...]

>> A) hooks that are either const or marked as RO after init
>>
>> B) hooks that are writable for a short time, long enough to load
>> additional, non built-in modules, but then get locked down
>> I provided an example some time ago [1]
>>
>> C) hooks that are unloadable (and therefore always attackable?)

[...]

>> Do you have any specific case in mind where this trade-off would be
>> acceptable?
>>
>
> A useful case for loadable/unloadable LSM is development automate QA.

I did not consider this case, but I see the point.

[...]

> I would say normal production machines being able to swap LSM like
> this does not have much use.

yes, this is what I had in mind

[...]

> There is a shade of grey between something being a security hazard and
> something being a useful feature.

Maybe the problem I see is only in the naming: if what right now is
addressed as "mutable" were to be called in some other way that does not
imply that it's impossible to lock it down, then I think there wouldn't
be much of a problem anymore.

How about s/mutable/protectable/g ?

Then it could be a boot time parameter to decide if the "extra" hooks
should be protected or stay writable, for example for performing more
extensive testing.

--
igor

2018-04-05 12:29:57

by Peter Dolding

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On Thu, Apr 5, 2018 at 9:34 PM, Igor Stoppa <[email protected]> wrote:
> On 05/04/18 13:31, Peter Dolding wrote:
>> On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]> wrote:
>> There is a shade of grey between something being a security hazard and
>> something being a useful feature.
>
> Maybe the problem I see is only in the naming: if what right now is
> addressed as "mutable" were to be called in some other way that does not
> imply that it's impossible to lock it down, then I think there wouldn't
> be much of a problem anymore.
>
> How about s/mutable/protectable/g ?
>
> Then it could be a boot time parameter to decide if the "extra" hooks
> should be protected or stay writable, for example for performing more
> extensive testing.
>
Due to being a shades of grey area I would say kconfig 2 option and 1
boot time parameter.

Some kernels the ability to change LSM on fly should be fully disabled
in the build process.

The abplity to change LSM at runtime has limited valid usage cases so
even if the kernel is built with the ablity to change LSM at runtime
enabled it should still be off by default until enabled with boot time
parameter. So those who need the feature turn it on and those who
don't need it on cannot turn it on just by installing a kernel. For
systems that cannot use Linux kernel command line features to turn
stuff on and off a kernel configuration option to change the default
to on with warning in kernel configure. So 2 kconfig entries and 1
Kernel Boot Parameter. Of course when a feature like this is enabled
there should be a kernel message so its recorded in logs and is check
able if a feature like this that can lower security is turn on.

The ability to change LSM on fly i see the development usage cases.
I can not think of a single production system usage case for anyone
who is not a developer. I might be thinking way to narrow. Unless
someone else can find another use case I would suggest following what
I suggest how a feature like this is enabled.

Naming the feature what ever you think is suitable.

Peter Dolding

2018-04-05 16:31:56

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On 4/5/2018 3:31 AM, Peter Dolding wrote:
> On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]> wrote:
>> On 01/04/18 08:41, Sargun Dhillon wrote:
>>> The biggest security benefit of this patchset is the introduction of
>>> read-only hooks, even if some security modules have mutable hooks.
>>> Currently, if you have any LSMs with mutable hooks it will render all heads, and
>>> list nodes mutable. These are a prime place to attack, because being able to
>>> manipulate those hooks is a way to bypass all LSMs easily, and to create a
>>> persistent, covert channel to intercept nearly all calls.
>>>
>>>
>>> If LSMs have a model to be unloaded, or are compled as modules, they should mark
>>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE macro
>>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
>>> chain.
>>
>> I'd rather consider these types of hooks:
>>
>> A) hooks that are either const or marked as RO after init
>>
>> B) hooks that are writable for a short time, long enough to load
>> additional, non built-in modules, but then get locked down
>> I provided an example some time ago [1]
>>
>> C) hooks that are unloadable (and therefore always attackable?)
>>
>> Maybe type-A could be dropped and used only as type-B, if it's
>> acceptable that type-A hooks are vulnerable before lock-down of type-B
>> hooks.
>>
>> I have some doubts about the usefulness of type-C, though.
>> The benefit I see htat it brings is that it avoids having to reboot when
>> a mutable LSM is changed, at the price of leaving it attackable.
>>
>> Do you have any specific case in mind where this trade-off would be
>> acceptable?
>>
> A useful case for loadable/unloadable LSM is development automate QA.
>
> So you have built a new program and you you want to test it against a
> list of different LSM configurations without having to reboot the
> system. So a run testsuite with LSM off then enabled LSM1 run
> testsuite again disable LSM1 enable LSM2. run testsuite disable
> LSM2... Basically repeating process.
>
> I would say normal production machines being able to swap LSM like
> this does not have much use.
>
> Sometimes for productivity it makes sense to be able to breach
> security. The fact you need to test with LSM disabled to know if any
> of the defects you are seeing is LSM configuration related that
> instance is already in the camp of non secure anyhow..
>
> There is a shade of grey between something being a security hazard and
> something being a useful feature.

If the only value of a feature is development I strongly
advocate against it. The number of times I've seen things
completely messed up because it makes development easier
is astonishing. If you have to enable something dangerous
just for testing you have to wonder about the testing.



2018-04-06 01:52:18

by Sargun Dhillon

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On Thu, Apr 5, 2018 at 9:29 AM, Casey Schaufler <[email protected]> wrote:
>
> On 4/5/2018 3:31 AM, Peter Dolding wrote:
> > On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]> wrote:
> >> On 01/04/18 08:41, Sargun Dhillon wrote:
> >>> The biggest security benefit of this patchset is the introduction of
> >>> read-only hooks, even if some security modules have mutable hooks.
> >>> Currently, if you have any LSMs with mutable hooks it will render all heads, and
> >>> list nodes mutable. These are a prime place to attack, because being able to
> >>> manipulate those hooks is a way to bypass all LSMs easily, and to create a
> >>> persistent, covert channel to intercept nearly all calls.
> >>>
> >>>
> >>> If LSMs have a model to be unloaded, or are compled as modules, they should mark
> >>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE macro
> >>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
> >>> chain.
> >>
> >> I'd rather consider these types of hooks:
> >>
> >> A) hooks that are either const or marked as RO after init
> >>
> >> B) hooks that are writable for a short time, long enough to load
> >> additional, non built-in modules, but then get locked down
> >> I provided an example some time ago [1]
> >>
> >> C) hooks that are unloadable (and therefore always attackable?)
> >>
> >> Maybe type-A could be dropped and used only as type-B, if it's
> >> acceptable that type-A hooks are vulnerable before lock-down of type-B
> >> hooks.
> >>
> >> I have some doubts about the usefulness of type-C, though.
> >> The benefit I see htat it brings is that it avoids having to reboot when
> >> a mutable LSM is changed, at the price of leaving it attackable.
> >>
> >> Do you have any specific case in mind where this trade-off would be
> >> acceptable?
> >>
> > A useful case for loadable/unloadable LSM is development automate QA.
> >
> > So you have built a new program and you you want to test it against a
> > list of different LSM configurations without having to reboot the
> > system. So a run testsuite with LSM off then enabled LSM1 run
> > testsuite again disable LSM1 enable LSM2. run testsuite disable
> > LSM2... Basically repeating process.
> >
> > I would say normal production machines being able to swap LSM like
> > this does not have much use.
> >
> > Sometimes for productivity it makes sense to be able to breach
> > security. The fact you need to test with LSM disabled to know if any
> > of the defects you are seeing is LSM configuration related that
> > instance is already in the camp of non secure anyhow..
> >
> > There is a shade of grey between something being a security hazard and
> > something being a useful feature.
>
> If the only value of a feature is development I strongly
> advocate against it. The number of times I've seen things
> completely messed up because it makes development easier
> is astonishing. If you have to enable something dangerous
> just for testing you have to wonder about the testing.
>
>
[Sorry for the double post]
So, first, this gives us a security benefit for LSMs which do not have
unloadable hooks. For those, they will always be able to load at
boot-time, and get protected hooks. Given that we can't really remove
security_delete_hooks until this SELinux removes their dependency on
it, I'm not sure we that this happy accident of safe (un)loading
should be sacrificed.

I think having LSMs that are loadable after boot is extremely
valuable. In our specific use case, we've wanted to implement specific
security policies which are not capable of being implemented on the
traditional LSMs. We have the capability of deploying a Linux Kernel
Module throughout our fleet. Recent examples include issues with
specific networking address families, IPTables (over netlink API).
It's not easy to block out RDS across the system while it's running,
even if seccomp can do it.

We have other use cases -- like being able to run systemd in
unprivileged user namespaces. This comes at the cost of giving the
container CAP_SYS_ADMIN. We want to be able to give PID 1 in the user
namespace CAP_SYS_ADMIN, but we want to revoke these capbilities
across execve, without having to control the user's installation of
systemd in their container.

Other times, it's about performance. There is a measureable overhead
with seccomp, and apparmor. LSMs fit better for doing some of the
filtering we're forced to do in seccomp, or apparmor for containers.
The performance gain by implementing purpose-built policies in custom
LSMs is significant.

My suggestion is to change security_delete_hooks() to return -EPERM by
default. Hook unloading can then be disabled by a Kconfig feature. If
we need to get "more secure", we can disable unloading via cmdline, or
proc / securityfs at boot time.

2018-04-06 04:14:53

by Peter Dolding

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On Fri, Apr 6, 2018 at 11:31 AM, Sargun Dhillon <[email protected]> wrote:
>
>
> On Thu, Apr 5, 2018 at 9:29 AM, Casey Schaufler <[email protected]>
> wrote:
>>
>> On 4/5/2018 3:31 AM, Peter Dolding wrote:
>> > On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]>
>> > wrote:
>> >> On 01/04/18 08:41, Sargun Dhillon wrote:
>> >>> The biggest security benefit of this patchset is the introduction of
>> >>> read-only hooks, even if some security modules have mutable hooks.
>> >>> Currently, if you have any LSMs with mutable hooks it will render all
>> >>> heads, and
>> >>> list nodes mutable. These are a prime place to attack, because being
>> >>> able to
>> >>> manipulate those hooks is a way to bypass all LSMs easily, and to
>> >>> create a
>> >>> persistent, covert channel to intercept nearly all calls.
>> >>>
>> >>>
>> >>> If LSMs have a model to be unloaded, or are compled as modules, they
>> >>> should mark
>> >>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE
>> >>> macro
>> >>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
>> >>> chain.
>> >>
>> >> I'd rather consider these types of hooks:
>> >>
>> >> A) hooks that are either const or marked as RO after init
>> >>
>> >> B) hooks that are writable for a short time, long enough to load
>> >> additional, non built-in modules, but then get locked down
>> >> I provided an example some time ago [1]
>> >>
>> >> C) hooks that are unloadable (and therefore always attackable?)
>> >>
>> >> Maybe type-A could be dropped and used only as type-B, if it's
>> >> acceptable that type-A hooks are vulnerable before lock-down of type-B
>> >> hooks.
>> >>
>> >> I have some doubts about the usefulness of type-C, though.
>> >> The benefit I see htat it brings is that it avoids having to reboot
>> >> when
>> >> a mutable LSM is changed, at the price of leaving it attackable.
>> >>
>> >> Do you have any specific case in mind where this trade-off would be
>> >> acceptable?
>> >>
>> > A useful case for loadable/unloadable LSM is development automate QA.
>> >
>> > So you have built a new program and you you want to test it against a
>> > list of different LSM configurations without having to reboot the
>> > system. So a run testsuite with LSM off then enabled LSM1 run
>> > testsuite again disable LSM1 enable LSM2. run testsuite disable
>> > LSM2... Basically repeating process.
>> >
>> > I would say normal production machines being able to swap LSM like
>> > this does not have much use.
>> >
>> > Sometimes for productivity it makes sense to be able to breach
>> > security. The fact you need to test with LSM disabled to know if any
>> > of the defects you are seeing is LSM configuration related that
>> > instance is already in the camp of non secure anyhow..
>> >
>> > There is a shade of grey between something being a security hazard and
>> > something being a useful feature.
>>
>> If the only value of a feature is development I strongly
>> advocate against it. The number of times I've seen things
>> completely messed up because it makes development easier
>> is astonishing. If you have to enable something dangerous
>> just for testing you have to wonder about the testing.
>>
Casey Schaufler we have had different points of view before. I will
point out some serous issues here. If you look a PPA and many other
locations you will find no LSM configuration files.

Majority of QA servers around the place run with LSM off. There is a
practical annoying reason. No point running application with new
code with LSM on at first you run with LSM off to make sure program
works. If program works and you have the resources then transfer to
another machine/reboot to test with LSM this creates a broken
workflow. When customer gets untested LSM configuration files and
they don't work what do support straight up recommend turning the LSM
off.

Reality enabling LSM module loading and unloading on the fly on QA
servers will not change their security 1 bit because they are most
running without LSM at all. Making it simple to implement LSM
configuration testing on QA servers will reduce the number of times
end users at told to turn LSM off on their machines that will effect
over all security.

So we need to make the process of testing LSM configurations against
applications on the QA servers way smoother.

> So, first, this gives us a security benefit for LSMs which do not have
> unloadable hooks. For those, they will always be able to load at boot-time,
> and get protected hooks. Given that we can't really remove
> security_delete_hooks until this SELinux removes their dependency on it, I'm
> not sure we that this happy accident of safe (un)loading should be
> sacrificed.
>
> I think having LSMs that are loadable after boot is extremely valuable. In
> our specific use case, we've wanted to implement specific security policies
> which are not capable of being implemented on the traditional LSMs. We have
> the capability of deploying a Linux Kernel Module throughout our fleet.
> Recent examples include issues with specific networking address families,
> IPTables (over netlink API). It's not easy to block out RDS across the
> system while it's running, even if seccomp can do it.
>
> We have other use cases -- like being able to run systemd in unprivileged
> user namespaces. This comes at the cost of giving the container
> CAP_SYS_ADMIN. We want to be able to give PID 1 in the user namespace
> CAP_SYS_ADMIN, but we want to revoke these capbilities across execve,
> without having to control the user's installation of systemd in their
> container.
>
> Other times, it's about performance. There is a measureable overhead with
> seccomp, and apparmor. LSMs fit better for doing some of the filtering we're
> forced to do in seccomp, or apparmor for containers. The performance gain by
> implementing purpose-built policies in custom LSMs is significant.
>
> My suggestion is to change security_delete_hooks() to return -EPERM by
> default. Hook unloading can then be disabled by a Kconfig feature. If we
> need to get "more secure", we can disable unloading via cmdline, or proc /
> securityfs at boot time.

Yes this is a different usage case there is a peer review issue to it..

https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hooks.h#L1999

Selinux is the only one that allows you to load and unload it on fly.
It also one of the reasons why you have a few applications that ship
with dependable Selinux profiles because they are turning selinux on
and off on the QA servers. If you look at security_delete_hooks()
design if you can or cannot unload a LSM module is purely left to the
security module.

First step make if LSM can be unloaded or not generic including what
LSM set to block unloading.
Second step provide some generic way that can be integrated into test
suites to test LSM configurations.

Sargun Dhillon issue would also partly link to the fact applications
are not tested with more LSM options. So if lets say selinux fits
technically fits use case better and all vendor is providing is
apparmour profiles they are going to be tempted to reinvent the wheel
so it is important to improve testing process.

Even implement a custom hard coded LSM will gain from ability to build
load test unload and be able to repeat cycle in development stage.

We don't have a LSM that takes like apparmour/selinux/seccomp
configuration builds that into a single optimised kernel module.
Most LSM are design around the idea that they need configuration files
when you look at deployed systems you see something. The LSM
configuration files don't get touched for years at time in production
systems. Maybe LSM having to read configuration files is completely
wrong. Maybe the right answer is that configuration files for LSM
should basically be source code to build a module being processed once
run many this would allow a lot more optimisation. Its not like
apparmour/selinux forbid reloading configuration.

With LSM loading and unloading formally allowed there is option to
move to where a LSM can safely hand over control to another LSM
without leaving a unhooked time this would be useful for hard coded
LSM for updating configuration..

Peter Dolding

2018-04-06 16:36:45

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On 4/5/2018 9:12 PM, Peter Dolding wrote:
> On Fri, Apr 6, 2018 at 11:31 AM, Sargun Dhillon <[email protected]> wrote:
>>
>> On Thu, Apr 5, 2018 at 9:29 AM, Casey Schaufler <[email protected]>
>> wrote:
>>> On 4/5/2018 3:31 AM, Peter Dolding wrote:
>>>> On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]>
>>>> wrote:
>>>>> On 01/04/18 08:41, Sargun Dhillon wrote:
>>>>>> The biggest security benefit of this patchset is the introduction of
>>>>>> read-only hooks, even if some security modules have mutable hooks.
>>>>>> Currently, if you have any LSMs with mutable hooks it will render all
>>>>>> heads, and
>>>>>> list nodes mutable. These are a prime place to attack, because being
>>>>>> able to
>>>>>> manipulate those hooks is a way to bypass all LSMs easily, and to
>>>>>> create a
>>>>>> persistent, covert channel to intercept nearly all calls.
>>>>>>
>>>>>>
>>>>>> If LSMs have a model to be unloaded, or are compled as modules, they
>>>>>> should mark
>>>>>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE
>>>>>> macro
>>>>>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
>>>>>> chain.
>>>>> I'd rather consider these types of hooks:
>>>>>
>>>>> A) hooks that are either const or marked as RO after init
>>>>>
>>>>> B) hooks that are writable for a short time, long enough to load
>>>>> additional, non built-in modules, but then get locked down
>>>>> I provided an example some time ago [1]
>>>>>
>>>>> C) hooks that are unloadable (and therefore always attackable?)
>>>>>
>>>>> Maybe type-A could be dropped and used only as type-B, if it's
>>>>> acceptable that type-A hooks are vulnerable before lock-down of type-B
>>>>> hooks.
>>>>>
>>>>> I have some doubts about the usefulness of type-C, though.
>>>>> The benefit I see htat it brings is that it avoids having to reboot
>>>>> when
>>>>> a mutable LSM is changed, at the price of leaving it attackable.
>>>>>
>>>>> Do you have any specific case in mind where this trade-off would be
>>>>> acceptable?
>>>>>
>>>> A useful case for loadable/unloadable LSM is development automate QA.
>>>>
>>>> So you have built a new program and you you want to test it against a
>>>> list of different LSM configurations without having to reboot the
>>>> system. So a run testsuite with LSM off then enabled LSM1 run
>>>> testsuite again disable LSM1 enable LSM2. run testsuite disable
>>>> LSM2... Basically repeating process.
>>>>
>>>> I would say normal production machines being able to swap LSM like
>>>> this does not have much use.
>>>>
>>>> Sometimes for productivity it makes sense to be able to breach
>>>> security. The fact you need to test with LSM disabled to know if any
>>>> of the defects you are seeing is LSM configuration related that
>>>> instance is already in the camp of non secure anyhow..
>>>>
>>>> There is a shade of grey between something being a security hazard and
>>>> something being a useful feature.
>>> If the only value of a feature is development I strongly
>>> advocate against it. The number of times I've seen things
>>> completely messed up because it makes development easier
>>> is astonishing. If you have to enable something dangerous
>>> just for testing you have to wonder about the testing.
>>>
> Casey Schaufler we have had different points of view before.

That's OK. I'm not always right.

> I will
> point out some serous issues here. If you look a PPA

Sorry, my acronym processor was seriously damaged in 1992.
What's "PPA" in this context?

> and many other
> locations you will find no LSM configuration files.
>
> Majority of QA servers around the place run with LSM off. There is a
> practical annoying reason. No point running application with new
> code with LSM on at first you run with LSM off to make sure program
> works.

You're right. We have different points of view.

Can someone tell me why it makes sense to develop a program
that they know is going to run in a secured environment in
an unsecured environment? The fact that it may be easier to
make the program "work" in the unsecured environment is the
reason you should never ever ever EVER do that. All you're
doing is setting up the security to be the bad guy when your
release is late.

> If program works and you have the resources then transfer to
> another machine/reboot to test with LSM this creates a broken
> workflow.

That's right. It's a broken workflow. If you want a program
to work in secured environment it should be developed in that
secured environment. It saves everyone time and effort.
Except for the guy who's all set to blame security for making
the release late.

> When customer gets untested LSM configuration files and
> they don't work what do support straight up recommend turning the LSM
> off.

YES! Your entire workflow is fundamentally flawed.
The fact that the program works as desired running as root
with SELinux in permissive mode is no indication that it
will do so without privilege and/or with SELinux in
enforcing mode. Why would anyone think it would? And yet,
people continue to advocate this completely broken
development mindset. It drives me nuts!

> Reality enabling LSM module loading and unloading on the fly on QA
> servers will not change their security 1 bit because they are most
> running without LSM at all.

More to the point, a QA server is a special case environment,
where you know you're going to be changing all sorts of configuration
on the fly.

> Making it simple to implement LSM
> configuration testing on QA servers will reduce the number of times
> end users at told to turn LSM off on their machines that will effect
> over all security.

Well, fixing the workflow would be the right way to do that.

> So we need to make the process of testing LSM configurations against
> applications on the QA servers way smoother.

Regardless of the workflow argument, this is a worthy goal.

>> So, first, this gives us a security benefit for LSMs which do not have
>> unloadable hooks. For those, they will always be able to load at boot-time,
>> and get protected hooks. Given that we can't really remove
>> security_delete_hooks until this SELinux removes their dependency on it, I'm
>> not sure we that this happy accident of safe (un)loading should be
>> sacrificed.
>>
>> I think having LSMs that are loadable after boot is extremely valuable. In
>> our specific use case, we've wanted to implement specific security policies
>> which are not capable of being implemented on the traditional LSMs. We have
>> the capability of deploying a Linux Kernel Module throughout our fleet.
>> Recent examples include issues with specific networking address families,
>> IPTables (over netlink API). It's not easy to block out RDS across the
>> system while it's running, even if seccomp can do it.
>>
>> We have other use cases -- like being able to run systemd in unprivileged
>> user namespaces. This comes at the cost of giving the container
>> CAP_SYS_ADMIN. We want to be able to give PID 1 in the user namespace
>> CAP_SYS_ADMIN, but we want to revoke these capbilities across execve,
>> without having to control the user's installation of systemd in their
>> container.
>>
>> Other times, it's about performance. There is a measureable overhead with
>> seccomp, and apparmor. LSMs fit better for doing some of the filtering we're
>> forced to do in seccomp, or apparmor for containers. The performance gain by
>> implementing purpose-built policies in custom LSMs is significant.
>>
>> My suggestion is to change security_delete_hooks() to return -EPERM by
>> default. Hook unloading can then be disabled by a Kconfig feature. If we
>> need to get "more secure", we can disable unloading via cmdline, or proc /
>> securityfs at boot time.
> Yes this is a different usage case there is a peer review issue to it..
>
> https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hooks.h#L1999
>
> Selinux is the only one that allows you to load and unload it on fly.

SELinux does not allow you to load "on the fly". SELinux allows you
to unload, but only if policy has never been loaded. The only case
this supports is "I have SELinux installed, but don't want to use it
and can't get to the boot command line to disable it". Removing the
ability to unload SELinux is on the SELinux team's todo list.

> It also one of the reasons why you have a few applications that ship
> with dependable Selinux profiles because they are turning selinux on
> and off on the QA servers. If you look at security_delete_hooks()
> design if you can or cannot unload a LSM module is purely left to the
> security module.

That's right. Only SELinux allows deletion, and only if it's never
been initialized. None of the other security modules saw a need to
provide the facility, and none, SELinux included, can do it once
they've started allocating attribute data.

> First step make if LSM can be unloaded or not generic including what
> LSM set to block unloading.

I suggest that the first step would be to identify how a security
module can ensure that all its state and data can be cleaned up
safely during the removal process.

> Second step provide some generic way that can be integrated into test
> suites to test LSM configurations.

That would be stacked security namespaces.

> Sargun Dhillon issue would also partly link to the fact applications
> are not tested with more LSM options.

These days it seems that few developers even know what file mode bits
do, much less the implications of a security module. If you don't
believe me, ask them what umask is for. Which winds us back to the
workflow issue.

> So if lets say selinux fits
> technically fits use case better and all vendor is providing is
> apparmour profiles they are going to be tempted to reinvent the wheel
> so it is important to improve testing process.

An AppArmor profile to SELinux policy converter program.
There must be some available on NPM. ( - NO! I'm not serious! - )
Although I have had people ask for an SELinux policy to Smack
rule converter.

The point is that if you could do an automatic conversion
there would be no point in having the different security
modules. Which is why I agree with you that testing needs
to be done in the deployment environment.

> Even implement a custom hard coded LSM will gain from ability to build
> load test unload and be able to repeat cycle in development stage.

I agree that would be valuable for the test environment,
but for different reasons.

> We don't have a LSM that takes like apparmour/selinux/seccomp
> configuration builds that into a single optimised kernel module.

I am working on that.

> Most LSM are design around the idea that they need configuration files
> when you look at deployed systems you see something. The LSM
> configuration files don't get touched for years at time in production
> systems. Maybe LSM having to read configuration files is completely
> wrong.

In the 1980's we implemented hard coded policies.
We did Bell & LaPadula sensitivity and Biba integrity.
Nobody liked that (except the US DoD, who only liked it a little)
because it "doesn't meet our security policy". That's why
we have programmable policies.

> Maybe the right answer is that configuration files for LSM
> should basically be source code to build a module being processed once
> run many this would allow a lot more optimisation.

SELinux policy is compiled.

> Its not like
> apparmour/selinux forbid reloading configuration.
>
> With LSM loading and unloading formally allowed there is option to
> move to where a LSM can safely hand over control to another LSM
> without leaving a unhooked time this would be useful for hard coded
> LSM for updating configuration..

I think that what you'd really like is stacked security namespaces.

> Peter Dolding

Thanks for the discussion. I owe you (another?) beer.


2018-04-07 09:30:47

by Peter Dolding

[permalink] [raw]
Subject: Re: [PATCH v4 0/1] Safe LSM (un)loading, and immutable hooks

On Sat, Apr 7, 2018 at 2:31 AM, Casey Schaufler <[email protected]> wrote:
> On 4/5/2018 9:12 PM, Peter Dolding wrote:
>> On Fri, Apr 6, 2018 at 11:31 AM, Sargun Dhillon <[email protected]> wrote:
>>>
>>> On Thu, Apr 5, 2018 at 9:29 AM, Casey Schaufler <[email protected]>
>>> wrote:
>>>> On 4/5/2018 3:31 AM, Peter Dolding wrote:
>>>>> On Thu, Apr 5, 2018 at 7:55 PM, Igor Stoppa <[email protected]>
>>>>> wrote:
>>>>>> On 01/04/18 08:41, Sargun Dhillon wrote:
>>>>>>> The biggest security benefit of this patchset is the introduction of
>>>>>>> read-only hooks, even if some security modules have mutable hooks.
>>>>>>> Currently, if you have any LSMs with mutable hooks it will render all
>>>>>>> heads, and
>>>>>>> list nodes mutable. These are a prime place to attack, because being
>>>>>>> able to
>>>>>>> manipulate those hooks is a way to bypass all LSMs easily, and to
>>>>>>> create a
>>>>>>> persistent, covert channel to intercept nearly all calls.
>>>>>>>
>>>>>>>
>>>>>>> If LSMs have a model to be unloaded, or are compled as modules, they
>>>>>>> should mark
>>>>>>> themselves mutable at compile time, and use the LSM_HOOK_INIT_MUTABLE
>>>>>>> macro
>>>>>>> instead of the LSM_HOOK_INIT macro, so their hooks are on the mutable
>>>>>>> chain.
>>>>>> I'd rather consider these types of hooks:
>>>>>>
>>>>>> A) hooks that are either const or marked as RO after init
>>>>>>
>>>>>> B) hooks that are writable for a short time, long enough to load
>>>>>> additional, non built-in modules, but then get locked down
>>>>>> I provided an example some time ago [1]
>>>>>>
>>>>>> C) hooks that are unloadable (and therefore always attackable?)
>>>>>>
>>>>>> Maybe type-A could be dropped and used only as type-B, if it's
>>>>>> acceptable that type-A hooks are vulnerable before lock-down of type-B
>>>>>> hooks.
>>>>>>
>>>>>> I have some doubts about the usefulness of type-C, though.
>>>>>> The benefit I see htat it brings is that it avoids having to reboot
>>>>>> when
>>>>>> a mutable LSM is changed, at the price of leaving it attackable.
>>>>>>
>>>>>> Do you have any specific case in mind where this trade-off would be
>>>>>> acceptable?
>>>>>>
>>>>> A useful case for loadable/unloadable LSM is development automate QA.
>>>>>
>>>>> So you have built a new program and you you want to test it against a
>>>>> list of different LSM configurations without having to reboot the
>>>>> system. So a run testsuite with LSM off then enabled LSM1 run
>>>>> testsuite again disable LSM1 enable LSM2. run testsuite disable
>>>>> LSM2... Basically repeating process.
>>>>>
>>>>> I would say normal production machines being able to swap LSM like
>>>>> this does not have much use.
>>>>>
>>>>> Sometimes for productivity it makes sense to be able to breach
>>>>> security. The fact you need to test with LSM disabled to know if any
>>>>> of the defects you are seeing is LSM configuration related that
>>>>> instance is already in the camp of non secure anyhow..
>>>>>
>>>>> There is a shade of grey between something being a security hazard and
>>>>> something being a useful feature.
>>>> If the only value of a feature is development I strongly
>>>> advocate against it. The number of times I've seen things
>>>> completely messed up because it makes development easier
>>>> is astonishing. If you have to enable something dangerous
>>>> just for testing you have to wonder about the testing.
>>>>
>> Casey Schaufler we have had different points of view before.
>
> That's OK. I'm not always right.
>
>> I will
>> point out some serous issues here. If you look a PPA
>
> Sorry, my acronym processor was seriously damaged in 1992.
> What's "PPA" in this context?
>

Personal Package Archives the ubuntu term sorry.


>> and many other
>> locations you will find no LSM configuration files.
>>
>> Majority of QA servers around the place run with LSM off. There is a
>> practical annoying reason. No point running application with new
>> code with LSM on at first you run with LSM off to make sure program
>> works.
>
> You're right. We have different points of view.
>
> Can someone tell me why it makes sense to develop a program
> that they know is going to run in a secured environment in
> an unsecured environment? The fact that it may be easier to
> make the program "work" in the unsecured environment is the
> reason you should never ever ever EVER do that. All you're
> doing is setting up the security to be the bad guy when your
> release is late.

it makes sense when you have programs adding features that result in
breaking the security policy. If that patch happens without any LSM
fail conformance suite no point changing the LSM settings.

So lets say you do develop in secured first. New patch fails to
breaking security policy you update policy so that you can run test
suite then you find out in the test suite that the patch does not work
then human error creeps in and you fail to reverse the security policy
change.

There is a very good reason at least on a QA server for the first
past to be without LSM. Failure without LSM active is total failure
reject the patch. If program test suite passes then you active the
LSM and run again what is mostly selinux.

> YES! Your entire workflow is fundamentally flawed.
> The fact that the program works as desired running as root
> with SELinux in permissive mode is no indication that it
> will do so without privilege and/or with SELinux in
> enforcing mode. Why would anyone think it would? And yet,
> people continue to advocate this completely broken
> development mindset. It drives me nuts!

Part of this is how hard it to run a multi test. So start in
permissive mode as root then ren
>
>> Reality enabling LSM module loading and unloading on the fly on QA
>> servers will not change their security 1 bit because they are most
>> running without LSM at all.
>
> More to the point, a QA server is a special case environment,
> where you know you're going to be changing all sorts of configuration
> on the fly.
>
>> Making it simple to implement LSM
>> configuration testing on QA servers will reduce the number of times
>> end users at told to turn LSM off on their machines that will effect
>> over all security.
>
> Well, fixing the workflow would be the right way to do that.
>
>> So we need to make the process of testing LSM configurations against
>> applications on the QA servers way smoother.
>
> Regardless of the workflow argument, this is a worthy goal.
>

>
> SELinux does not allow you to load "on the fly". SELinux allows you
> to unload, but only if policy has never been loaded. The only case
> this supports is "I have SELinux installed, but don't want to use it
> and can't get to the boot command line to disable it". Removing the
> ability to unload SELinux is on the SELinux team's todo list.

Even if you don't unload SELinux you can run you test suite with
SELInux unconfigured then configure SELinix latter.
>
> That's right. Only SELinux allows deletion, and only if it's never
> been initialized. None of the other security modules saw a need to
> provide the facility, and none, SELinux included, can do it once
> they've started allocating attribute data.

Basically this leads you to problem. Person has run 2 tests one
without SELinux enabled with with SELinux enabled then they reboot.
Then don't test any other LSM becuase this can be done in a VM count
of 1. If there is a issue in permissive before selinux is setup you
can unload and run test locating if it linked to SELinux at all.

This workflow is absolutely no use to other LSM modules. This is the
problem you end up with. Each workflow end up per LSM that is not
good.

>> So if lets say selinux fits
>> technically fits use case better and all vendor is providing is
>> apparmour profiles they are going to be tempted to reinvent the wheel
>> so it is important to improve testing process.
>
> An AppArmor profile to SELinux policy converter program.
> There must be some available on NPM. ( - NO! I'm not serious! - )
> Although I have had people ask for an SELinux policy to Smack
> rule converter.
>
> The point is that if you could do an automatic conversion
> there would be no point in having the different security
> modules. Which is why I agree with you that testing needs
> to be done in the deployment environment.

QA server setups can have limited VM instances. This means testing
and maintaining multi LSM security configurations does not happen.
>
>> Even implement a custom hard coded LSM will gain from ability to build
>> load test unload and be able to repeat cycle in development stage.
>
> I agree that would be valuable for the test environment,
> but for different reasons.
>
>> We don't have a LSM that takes like apparmour/selinux/seccomp
>> configuration builds that into a single optimised kernel module.
>
> I am working on that.

Nice look forward to it.
>
>> Most LSM are design around the idea that they need configuration files
>> when you look at deployed systems you see something. The LSM
>> configuration files don't get touched for years at time in production
>> systems. Maybe LSM having to read configuration files is completely
>> wrong.
>
> In the 1980's we implemented hard coded policies.
> We did Bell & LaPadula sensitivity and Biba integrity.
> Nobody liked that (except the US DoD, who only liked it a little)
> because it "doesn't meet our security policy". That's why
> we have programmable policies.

Yes I know about this early stuff. I have a horrible felling we went
the wrong way.

Yes the early hard code policies were a problem because administrators
were not given effective tools to modify them. The we went to
programmable polices that is basically give module bytecode or
something is to process.

There is kind of a half way bit. Where you have like the
programmable policies files as a true compiler acceptable source. So
this is performance vs configuration. Early raw C written polices
where not easy reading.
>
>> Maybe the right answer is that configuration files for LSM
>> should basically be source code to build a module being processed once
>> run many this would allow a lot more optimisation.
>
> SELinux policy is compiled.
>
SELinux policy is like complied python where it converted to a
bytecode then it still interpreted by selinux kernel module. When I
say built to a module I mean built to a real .ko file and able to
perform proper link time optimisation and get it as tight with the
least overhead possible on all the hooks as possible..

>> Its not like
>> apparmour/selinux forbid reloading configuration.
>>
>> With LSM loading and unloading formally allowed there is option to
>> move to where a LSM can safely hand over control to another LSM
>> without leaving a unhooked time this would be useful for hard coded
>> LSM for updating configuration..
>
> I think that what you'd really like is stacked security namespaces.
>
If this will make it possible to have 1 VM instance and build program
test against no LSM and all commonly used LSM with made policies and
generate a report saying this patch works but X Y ans Z LSM policies
need looking at with consideration if this security expand is
acceptable or this patch does not work at all even without LSM so
reject it out right for being totally bad or hopefully just reported
everything works perfectly these are the results I want.

This 1 VM limit is your worst case QA limitation. If we have a test
workflow that is effective with a 1VM it will be hard to justify not
doing it.

It is quite important to know before playing with security policies if
the code works at all this is where the idea of develop in secure
environment for secured environment fails it leads to worse written
security polices as the human errors of policy editing stacks up from
editing where a patch fails due to LSM policy then with modified
policy turns out to fail test suite and then the LSM policy edit does
not end up reversed. So its a important to detect patch is failed as
soon as possible with the least amount of work performed. If
something is modified humans have a bad habit of forgetting reverse
it.

Peter Dolding