LSM: Infrastructure management of the task security

Move management of the task_struct->security blob out
of the individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.
The only user of this blob is AppArmor. The AppArmor use
is abstracted to avoid future conflict.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
[kees: adjusted for ordered init series]
Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
Casey Schaufler 2018-09-21 17:19:37 -07:00 committed by Kees Cook
parent afb1cbe374
commit f4ad8f2c40
4 changed files with 62 additions and 27 deletions

View File

@ -2034,6 +2034,7 @@ struct lsm_blob_sizes {
int lbs_cred; int lbs_cred;
int lbs_file; int lbs_file;
int lbs_inode; int lbs_inode;
int lbs_task;
}; };
/* /*
@ -2109,6 +2110,7 @@ extern int lsm_inode_alloc(struct inode *inode);
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
void __init lsm_early_cred(struct cred *cred); void __init lsm_early_cred(struct cred *cred);
void __init lsm_early_task(struct task_struct *task);
#endif #endif
#endif /* ! __LINUX_LSM_HOOKS_H */ #endif /* ! __LINUX_LSM_HOOKS_H */

View File

@ -14,7 +14,10 @@
#ifndef __AA_TASK_H #ifndef __AA_TASK_H
#define __AA_TASK_H #define __AA_TASK_H
#define task_ctx(X) ((X)->security) static inline struct aa_task_ctx *task_ctx(struct task_struct *task)
{
return task->security;
}
/* /*
* struct aa_task_ctx - information for current task label change * struct aa_task_ctx - information for current task label change
@ -36,17 +39,6 @@ int aa_set_current_hat(struct aa_label *label, u64 token);
int aa_restore_previous_label(u64 cookie); int aa_restore_previous_label(u64 cookie);
struct aa_label *aa_get_task_label(struct task_struct *task); struct aa_label *aa_get_task_label(struct task_struct *task);
/**
* aa_alloc_task_ctx - allocate a new task_ctx
* @flags: gfp flags for allocation
*
* Returns: allocated buffer or NULL on failure
*/
static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags)
{
return kzalloc(sizeof(struct aa_task_ctx), flags);
}
/** /**
* aa_free_task_ctx - free a task_ctx * aa_free_task_ctx - free a task_ctx
* @ctx: task_ctx to free (MAYBE NULL) * @ctx: task_ctx to free (MAYBE NULL)
@ -57,8 +49,6 @@ static inline void aa_free_task_ctx(struct aa_task_ctx *ctx)
aa_put_label(ctx->nnp); aa_put_label(ctx->nnp);
aa_put_label(ctx->previous); aa_put_label(ctx->previous);
aa_put_label(ctx->onexec); aa_put_label(ctx->onexec);
kzfree(ctx);
} }
} }

View File

@ -94,19 +94,14 @@ static void apparmor_task_free(struct task_struct *task)
{ {
aa_free_task_ctx(task_ctx(task)); aa_free_task_ctx(task_ctx(task));
task_ctx(task) = NULL;
} }
static int apparmor_task_alloc(struct task_struct *task, static int apparmor_task_alloc(struct task_struct *task,
unsigned long clone_flags) unsigned long clone_flags)
{ {
struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL); struct aa_task_ctx *new = task_ctx(task);
if (!new)
return -ENOMEM;
aa_dup_task_ctx(new, task_ctx(current)); aa_dup_task_ctx(new, task_ctx(current));
task_ctx(task) = new;
return 0; return 0;
} }
@ -1157,6 +1152,7 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct aa_task_ctx *), .lbs_cred = sizeof(struct aa_task_ctx *),
.lbs_file = sizeof(struct aa_file_ctx), .lbs_file = sizeof(struct aa_file_ctx),
.lbs_task = sizeof(struct aa_task_ctx),
}; };
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
@ -1487,15 +1483,10 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
static int __init set_init_ctx(void) static int __init set_init_ctx(void)
{ {
struct cred *cred = (struct cred *)current->real_cred; struct cred *cred = (struct cred *)current->real_cred;
struct aa_task_ctx *ctx;
ctx = aa_alloc_task_ctx(GFP_KERNEL);
if (!ctx)
return -ENOMEM;
lsm_early_cred(cred); lsm_early_cred(cred);
lsm_early_task(current);
set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
task_ctx(current) = ctx;
return 0; return 0;
} }

View File

@ -169,6 +169,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
if (needed->lbs_inode && blob_sizes.lbs_inode == 0) if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head); blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode); lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
} }
/* Prepare LSM for initialization. */ /* Prepare LSM for initialization. */
@ -292,6 +293,7 @@ static void __init ordered_lsm_init(void)
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file); init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
/* /*
* Create any kmem_caches needed for blobs * Create any kmem_caches needed for blobs
@ -515,6 +517,46 @@ int lsm_inode_alloc(struct inode *inode)
return 0; return 0;
} }
/**
* lsm_task_alloc - allocate a composite task blob
* @task: the task that needs a blob
*
* Allocate the task blob for all the modules
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
int lsm_task_alloc(struct task_struct *task)
{
if (blob_sizes.lbs_task == 0) {
task->security = NULL;
return 0;
}
task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
if (task->security == NULL)
return -ENOMEM;
return 0;
}
/**
* lsm_early_task - during initialization allocate a composite task blob
* @task: the task that needs a blob
*
* Allocate the task blob for all the modules if it's not already there
*/
void __init lsm_early_task(struct task_struct *task)
{
int rc;
if (task == NULL)
panic("%s: task cred.\n", __func__);
if (task->security != NULL)
return;
rc = lsm_task_alloc(task);
if (rc)
panic("%s: Early task alloc failed.\n", __func__);
}
/* /*
* Hook list operation macros. * Hook list operation macros.
* *
@ -1359,12 +1401,22 @@ int security_file_open(struct file *file)
int security_task_alloc(struct task_struct *task, unsigned long clone_flags) int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{ {
return call_int_hook(task_alloc, 0, task, clone_flags); int rc = lsm_task_alloc(task);
if (rc)
return rc;
rc = call_int_hook(task_alloc, 0, task, clone_flags);
if (unlikely(rc))
security_task_free(task);
return rc;
} }
void security_task_free(struct task_struct *task) void security_task_free(struct task_struct *task)
{ {
call_void_hook(task_free, task); call_void_hook(task_free, task);
kfree(task->security);
task->security = NULL;
} }
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)