@@ -2011,6 +2011,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
@@ -2023,6 +2030,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);
@@ -2069,4 +2077,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 */
@@ -704,19 +704,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);
@@ -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
@@ -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);
@@ -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
@@ -56,7 +56,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);
}
/*
@@ -64,7 +64,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;
}
@@ -74,7 +74,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;
}
@@ -83,7 +83,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)
@@ -1117,6 +1117,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),
@@ -1437,7 +1444,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;
@@ -1522,8 +1530,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;
@@ -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);
@@ -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;
@@ -82,10 +84,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;
}
@@ -193,6 +207,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.
*
@@ -993,17 +1074,36 @@ 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)
{
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)
@@ -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;
}
/*
@@ -3886,53 +3883,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;
}
@@ -6848,6 +6809,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),
@@ -6930,8 +6895,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),
@@ -7085,11 +7048,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) {
printk(KERN_INFO "SELinux: Disabled at boot.\n");
return 0;
@@ -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;
@@ -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. */
@@ -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
@@ -635,7 +635,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
*/
bool smack_privileged_cred(int cap, const struct cred *cred)
{
- struct task_smack *tsp = smack_cred(cred);
+ struct task_smack *tsp = cred->security;
struct smack_known *skp = tsp->smk_task;
struct smack_known_list_elem *sklep;
int rc;
@@ -308,29 +308,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;
}
/**
@@ -1957,14 +1948,7 @@ static int smack_file_open(struct file *file, const struct cred *cred)
*/
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;
}
@@ -1981,10 +1965,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) {
@@ -1992,7 +1972,6 @@ static void smack_cred_free(struct cred *cred)
list_del(&rp->list);
kfree(rp);
}
- kfree(tsp);
}
/**
@@ -2007,14 +1986,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)
@@ -2022,10 +1997,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;
}
/**
@@ -4622,6 +4594,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),
@@ -4799,23 +4775,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");
@@ -4829,20 +4817,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;
}
@@ -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;
}
/**
@@ -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;
@@ -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);
@@ -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;
}