Skip to content

Commit

Permalink
Infrastructure management of the cred security blob
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
[kees: adjusted for ordered init series]
Signed-off-by: Kees Cook <[email protected]>
  • Loading branch information
cschaufler authored and kees committed Jan 8, 2019
1 parent 43fc460 commit bbd3662
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 102 deletions.
12 changes: 12 additions & 0 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -2027,6 +2027,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
Expand Down Expand Up @@ -2056,6 +2063,7 @@ struct lsm_info {
unsigned long flags; /* Optional: flags describing LSM */
int *enabled; /* Optional: controlled by CONFIG_LSM */
int (*init)(void); /* Required. */
struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
};

extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
Expand Down Expand Up @@ -2095,4 +2103,8 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */

#ifdef CONFIG_SECURITY
void __init lsm_early_cred(struct cred *cred);
#endif

#endif /* ! __LINUX_LSM_HOOKS_H */
4 changes: 2 additions & 2 deletions security/apparmor/include/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

static inline struct aa_label *cred_label(const struct cred *cred)
{
struct aa_label **blob = cred->security;
struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;

AA_BUG(!blob);
return *blob;
Expand All @@ -34,7 +34,7 @@ static inline struct aa_label *cred_label(const struct cred *cred)
static inline void set_cred_label(const struct cred *cred,
struct aa_label *label)
{
struct aa_label **blob = cred->security;
struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;

AA_BUG(!blob);
*blob = label;
Expand Down
4 changes: 4 additions & 0 deletions security/apparmor/include/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/lsm_hooks.h>

#include "match.h"

Expand Down Expand Up @@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
size_t *ns_len);
void aa_info_message(const char *str);

/* Security blob offsets */
extern struct lsm_blob_sizes apparmor_blob_sizes;

/**
* aa_strneq - compare null terminated @str to a non null terminated substring
* @str: a null terminated string
Expand Down
9 changes: 9 additions & 0 deletions security/apparmor/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,13 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
}
#endif

/*
* The cred blob is a pointer to, not an instance of, an aa_task_ctx.
*/
struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
.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),
Expand Down Expand Up @@ -1485,6 +1492,7 @@ static int __init set_init_ctx(void)
if (!ctx)
return -ENOMEM;

lsm_early_cred(cred);
set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
task_ctx(current) = ctx;

Expand Down Expand Up @@ -1725,5 +1733,6 @@ DEFINE_LSM(apparmor) = {
.name = "apparmor",
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
.init = apparmor_init,
};
89 changes: 87 additions & 2 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 __lsm_ro_after_init;

/* Boot-time LSM user choice */
static __initdata const char *chosen_lsm_order;
static __initdata const char *chosen_major_lsm;
Expand Down Expand Up @@ -139,6 +141,25 @@ static bool __init lsm_allowed(struct lsm_info *lsm)
return true;
}

static void __init lsm_set_blob_size(int *need, int *lbs)
{
int offset;

if (*need > 0) {
offset = *lbs;
*lbs += *need;
*need = offset;
}
}

static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
{
if (!needed)
return;

lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
}

/* Prepare LSM for initialization. */
static void __init prepare_lsm(struct lsm_info *lsm)
{
Expand All @@ -153,6 +174,8 @@ static void __init prepare_lsm(struct lsm_info *lsm)
exclusive = lsm;
init_debug("exclusive chosen: %s\n", lsm->name);
}

lsm_set_blob_sizes(lsm->blobs);
}
}

Expand Down Expand Up @@ -255,6 +278,8 @@ static void __init ordered_lsm_init(void)
for (lsm = ordered_lsms; *lsm; lsm++)
prepare_lsm(*lsm);

init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);

for (lsm = ordered_lsms; *lsm; lsm++)
initialize_lsm(*lsm);

Expand Down Expand Up @@ -382,6 +407,47 @@ 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.
*/
static 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 __init 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__);
}

/*
* Hook list operation macros.
*
Expand Down Expand Up @@ -1195,17 +1261,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)
Expand Down
51 changes: 10 additions & 41 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,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;
}

/*
Expand Down Expand Up @@ -3685,47 +3682,16 @@ 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);

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);

tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
if (!tsec)
return -ENOMEM;
const struct task_security_struct *old_tsec = selinux_cred(old);
struct task_security_struct *tsec = selinux_cred(new);

new->security = tsec;
*tsec = *old_tsec;
return 0;
}

Expand Down Expand Up @@ -6678,6 +6644,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif

struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.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),
Expand Down Expand Up @@ -6761,8 +6731,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),
Expand Down Expand Up @@ -6981,6 +6949,7 @@ DEFINE_LSM(selinux) = {
.name = "selinux",
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled,
.blobs = &selinux_blob_sizes,
.init = selinux_init,
};

Expand Down
4 changes: 3 additions & 1 deletion security/selinux/include/objsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/binfmts.h>
#include <linux/in.h>
#include <linux/spinlock.h>
#include <linux/lsm_hooks.h>
#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"
Expand Down Expand Up @@ -158,9 +159,10 @@ 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;
return cred->security + selinux_blob_sizes.lbs_cred;
}

#endif /* _SELINUX_OBJSEC_H_ */
3 changes: 2 additions & 1 deletion security/smack/smack.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ extern struct smack_known *smack_syslog_label;
extern struct smack_known *smack_unconfined;
#endif
extern int smack_ptrace_rule;
extern struct lsm_blob_sizes smack_blob_sizes;

extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
Expand All @@ -358,7 +359,7 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];

static inline struct task_smack *smack_cred(const struct cred *cred)
{
return cred->security;
return cred->security + smack_blob_sizes.lbs_cred;
}

/*
Expand Down
Loading

0 comments on commit bbd3662

Please sign in to comment.