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

LSM: Infrastructure management of the file security



Move management of the file->f_security blob out of the
individual security modules and into the infrastructure.
The modules no longer allocate or free the data, instead
they 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 f28952ac
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2032,6 +2032,7 @@ struct security_hook_list {
 */
struct lsm_blob_sizes {
	int	lbs_cred;
	int	lbs_file;
};

/*
+4 −1
Original line number Diff line number Diff line
@@ -32,7 +32,10 @@ struct path;
				 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
				 AA_EXEC_MMAP | AA_MAY_LINK)

#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
static inline struct aa_file_ctx *file_ctx(struct file *file)
{
	return file->f_security + apparmor_blob_sizes.lbs_file;
}

/* struct aa_file_ctx - the AppArmor context the file was opened in
 * @lock: lock to update the ctx
+10 −9
Original line number Diff line number Diff line
@@ -434,21 +434,21 @@ static int apparmor_file_open(struct file *file)

static int apparmor_file_alloc_security(struct file *file)
{
	int error = 0;

	/* freed by apparmor_file_free_security */
	struct aa_file_ctx *ctx = file_ctx(file);
	struct aa_label *label = begin_current_label_crit_section();
	file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
	if (!file_ctx(file))
		error = -ENOMEM;
	end_current_label_crit_section(label);

	return error;
	spin_lock_init(&ctx->lock);
	rcu_assign_pointer(ctx->label, aa_get_label(label));
	end_current_label_crit_section(label);
	return 0;
}

static void apparmor_file_free_security(struct file *file)
{
	aa_free_file_ctx(file_ctx(file));
	struct aa_file_ctx *ctx = file_ctx(file);

	if (ctx)
		aa_put_label(rcu_access_pointer(ctx->label));
}

static int common_file_perm(const char *op, struct file *file, u32 mask)
@@ -1156,6 +1156,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 = {
	.lbs_cred = sizeof(struct aa_task_ctx *),
	.lbs_file = sizeof(struct aa_file_ctx),
};

static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+51 −3
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

static struct kmem_cache *lsm_file_cache;

char *lsm_names;
static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;

@@ -158,6 +160,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
		return;

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

/* Prepare LSM for initialization. */
@@ -279,6 +282,15 @@ static void __init ordered_lsm_init(void)
		prepare_lsm(*lsm);

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

	/*
	 * Create any kmem_caches needed for blobs
	 */
	if (blob_sizes.lbs_file)
		lsm_file_cache = kmem_cache_create("lsm_file_cache",
						   blob_sizes.lbs_file, 0,
						   SLAB_PANIC, NULL);

	for (lsm = ordered_lsms; *lsm; lsm++)
		initialize_lsm(*lsm);
@@ -448,6 +460,27 @@ void __init lsm_early_cred(struct cred *cred)
		panic("%s: Early cred alloc failed.\n", __func__);
}

/**
 * lsm_file_alloc - allocate a composite file blob
 * @file: the file that needs a blob
 *
 * Allocate the file blob for all the modules
 *
 * Returns 0, or -ENOMEM if memory can't be allocated.
 */
static int lsm_file_alloc(struct file *file)
{
	if (!lsm_file_cache) {
		file->f_security = NULL;
		return 0;
	}

	file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
	if (file->f_security == NULL)
		return -ENOMEM;
	return 0;
}

/*
 * Hook list operation macros.
 *
@@ -1144,12 +1177,27 @@ int security_file_permission(struct file *file, int mask)

int security_file_alloc(struct file *file)
{
	return call_int_hook(file_alloc_security, 0, file);
	int rc = lsm_file_alloc(file);

	if (rc)
		return rc;
	rc = call_int_hook(file_alloc_security, 0, file);
	if (unlikely(rc))
		security_file_free(file);
	return rc;
}

void security_file_free(struct file *file)
{
	void *blob;

	call_void_hook(file_free_security, file);

	blob = file->f_security;
	if (blob) {
		file->f_security = NULL;
		kmem_cache_free(lsm_file_cache, blob);
	}
}

int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1267,7 +1315,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
		return rc;

	rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
	if (rc)
	if (unlikely(rc))
		security_cred_free(cred);
	return rc;
}
@@ -1288,7 +1336,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
		return rc;

	rc = call_int_hook(cred_prepare, 0, new, old, gfp);
	if (rc)
	if (unlikely(rc))
		security_cred_free(new);
	return rc;
}
+2 −23
Original line number Diff line number Diff line
@@ -146,7 +146,6 @@ static int __init checkreqprot_setup(char *str)
__setup("checkreqprot=", checkreqprot_setup);

static struct kmem_cache *sel_inode_cache;
static struct kmem_cache *file_security_cache;

/**
 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
@@ -378,27 +377,15 @@ static void inode_free_security(struct inode *inode)

static int file_alloc_security(struct file *file)
{
	struct file_security_struct *fsec;
	struct file_security_struct *fsec = selinux_file(file);
	u32 sid = current_sid();

	fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
	if (!fsec)
		return -ENOMEM;

	fsec->sid = sid;
	fsec->fown_sid = sid;
	file->f_security = fsec;

	return 0;
}

static void file_free_security(struct file *file)
{
	struct file_security_struct *fsec = selinux_file(file);
	file->f_security = NULL;
	kmem_cache_free(file_security_cache, fsec);
}

static int superblock_alloc_security(struct super_block *sb)
{
	struct superblock_security_struct *sbsec;
@@ -3345,11 +3332,6 @@ static int selinux_file_alloc_security(struct file *file)
	return file_alloc_security(file);
}

static void selinux_file_free_security(struct file *file)
{
	file_free_security(file);
}

/*
 * Check whether a task has the ioctl permission and cmd
 * operation to an inode.
@@ -6646,6 +6628,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)

struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
	.lbs_cred = sizeof(struct task_security_struct),
	.lbs_file = sizeof(struct file_security_struct),
};

static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
@@ -6717,7 +6700,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {

	LSM_HOOK_INIT(file_permission, selinux_file_permission),
	LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
	LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
	LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
	LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
	LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
@@ -6902,9 +6884,6 @@ static __init int selinux_init(void)
	sel_inode_cache = kmem_cache_create("selinux_inode_security",
					    sizeof(struct inode_security_struct),
					    0, SLAB_PANIC, NULL);
	file_security_cache = kmem_cache_create("selinux_file_security",
					    sizeof(struct file_security_struct),
					    0, SLAB_PANIC, NULL);
	avc_init();

	avtab_cache_init();
Loading