1019 lines
29 KiB
Diff
1019 lines
29 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Casey Schaufler <casey@schaufler-ca.com>
|
|
Date: Mon, 27 Aug 2018 15:16:06 -0700
|
|
Subject: [PATCH] LSM: Infrastructure management of the cred security blob
|
|
|
|
Move management of the cred security blob out of the
|
|
security modules and into the security infrastructre.
|
|
Instead of allocating and freeing space the security
|
|
modules tell the infrastructure how much space they
|
|
require.
|
|
|
|
Some SELinux memory management debug code has been removed.
|
|
|
|
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
|
|
---
|
|
include/linux/lsm_hooks.h | 14 ++++
|
|
kernel/cred.c | 13 ----
|
|
security/Kconfig | 11 ++++
|
|
security/apparmor/domain.c | 2 +-
|
|
security/apparmor/include/cred.h | 16 ++++-
|
|
security/apparmor/lsm.c | 28 ++++++--
|
|
security/apparmor/task.c | 6 +-
|
|
security/security.c | 106 +++++++++++++++++++++++++++++-
|
|
security/selinux/hooks.c | 63 +++++-------------
|
|
security/selinux/include/objsec.h | 4 ++
|
|
security/selinux/selinuxfs.c | 1 +
|
|
security/smack/smack.h | 1 +
|
|
security/smack/smack_lsm.c | 85 +++++++++---------------
|
|
security/tomoyo/common.h | 21 +++++-
|
|
security/tomoyo/domain.c | 4 +-
|
|
security/tomoyo/securityfs_if.c | 15 +++--
|
|
security/tomoyo/tomoyo.c | 56 +++++++++++++---
|
|
17 files changed, 303 insertions(+), 143 deletions(-)
|
|
|
|
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
|
|
index 97a020c..0bef312 100644
|
|
--- a/include/linux/lsm_hooks.h
|
|
+++ b/include/linux/lsm_hooks.h
|
|
@@ -2024,6 +2024,13 @@ struct security_hook_list {
|
|
char *lsm;
|
|
} __randomize_layout;
|
|
|
|
+/*
|
|
+ * Security blob size or offset data.
|
|
+ */
|
|
+struct lsm_blob_sizes {
|
|
+ int lbs_cred;
|
|
+};
|
|
+
|
|
/*
|
|
* Initializing a security_hook_list structure takes
|
|
* up a lot of space in a source file. This macro takes
|
|
@@ -2036,6 +2043,7 @@ struct security_hook_list {
|
|
extern struct security_hook_heads security_hook_heads;
|
|
extern char *lsm_names;
|
|
|
|
+extern void security_add_blobs(struct lsm_blob_sizes *needed);
|
|
extern void security_add_hooks(struct security_hook_list *hooks, int count,
|
|
char *lsm);
|
|
|
|
@@ -2082,4 +2090,10 @@ void __init loadpin_add_hooks(void);
|
|
static inline void loadpin_add_hooks(void) { };
|
|
#endif
|
|
|
|
+extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
|
|
+
|
|
+#ifdef CONFIG_SECURITY
|
|
+void lsm_early_cred(struct cred *cred);
|
|
+#endif
|
|
+
|
|
#endif /* ! __LINUX_LSM_HOOKS_H */
|
|
diff --git a/kernel/cred.c b/kernel/cred.c
|
|
index efd04b2..c779d0e 100644
|
|
--- a/kernel/cred.c
|
|
+++ b/kernel/cred.c
|
|
@@ -713,19 +713,6 @@ bool creds_are_invalid(const struct cred *cred)
|
|
{
|
|
if (cred->magic != CRED_MAGIC)
|
|
return true;
|
|
-#ifdef CONFIG_SECURITY_SELINUX
|
|
- /*
|
|
- * cred->security == NULL if security_cred_alloc_blank() or
|
|
- * security_prepare_creds() returned an error.
|
|
- */
|
|
- if (selinux_is_enabled() && cred->security) {
|
|
- if ((unsigned long) cred->security < PAGE_SIZE)
|
|
- return true;
|
|
- if ((*(u32 *)cred->security & 0xffffff00) ==
|
|
- (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
|
|
- return true;
|
|
- }
|
|
-#endif
|
|
return false;
|
|
}
|
|
EXPORT_SYMBOL(creds_are_invalid);
|
|
diff --git a/security/Kconfig b/security/Kconfig
|
|
index d9aa521..0447d9d 100644
|
|
--- a/security/Kconfig
|
|
+++ b/security/Kconfig
|
|
@@ -36,6 +36,17 @@ config SECURITY_WRITABLE_HOOKS
|
|
bool
|
|
default n
|
|
|
|
+config SECURITY_LSM_DEBUG
|
|
+ bool "Enable debugging of the LSM infrastructure"
|
|
+ depends on SECURITY
|
|
+ help
|
|
+ This allows you to choose debug messages related to
|
|
+ security modules configured into your kernel. These
|
|
+ messages may be helpful in determining how a security
|
|
+ module is using security blobs.
|
|
+
|
|
+ If you are unsure how to answer this question, answer N.
|
|
+
|
|
config SECURITYFS
|
|
bool "Enable the securityfs filesystem"
|
|
help
|
|
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
|
index 11975ec..3b266a4 100644
|
|
--- a/security/apparmor/domain.c
|
|
+++ b/security/apparmor/domain.c
|
|
@@ -975,7 +975,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
|
}
|
|
aa_put_label(cred_label(bprm->cred));
|
|
/* transfer reference, released when cred is freed */
|
|
- cred_label(bprm->cred) = new;
|
|
+ set_cred_label(bprm->cred, new);
|
|
|
|
done:
|
|
aa_put_label(label);
|
|
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h
|
|
index e287b7d..a90eae7 100644
|
|
--- a/security/apparmor/include/cred.h
|
|
+++ b/security/apparmor/include/cred.h
|
|
@@ -23,8 +23,22 @@
|
|
#include "policy_ns.h"
|
|
#include "task.h"
|
|
|
|
-#define cred_label(X) ((X)->security)
|
|
+static inline struct aa_label *cred_label(const struct cred *cred)
|
|
+{
|
|
+ struct aa_label **blob = cred->security;
|
|
+
|
|
+ AA_BUG(!blob);
|
|
+ return *blob;
|
|
+}
|
|
|
|
+static inline void set_cred_label(const struct cred *cred,
|
|
+ struct aa_label *label)
|
|
+{
|
|
+ struct aa_label **blob = cred->security;
|
|
+
|
|
+ AA_BUG(!blob);
|
|
+ *blob = label;
|
|
+}
|
|
|
|
/**
|
|
* aa_cred_raw_label - obtain cred's label
|
|
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
|
index 8b8b706..c2566aa 100644
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -57,7 +57,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
|
|
static void apparmor_cred_free(struct cred *cred)
|
|
{
|
|
aa_put_label(cred_label(cred));
|
|
- cred_label(cred) = NULL;
|
|
+ set_cred_label(cred, NULL);
|
|
}
|
|
|
|
/*
|
|
@@ -65,7 +65,7 @@ static void apparmor_cred_free(struct cred *cred)
|
|
*/
|
|
static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
|
{
|
|
- cred_label(cred) = NULL;
|
|
+ set_cred_label(cred, NULL);
|
|
return 0;
|
|
}
|
|
|
|
@@ -75,7 +75,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
|
static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
|
|
gfp_t gfp)
|
|
{
|
|
- cred_label(new) = aa_get_newest_label(cred_label(old));
|
|
+ set_cred_label(new, aa_get_newest_label(cred_label(old)));
|
|
return 0;
|
|
}
|
|
|
|
@@ -84,7 +84,7 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
|
|
*/
|
|
static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
|
|
{
|
|
- cred_label(new) = aa_get_newest_label(cred_label(old));
|
|
+ set_cred_label(new, aa_get_newest_label(cred_label(old)));
|
|
}
|
|
|
|
static void apparmor_task_free(struct task_struct *task)
|
|
@@ -1126,6 +1126,13 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
|
|
ctx->label = aa_get_current_label();
|
|
}
|
|
|
|
+/*
|
|
+ * The cred blob is a pointer to, not an instance of, an aa_task_ctx.
|
|
+ */
|
|
+struct lsm_blob_sizes apparmor_blob_sizes = {
|
|
+ .lbs_cred = sizeof(struct aa_task_ctx *),
|
|
+};
|
|
+
|
|
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
|
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
|
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
|
@@ -1455,7 +1462,8 @@ static int __init set_init_ctx(void)
|
|
if (!ctx)
|
|
return -ENOMEM;
|
|
|
|
- cred_label(cred) = aa_get_label(ns_unconfined(root_ns));
|
|
+ lsm_early_cred(cred);
|
|
+ set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
|
|
task_ctx(current) = ctx;
|
|
|
|
return 0;
|
|
@@ -1540,8 +1548,18 @@ static inline int apparmor_init_sysctl(void)
|
|
|
|
static int __init apparmor_init(void)
|
|
{
|
|
+ static int finish;
|
|
int error;
|
|
|
|
+ if (!finish) {
|
|
+ if (apparmor_enabled && security_module_enable("apparmor"))
|
|
+ security_add_blobs(&apparmor_blob_sizes);
|
|
+ else
|
|
+ apparmor_enabled = false;
|
|
+ finish = 1;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
if (!apparmor_enabled || !security_module_enable("apparmor")) {
|
|
aa_info_message("AppArmor disabled by boot time parameter");
|
|
apparmor_enabled = false;
|
|
diff --git a/security/apparmor/task.c b/security/apparmor/task.c
|
|
index c6b78a1..4551110 100644
|
|
--- a/security/apparmor/task.c
|
|
+++ b/security/apparmor/task.c
|
|
@@ -81,7 +81,7 @@ int aa_replace_current_label(struct aa_label *label)
|
|
*/
|
|
aa_get_label(label);
|
|
aa_put_label(cred_label(new));
|
|
- cred_label(new) = label;
|
|
+ set_cred_label(new, label);
|
|
|
|
commit_creds(new);
|
|
return 0;
|
|
@@ -138,7 +138,7 @@ int aa_set_current_hat(struct aa_label *label, u64 token)
|
|
return -EACCES;
|
|
}
|
|
|
|
- cred_label(new) = aa_get_newest_label(label);
|
|
+ set_cred_label(new, aa_get_newest_label(label));
|
|
/* clear exec on switching context */
|
|
aa_put_label(ctx->onexec);
|
|
ctx->onexec = NULL;
|
|
@@ -172,7 +172,7 @@ int aa_restore_previous_label(u64 token)
|
|
return -ENOMEM;
|
|
|
|
aa_put_label(cred_label(new));
|
|
- cred_label(new) = aa_get_newest_label(ctx->previous);
|
|
+ set_cred_label(new, aa_get_newest_label(ctx->previous));
|
|
AA_BUG(!cred_label(new));
|
|
/* clear exec && prev information when restoring to previous context */
|
|
aa_clear_task_ctx_trans(ctx);
|
|
diff --git a/security/security.c b/security/security.c
|
|
index fb75d36..b491c50 100644
|
|
--- a/security/security.c
|
|
+++ b/security/security.c
|
|
@@ -41,6 +41,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init;
|
|
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
|
|
|
|
char *lsm_names;
|
|
+static struct lsm_blob_sizes blob_sizes;
|
|
+
|
|
/* Boot-time LSM user choice */
|
|
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
|
|
CONFIG_DEFAULT_SECURITY;
|
|
@@ -85,10 +87,22 @@ int __init security_init(void)
|
|
loadpin_add_hooks();
|
|
|
|
/*
|
|
- * Load all the remaining security modules.
|
|
+ * The first call to a module specific init function
|
|
+ * updates the blob size requirements.
|
|
+ */
|
|
+ do_security_initcalls();
|
|
+
|
|
+ /*
|
|
+ * The second call to a module specific init function
|
|
+ * adds hooks to the hook lists and does any other early
|
|
+ * initializations required.
|
|
*/
|
|
do_security_initcalls();
|
|
|
|
+#ifdef CONFIG_SECURITY_LSM_DEBUG
|
|
+ pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -198,6 +212,73 @@ int unregister_lsm_notifier(struct notifier_block *nb)
|
|
}
|
|
EXPORT_SYMBOL(unregister_lsm_notifier);
|
|
|
|
+/**
|
|
+ * lsm_cred_alloc - allocate a composite cred blob
|
|
+ * @cred: the cred that needs a blob
|
|
+ * @gfp: allocation type
|
|
+ *
|
|
+ * Allocate the cred blob for all the modules
|
|
+ *
|
|
+ * Returns 0, or -ENOMEM if memory can't be allocated.
|
|
+ */
|
|
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
|
|
+{
|
|
+ if (blob_sizes.lbs_cred == 0) {
|
|
+ cred->security = NULL;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
|
|
+ if (cred->security == NULL)
|
|
+ return -ENOMEM;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * lsm_early_cred - during initialization allocate a composite cred blob
|
|
+ * @cred: the cred that needs a blob
|
|
+ *
|
|
+ * Allocate the cred blob for all the modules if it's not already there
|
|
+ */
|
|
+void lsm_early_cred(struct cred *cred)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ if (cred == NULL)
|
|
+ panic("%s: NULL cred.\n", __func__);
|
|
+ if (cred->security != NULL)
|
|
+ return;
|
|
+ rc = lsm_cred_alloc(cred, GFP_KERNEL);
|
|
+ if (rc)
|
|
+ panic("%s: Early cred alloc failed.\n", __func__);
|
|
+}
|
|
+
|
|
+static void __init lsm_set_size(int *need, int *lbs)
|
|
+{
|
|
+ int offset;
|
|
+
|
|
+ if (*need > 0) {
|
|
+ offset = *lbs;
|
|
+ *lbs += *need;
|
|
+ *need = offset;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * security_add_blobs - Report blob sizes
|
|
+ * @needed: the size of blobs needed by the module
|
|
+ *
|
|
+ * Each LSM has to register its blobs with the infrastructure.
|
|
+ * The "needed" data tells the infrastructure how much memory
|
|
+ * the module requires for each of its blobs. On return the
|
|
+ * structure is filled with the offset that module should use
|
|
+ * from the blob pointer.
|
|
+ */
|
|
+void __init security_add_blobs(struct lsm_blob_sizes *needed)
|
|
+{
|
|
+ lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
|
|
+}
|
|
+
|
|
/*
|
|
* Hook list operation macros.
|
|
*
|
|
@@ -998,7 +1079,15 @@ void security_task_free(struct task_struct *task)
|
|
|
|
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
|
{
|
|
- return call_int_hook(cred_alloc_blank, 0, cred, gfp);
|
|
+ int rc = lsm_cred_alloc(cred, gfp);
|
|
+
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
|
|
+ if (rc)
|
|
+ security_cred_free(cred);
|
|
+ return rc;
|
|
}
|
|
|
|
void security_cred_free(struct cred *cred)
|
|
@@ -1011,11 +1100,22 @@ void security_cred_free(struct cred *cred)
|
|
return;
|
|
|
|
call_void_hook(cred_free, cred);
|
|
+
|
|
+ kfree(cred->security);
|
|
+ cred->security = NULL;
|
|
}
|
|
|
|
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
|
|
{
|
|
- return call_int_hook(cred_prepare, 0, new, old, gfp);
|
|
+ int rc = lsm_cred_alloc(new, gfp);
|
|
+
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = call_int_hook(cred_prepare, 0, new, old, gfp);
|
|
+ if (rc)
|
|
+ security_cred_free(new);
|
|
+ return rc;
|
|
}
|
|
|
|
void security_transfer_creds(struct cred *new, const struct cred *old)
|
|
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
|
|
index b1c67db..5e12777 100644
|
|
--- a/security/selinux/hooks.c
|
|
+++ b/security/selinux/hooks.c
|
|
@@ -213,12 +213,9 @@ static void cred_init_security(void)
|
|
struct cred *cred = (struct cred *) current->real_cred;
|
|
struct task_security_struct *tsec;
|
|
|
|
- tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
|
|
- if (!tsec)
|
|
- panic("SELinux: Failed to initialize initial task.\n");
|
|
-
|
|
+ lsm_early_cred(cred);
|
|
+ tsec = selinux_cred(cred);
|
|
tsec->osid = tsec->sid = SECINITSID_KERNEL;
|
|
- cred->security = tsec;
|
|
}
|
|
|
|
/*
|
|
@@ -3934,53 +3931,17 @@ static int selinux_task_alloc(struct task_struct *task,
|
|
sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
|
|
}
|
|
|
|
-/*
|
|
- * allocate the SELinux part of blank credentials
|
|
- */
|
|
-static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
|
-{
|
|
- struct task_security_struct *tsec;
|
|
-
|
|
- tsec = kzalloc(sizeof(struct task_security_struct), gfp);
|
|
- if (!tsec)
|
|
- return -ENOMEM;
|
|
-
|
|
- cred->security = tsec;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * detach and free the LSM part of a set of credentials
|
|
- */
|
|
-static void selinux_cred_free(struct cred *cred)
|
|
-{
|
|
- struct task_security_struct *tsec = selinux_cred(cred);
|
|
-
|
|
- /*
|
|
- * cred->security == NULL if security_cred_alloc_blank() or
|
|
- * security_prepare_creds() returned an error.
|
|
- */
|
|
- BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
|
|
- cred->security = (void *) 0x7UL;
|
|
- kfree(tsec);
|
|
-}
|
|
-
|
|
/*
|
|
* prepare a new set of credentials for modification
|
|
*/
|
|
static int selinux_cred_prepare(struct cred *new, const struct cred *old,
|
|
gfp_t gfp)
|
|
{
|
|
- const struct task_security_struct *old_tsec;
|
|
- struct task_security_struct *tsec;
|
|
-
|
|
- old_tsec = selinux_cred(old);
|
|
+ const struct task_security_struct *old_tsec = selinux_cred(old);
|
|
+ struct task_security_struct *tsec = selinux_cred(new);
|
|
|
|
- tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
|
|
- if (!tsec)
|
|
- return -ENOMEM;
|
|
+ *tsec = *old_tsec;
|
|
|
|
- new->security = tsec;
|
|
return 0;
|
|
}
|
|
|
|
@@ -6939,6 +6900,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
|
|
}
|
|
#endif
|
|
|
|
+struct lsm_blob_sizes selinux_blob_sizes = {
|
|
+ .lbs_cred = sizeof(struct task_security_struct),
|
|
+};
|
|
+
|
|
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),
|
|
@@ -7021,8 +6986,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
|
|
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(cred_getsecid, selinux_cred_getsecid),
|
|
@@ -7178,11 +7141,19 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
|
|
|
|
static __init int selinux_init(void)
|
|
{
|
|
+ static int finish;
|
|
+
|
|
if (!security_module_enable("selinux")) {
|
|
selinux_enabled = 0;
|
|
return 0;
|
|
}
|
|
|
|
+ if (!finish) {
|
|
+ security_add_blobs(&selinux_blob_sizes);
|
|
+ finish = 1;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
if (!selinux_enabled) {
|
|
pr_info("SELinux: Disabled at boot.\n");
|
|
return 0;
|
|
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
|
|
index 734b683..db1c700 100644
|
|
--- a/security/selinux/include/objsec.h
|
|
+++ b/security/selinux/include/objsec.h
|
|
@@ -25,6 +25,9 @@
|
|
#include <linux/binfmts.h>
|
|
#include <linux/in.h>
|
|
#include <linux/spinlock.h>
|
|
+#include <linux/lsm_hooks.h>
|
|
+#include <linux/msg.h>
|
|
+#include <net/sock.h>
|
|
#include <net/net_namespace.h>
|
|
#include "flask.h"
|
|
#include "avc.h"
|
|
@@ -158,6 +161,7 @@ struct bpf_security_struct {
|
|
u32 sid; /*SID of bpf obj creater*/
|
|
};
|
|
|
|
+extern struct lsm_blob_sizes selinux_blob_sizes;
|
|
static inline struct task_security_struct *selinux_cred(const struct cred *cred)
|
|
{
|
|
return cred->security;
|
|
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
|
|
index f3a5a13..b5665bd 100644
|
|
--- a/security/selinux/selinuxfs.c
|
|
+++ b/security/selinux/selinuxfs.c
|
|
@@ -31,6 +31,7 @@
|
|
#include <linux/uaccess.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/ctype.h>
|
|
+#include <linux/lsm_hooks.h>
|
|
|
|
/* selinuxfs pseudo filesystem for exporting the security policy API.
|
|
Based on the proc code and the fs/nfsd/nfsctl.c code. */
|
|
diff --git a/security/smack/smack.h b/security/smack/smack.h
|
|
index 0b55d6a..0c6dce4 100644
|
|
--- a/security/smack/smack.h
|
|
+++ b/security/smack/smack.h
|
|
@@ -24,6 +24,7 @@
|
|
#include <linux/list.h>
|
|
#include <linux/rculist.h>
|
|
#include <linux/lsm_audit.h>
|
|
+#include <linux/msg.h>
|
|
|
|
/*
|
|
* Use IPv6 port labeling if IPv6 is enabled and secmarks
|
|
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
|
|
index bb0d401..0b63915 100644
|
|
--- a/security/smack/smack_lsm.c
|
|
+++ b/security/smack/smack_lsm.c
|
|
@@ -309,29 +309,20 @@ static struct inode_smack *new_inode_smack(struct smack_known *skp)
|
|
}
|
|
|
|
/**
|
|
- * new_task_smack - allocate a task security blob
|
|
+ * init_task_smack - initialize a task security blob
|
|
+ * @tsp: blob to initialize
|
|
* @task: a pointer to the Smack label for the running task
|
|
* @forked: a pointer to the Smack label for the forked task
|
|
- * @gfp: type of the memory for the allocation
|
|
*
|
|
- * Returns the new blob or NULL if there's no memory available
|
|
*/
|
|
-static struct task_smack *new_task_smack(struct smack_known *task,
|
|
- struct smack_known *forked, gfp_t gfp)
|
|
+static void init_task_smack(struct task_smack *tsp, struct smack_known *task,
|
|
+ struct smack_known *forked)
|
|
{
|
|
- struct task_smack *tsp;
|
|
-
|
|
- tsp = kzalloc(sizeof(struct task_smack), gfp);
|
|
- if (tsp == NULL)
|
|
- return NULL;
|
|
-
|
|
tsp->smk_task = task;
|
|
tsp->smk_forked = forked;
|
|
INIT_LIST_HEAD(&tsp->smk_rules);
|
|
INIT_LIST_HEAD(&tsp->smk_relabel);
|
|
mutex_init(&tsp->smk_rules_lock);
|
|
-
|
|
- return tsp;
|
|
}
|
|
|
|
/**
|
|
@@ -1965,14 +1956,7 @@ static int smack_file_open(struct file *file)
|
|
*/
|
|
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
|
|
{
|
|
- struct task_smack *tsp;
|
|
-
|
|
- tsp = new_task_smack(NULL, NULL, gfp);
|
|
- if (tsp == NULL)
|
|
- return -ENOMEM;
|
|
-
|
|
- cred->security = tsp;
|
|
-
|
|
+ init_task_smack(smack_cred(cred), NULL, NULL);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1989,10 +1973,6 @@ static void smack_cred_free(struct cred *cred)
|
|
struct list_head *l;
|
|
struct list_head *n;
|
|
|
|
- if (tsp == NULL)
|
|
- return;
|
|
- cred->security = NULL;
|
|
-
|
|
smk_destroy_label_list(&tsp->smk_relabel);
|
|
|
|
list_for_each_safe(l, n, &tsp->smk_rules) {
|
|
@@ -2000,7 +1980,6 @@ static void smack_cred_free(struct cred *cred)
|
|
list_del(&rp->list);
|
|
kfree(rp);
|
|
}
|
|
- kfree(tsp);
|
|
}
|
|
|
|
/**
|
|
@@ -2015,14 +1994,10 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
|
|
gfp_t gfp)
|
|
{
|
|
struct task_smack *old_tsp = smack_cred(old);
|
|
- struct task_smack *new_tsp;
|
|
+ struct task_smack *new_tsp = smack_cred(new);
|
|
int rc;
|
|
|
|
- new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
|
|
- if (new_tsp == NULL)
|
|
- return -ENOMEM;
|
|
-
|
|
- new->security = new_tsp;
|
|
+ init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task);
|
|
|
|
rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
|
|
if (rc != 0)
|
|
@@ -2030,10 +2005,7 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
|
|
|
|
rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
|
|
gfp);
|
|
- if (rc != 0)
|
|
- return rc;
|
|
-
|
|
- return 0;
|
|
+ return rc;
|
|
}
|
|
|
|
/**
|
|
@@ -4665,6 +4637,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
|
return 0;
|
|
}
|
|
|
|
+struct lsm_blob_sizes smack_blob_sizes = {
|
|
+ .lbs_cred = sizeof(struct task_smack),
|
|
+};
|
|
+
|
|
static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
|
|
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
|
|
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
|
|
@@ -4843,23 +4819,35 @@ static __init void init_smack_known_list(void)
|
|
*/
|
|
static __init int smack_init(void)
|
|
{
|
|
- struct cred *cred;
|
|
+ static int finish;
|
|
+ struct cred *cred = (struct cred *) current->cred;
|
|
struct task_smack *tsp;
|
|
|
|
if (!security_module_enable("smack"))
|
|
return 0;
|
|
|
|
+ if (!finish) {
|
|
+ security_add_blobs(&smack_blob_sizes);
|
|
+ finish = 1;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
|
|
if (!smack_inode_cache)
|
|
return -ENOMEM;
|
|
|
|
- tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
|
|
- GFP_KERNEL);
|
|
- if (tsp == NULL) {
|
|
- kmem_cache_destroy(smack_inode_cache);
|
|
- return -ENOMEM;
|
|
- }
|
|
+ lsm_early_cred(cred);
|
|
|
|
+ /*
|
|
+ * Set the security state for the initial task.
|
|
+ */
|
|
+ tsp = smack_cred(cred);
|
|
+ init_task_smack(tsp, &smack_known_floor, &smack_known_floor);
|
|
+
|
|
+ /*
|
|
+ * Register with LSM
|
|
+ */
|
|
+ security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
|
|
smack_enabled = 1;
|
|
|
|
pr_info("Smack: Initializing.\n");
|
|
@@ -4873,20 +4861,9 @@ static __init int smack_init(void)
|
|
pr_info("Smack: IPv6 Netfilter enabled.\n");
|
|
#endif
|
|
|
|
- /*
|
|
- * Set the security state for the initial task.
|
|
- */
|
|
- cred = (struct cred *) current->cred;
|
|
- cred->security = tsp;
|
|
-
|
|
/* initialize the smack_known_list */
|
|
init_smack_known_list();
|
|
|
|
- /*
|
|
- * Register with LSM
|
|
- */
|
|
- security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
|
|
index 539bcdd..0110beb 100644
|
|
--- a/security/tomoyo/common.h
|
|
+++ b/security/tomoyo/common.h
|
|
@@ -29,6 +29,7 @@
|
|
#include <linux/in.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/un.h>
|
|
+#include <linux/lsm_hooks.h>
|
|
#include <net/sock.h>
|
|
#include <net/af_unix.h>
|
|
#include <net/ip.h>
|
|
@@ -1062,6 +1063,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
|
|
/********** External variable definitions. **********/
|
|
|
|
extern bool tomoyo_policy_loaded;
|
|
+extern bool tomoyo_enabled;
|
|
extern const char * const tomoyo_condition_keyword
|
|
[TOMOYO_MAX_CONDITION_KEYWORD];
|
|
extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
|
|
@@ -1196,6 +1198,17 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
|
|
atomic_dec(&group->head.users);
|
|
}
|
|
|
|
+/**
|
|
+ * tomoyo_cred - Get a pointer to the tomoyo cred security blob
|
|
+ * @cred - the relevant cred
|
|
+ *
|
|
+ * Returns pointer to the tomoyo cred blob.
|
|
+ */
|
|
+static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
|
|
+{
|
|
+ return cred->security;
|
|
+}
|
|
+
|
|
/**
|
|
* tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
|
|
*
|
|
@@ -1203,7 +1216,9 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
|
|
*/
|
|
static inline struct tomoyo_domain_info *tomoyo_domain(void)
|
|
{
|
|
- return current_cred()->security;
|
|
+ struct tomoyo_domain_info **blob = tomoyo_cred(current_cred());
|
|
+
|
|
+ return *blob;
|
|
}
|
|
|
|
/**
|
|
@@ -1216,7 +1231,9 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void)
|
|
static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
|
|
*task)
|
|
{
|
|
- return task_cred_xxx(task, security);
|
|
+ struct tomoyo_domain_info **blob = tomoyo_cred(get_task_cred(task));
|
|
+
|
|
+ return *blob;
|
|
}
|
|
|
|
/**
|
|
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
|
|
index f6758da..b7469fd 100644
|
|
--- a/security/tomoyo/domain.c
|
|
+++ b/security/tomoyo/domain.c
|
|
@@ -678,6 +678,7 @@ static int tomoyo_environ(struct tomoyo_execve *ee)
|
|
*/
|
|
int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|
{
|
|
+ struct tomoyo_domain_info **blob;
|
|
struct tomoyo_domain_info *old_domain = tomoyo_domain();
|
|
struct tomoyo_domain_info *domain = NULL;
|
|
const char *original_name = bprm->filename;
|
|
@@ -843,7 +844,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|
domain = old_domain;
|
|
/* Update reference count on "struct tomoyo_domain_info". */
|
|
atomic_inc(&domain->users);
|
|
- bprm->cred->security = domain;
|
|
+ blob = tomoyo_cred(bprm->cred);
|
|
+ *blob = domain;
|
|
kfree(exename.name);
|
|
if (!retval) {
|
|
ee->r.domain = domain;
|
|
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
|
|
index 1d3d7e7..768dff9 100644
|
|
--- a/security/tomoyo/securityfs_if.c
|
|
+++ b/security/tomoyo/securityfs_if.c
|
|
@@ -71,9 +71,12 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
|
|
if (!cred) {
|
|
error = -ENOMEM;
|
|
} else {
|
|
- struct tomoyo_domain_info *old_domain =
|
|
- cred->security;
|
|
- cred->security = new_domain;
|
|
+ struct tomoyo_domain_info **blob;
|
|
+ struct tomoyo_domain_info *old_domain;
|
|
+
|
|
+ blob = tomoyo_cred(cred);
|
|
+ old_domain = *blob;
|
|
+ *blob = new_domain;
|
|
atomic_inc(&new_domain->users);
|
|
atomic_dec(&old_domain->users);
|
|
commit_creds(cred);
|
|
@@ -234,10 +237,14 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
|
|
*/
|
|
static int __init tomoyo_initerface_init(void)
|
|
{
|
|
+ struct tomoyo_domain_info *domain;
|
|
struct dentry *tomoyo_dir;
|
|
|
|
+ if (!tomoyo_enabled)
|
|
+ return 0;
|
|
+ domain = tomoyo_domain();
|
|
/* Don't create securityfs entries unless registered. */
|
|
- if (current_cred()->security != &tomoyo_kernel_domain)
|
|
+ if (domain != &tomoyo_kernel_domain)
|
|
return 0;
|
|
|
|
tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
|
|
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
|
|
index 9f932e2..bb84e6e 100644
|
|
--- a/security/tomoyo/tomoyo.c
|
|
+++ b/security/tomoyo/tomoyo.c
|
|
@@ -18,7 +18,9 @@
|
|
*/
|
|
static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
|
|
{
|
|
- new->security = NULL;
|
|
+ struct tomoyo_domain_info **blob = tomoyo_cred(new);
|
|
+
|
|
+ *blob = NULL;
|
|
return 0;
|
|
}
|
|
|
|
@@ -34,8 +36,13 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
|
|
static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
|
|
gfp_t gfp)
|
|
{
|
|
- struct tomoyo_domain_info *domain = old->security;
|
|
- new->security = domain;
|
|
+ struct tomoyo_domain_info **old_blob = tomoyo_cred(old);
|
|
+ struct tomoyo_domain_info **new_blob = tomoyo_cred(new);
|
|
+ struct tomoyo_domain_info *domain;
|
|
+
|
|
+ domain = *old_blob;
|
|
+ *new_blob = domain;
|
|
+
|
|
if (domain)
|
|
atomic_inc(&domain->users);
|
|
return 0;
|
|
@@ -59,7 +66,9 @@ static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
|
|
*/
|
|
static void tomoyo_cred_free(struct cred *cred)
|
|
{
|
|
- struct tomoyo_domain_info *domain = cred->security;
|
|
+ struct tomoyo_domain_info **blob = tomoyo_cred(cred);
|
|
+ struct tomoyo_domain_info *domain = *blob;
|
|
+
|
|
if (domain)
|
|
atomic_dec(&domain->users);
|
|
}
|
|
@@ -73,6 +82,9 @@ static void tomoyo_cred_free(struct cred *cred)
|
|
*/
|
|
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
|
|
{
|
|
+ struct tomoyo_domain_info **blob;
|
|
+ struct tomoyo_domain_info *domain;
|
|
+
|
|
/*
|
|
* Do only if this function is called for the first time of an execve
|
|
* operation.
|
|
@@ -93,13 +105,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
|
|
* stored inside "bprm->cred->security" will be acquired later inside
|
|
* tomoyo_find_next_domain().
|
|
*/
|
|
- atomic_dec(&((struct tomoyo_domain_info *)
|
|
- bprm->cred->security)->users);
|
|
+ blob = tomoyo_cred(bprm->cred);
|
|
+ domain = *blob;
|
|
+ atomic_dec(&domain->users);
|
|
/*
|
|
* Tell tomoyo_bprm_check_security() is called for the first time of an
|
|
* execve operation.
|
|
*/
|
|
- bprm->cred->security = NULL;
|
|
+ *blob = NULL;
|
|
return 0;
|
|
}
|
|
|
|
@@ -112,8 +125,11 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
|
|
*/
|
|
static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
|
|
{
|
|
- struct tomoyo_domain_info *domain = bprm->cred->security;
|
|
+ struct tomoyo_domain_info **blob;
|
|
+ struct tomoyo_domain_info *domain;
|
|
|
|
+ blob = tomoyo_cred(bprm->cred);
|
|
+ domain = *blob;
|
|
/*
|
|
* Execute permission is checked against pathname passed to do_execve()
|
|
* using current domain.
|
|
@@ -493,6 +509,10 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
|
return tomoyo_socket_sendmsg_permission(sock, msg, size);
|
|
}
|
|
|
|
+struct lsm_blob_sizes tomoyo_blob_sizes = {
|
|
+ .lbs_cred = sizeof(struct tomoyo_domain_info *),
|
|
+};
|
|
+
|
|
/*
|
|
* tomoyo_security_ops is a "struct security_operations" which is used for
|
|
* registering TOMOYO.
|
|
@@ -531,6 +551,8 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
|
|
/* Lock for GC. */
|
|
DEFINE_SRCU(tomoyo_ss);
|
|
|
|
+bool tomoyo_enabled;
|
|
+
|
|
/**
|
|
* tomoyo_init - Register TOMOYO Linux as a LSM module.
|
|
*
|
|
@@ -538,14 +560,28 @@ DEFINE_SRCU(tomoyo_ss);
|
|
*/
|
|
static int __init tomoyo_init(void)
|
|
{
|
|
+ static int finish;
|
|
struct cred *cred = (struct cred *) current_cred();
|
|
+ struct tomoyo_domain_info **blob;
|
|
+
|
|
+ if (!security_module_enable("tomoyo")) {
|
|
+ tomoyo_enabled = false;
|
|
+ return 0;
|
|
+ }
|
|
+ tomoyo_enabled = true;
|
|
|
|
- if (!security_module_enable("tomoyo"))
|
|
+ if (!finish) {
|
|
+ security_add_blobs(&tomoyo_blob_sizes);
|
|
+ finish = 1;
|
|
return 0;
|
|
+ }
|
|
+
|
|
/* register ourselves with the security framework */
|
|
security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
|
|
printk(KERN_INFO "TOMOYO Linux initialized\n");
|
|
- cred->security = &tomoyo_kernel_domain;
|
|
+ lsm_early_cred(cred);
|
|
+ blob = tomoyo_cred(cred);
|
|
+ *blob = &tomoyo_kernel_domain;
|
|
tomoyo_mm_init();
|
|
return 0;
|
|
}
|
|
--
|
|
https://clearlinux.org
|
|
|