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

Commit f8eb8a13 authored by John Johansen's avatar John Johansen
Browse files

apparmor: add the ability to report a sha1 hash of loaded policy



Provide userspace the ability to introspect a sha1 hash value for each
profile currently loaded.

Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
Acked-by: default avatarSeth Arnold <seth.arnold@canonical.com>
parent 84f1f787
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -29,3 +29,15 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
	  boot.

	  If you are unsure how to answer this question, answer 1.

config SECURITY_APPARMOR_HASH
	bool "SHA1 hash of loaded profiles"
	depends on SECURITY_APPARMOR
	depends on CRYPTO
	select CRYPTO_SHA1
	default y

	help
	  This option selects whether sha1 hashing is done against loaded
          profiles and exported for inspection to user space via the apparmor
          filesystem.
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
              path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
              resource.o sid.o file.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o

clean-files := capability_names.h rlim_names.h

+37 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "include/apparmorfs.h"
#include "include/audit.h"
#include "include/context.h"
#include "include/crypto.h"
#include "include/policy.h"
#include "include/resource.h"

@@ -319,6 +320,34 @@ static const struct file_operations aa_fs_profattach_fops = {
	.release	= aa_fs_seq_profile_release,
};

static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
{
	struct aa_replacedby *r = seq->private;
	struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
	unsigned int i, size = aa_hash_size();

	if (profile->hash) {
		for (i = 0; i < size; i++)
			seq_printf(seq, "%.2x", profile->hash[i]);
		seq_puts(seq, "\n");
	}

	return 0;
}

static int aa_fs_seq_hash_open(struct inode *inode, struct file *file)
{
	return single_open(file, aa_fs_seq_hash_show, inode->i_private);
}

static const struct file_operations aa_fs_seq_hash_fops = {
	.owner		= THIS_MODULE,
	.open		= aa_fs_seq_hash_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

/** fns to setup dynamic per profile/namespace files **/
void __aa_fs_profile_rmdir(struct aa_profile *profile)
{
@@ -420,6 +449,14 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
		goto fail;
	profile->dents[AAFS_PROF_ATTACH] = dent;

	if (profile->hash) {
		dent = create_profile_file(dir, "sha1", profile,
					   &aa_fs_seq_hash_fops);
		if (IS_ERR(dent))
			goto fail;
		profile->dents[AAFS_PROF_HASH] = dent;
	}

	list_for_each_entry(child, &profile->base.profiles, base.list) {
		error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
		if (error)
+97 −0
Original line number Diff line number Diff line
/*
 * AppArmor security module
 *
 * This file contains AppArmor policy loading interface function definitions.
 *
 * Copyright 2013 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 2 of the
 * License.
 *
 * Fns to provide a checksum of policy that has been loaded this can be
 * compared to userspace policy compiles to check loaded policy is what
 * it should be.
 */

#include <linux/crypto.h>

#include "include/apparmor.h"
#include "include/crypto.h"

static unsigned int apparmor_hash_size;

static struct crypto_hash *apparmor_tfm;

unsigned int aa_hash_size(void)
{
	return apparmor_hash_size;
}

int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
			 size_t len)
{
	struct scatterlist sg[2];
	struct hash_desc desc = {
		.tfm = apparmor_tfm,
		.flags = 0
	};
	int error = -ENOMEM;
	u32 le32_version = cpu_to_le32(version);

	if (!apparmor_tfm)
		return 0;

	sg_init_table(sg, 2);
	sg_set_buf(&sg[0], &le32_version, 4);
	sg_set_buf(&sg[1], (u8 *) start, len);

	profile->hash = kzalloc(apparmor_hash_size, GFP_KERNEL);
	if (!profile->hash)
		goto fail;

	error = crypto_hash_init(&desc);
	if (error)
		goto fail;
	error = crypto_hash_update(&desc, &sg[0], 4);
	if (error)
		goto fail;
	error = crypto_hash_update(&desc, &sg[1], len);
	if (error)
		goto fail;
	error = crypto_hash_final(&desc, profile->hash);
	if (error)
		goto fail;

	return 0;

fail:
	kfree(profile->hash);
	profile->hash = NULL;

	return error;
}

static int __init init_profile_hash(void)
{
	struct crypto_hash *tfm;

	if (!apparmor_initialized)
		return 0;

	tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(tfm)) {
		int error = PTR_ERR(tfm);
		AA_ERROR("failed to setup profile sha1 hashing: %d\n", error);
		return error;
	}
	apparmor_tfm = tfm;
	apparmor_hash_size = crypto_hash_digestsize(apparmor_tfm);

	aa_info_message("AppArmor sha1 policy hashing enabled");

	return 0;
}

late_initcall(init_profile_hash);
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ enum aafs_prof_type {
	AAFS_PROF_NAME,
	AAFS_PROF_MODE,
	AAFS_PROF_ATTACH,
	AAFS_PROF_HASH,
	AAFS_PROF_SIZEOF,
};

Loading