Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bbd3662a authored by Casey Schaufler's avatar Casey Schaufler Committed by Kees Cook
Browse files

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.

Signed-off-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
[kees: adjusted for ordered init series]
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent 43fc4609
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -2027,6 +2027,13 @@ struct security_hook_list {
	char				*lsm;
	char				*lsm;
} __randomize_layout;
} __randomize_layout;


/*
 * Security blob size or offset data.
 */
struct lsm_blob_sizes {
	int	lbs_cred;
};

/*
/*
 * Initializing a security_hook_list structure takes
 * Initializing a security_hook_list structure takes
 * up a lot of space in a source file. This macro takes
 * up a lot of space in a source file. This macro takes
@@ -2056,6 +2063,7 @@ struct lsm_info {
	unsigned long flags;	/* Optional: flags describing LSM */
	unsigned long flags;	/* Optional: flags describing LSM */
	int *enabled;		/* Optional: controlled by CONFIG_LSM */
	int *enabled;		/* Optional: controlled by CONFIG_LSM */
	int (*init)(void);	/* Required. */
	int (*init)(void);	/* Required. */
	struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
};
};


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


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

#endif /* ! __LINUX_LSM_HOOKS_H */
#endif /* ! __LINUX_LSM_HOOKS_H */
+2 −2
Original line number Original line Diff line number Diff line
@@ -25,7 +25,7 @@


static inline struct aa_label *cred_label(const struct cred *cred)
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);
	AA_BUG(!blob);
	return *blob;
	return *blob;
@@ -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,
static inline void set_cred_label(const struct cred *cred,
				  struct aa_label *label)
				  struct aa_label *label)
{
{
	struct aa_label **blob = cred->security;
	struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;


	AA_BUG(!blob);
	AA_BUG(!blob);
	*blob = label;
	*blob = label;
+4 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


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


#include "match.h"
#include "match.h"


@@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
			     size_t *ns_len);
			     size_t *ns_len);
void aa_info_message(const char *str);
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
 * aa_strneq - compare null terminated @str to a non null terminated substring
 * @str: a null terminated string
 * @str: a null terminated string
+9 −0
Original line number Original line Diff line number Diff line
@@ -1151,6 +1151,13 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
}
}
#endif
#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 = {
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_access_check, apparmor_ptrace_access_check),
	LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
	LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1485,6 +1492,7 @@ static int __init set_init_ctx(void)
	if (!ctx)
	if (!ctx)
		return -ENOMEM;
		return -ENOMEM;


	lsm_early_cred(cred);
	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;
	task_ctx(current) = ctx;


@@ -1725,5 +1733,6 @@ DEFINE_LSM(apparmor) = {
	.name = "apparmor",
	.name = "apparmor",
	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
	.enabled = &apparmor_enabled,
	.enabled = &apparmor_enabled,
	.blobs = &apparmor_blob_sizes,
	.init = apparmor_init,
	.init = apparmor_init,
};
};
+87 −2
Original line number Original line Diff line number Diff line
@@ -41,6 +41,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);


char *lsm_names;
char *lsm_names;
static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;

/* Boot-time LSM user choice */
/* Boot-time LSM user choice */
static __initdata const char *chosen_lsm_order;
static __initdata const char *chosen_lsm_order;
static __initdata const char *chosen_major_lsm;
static __initdata const char *chosen_major_lsm;
@@ -139,6 +141,25 @@ static bool __init lsm_allowed(struct lsm_info *lsm)
	return true;
	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. */
/* Prepare LSM for initialization. */
static void __init prepare_lsm(struct lsm_info *lsm)
static void __init prepare_lsm(struct lsm_info *lsm)
{
{
@@ -153,6 +174,8 @@ static void __init prepare_lsm(struct lsm_info *lsm)
			exclusive = lsm;
			exclusive = lsm;
			init_debug("exclusive chosen: %s\n", lsm->name);
			init_debug("exclusive chosen: %s\n", lsm->name);
		}
		}

		lsm_set_blob_sizes(lsm->blobs);
	}
	}
}
}


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


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

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


@@ -382,6 +407,47 @@ int unregister_lsm_notifier(struct notifier_block *nb)
}
}
EXPORT_SYMBOL(unregister_lsm_notifier);
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.
 * Hook list operation macros.
 *
 *
@@ -1195,17 +1261,36 @@ void security_task_free(struct task_struct *task)


int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
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)
void security_cred_free(struct cred *cred)
{
{
	call_void_hook(cred_free, 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)
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)
void security_transfer_creds(struct cred *new, const struct cred *old)
Loading