diff options
| author | John Johansen <john.johansen@canonical.com> | 2013-08-14 14:27:36 -0400 |
|---|---|---|
| committer | John Johansen <john.johansen@canonical.com> | 2013-08-14 14:42:08 -0400 |
| commit | f8eb8a1324e81927b2c64823b2fc38386efd3fef (patch) | |
| tree | 78ef80523807aeb5b084b29f8b698601c71292b2 /security/apparmor | |
| parent | 84f1f787421cd83bb7dfb34d584586f6a5fe7baa (diff) | |
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: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Diffstat (limited to 'security/apparmor')
| -rw-r--r-- | security/apparmor/Kconfig | 12 | ||||
| -rw-r--r-- | security/apparmor/Makefile | 1 | ||||
| -rw-r--r-- | security/apparmor/apparmorfs.c | 37 | ||||
| -rw-r--r-- | security/apparmor/crypto.c | 97 | ||||
| -rw-r--r-- | security/apparmor/include/apparmorfs.h | 1 | ||||
| -rw-r--r-- | security/apparmor/include/crypto.h | 36 | ||||
| -rw-r--r-- | security/apparmor/include/policy.h | 1 | ||||
| -rw-r--r-- | security/apparmor/policy_unpack.c | 20 |
8 files changed, 199 insertions, 6 deletions
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 9b9013b2e321..d49c53960b60 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig | |||
| @@ -29,3 +29,15 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE | |||
| 29 | boot. | 29 | boot. |
| 30 | 30 | ||
| 31 | If you are unsure how to answer this question, answer 1. | 31 | If you are unsure how to answer this question, answer 1. |
| 32 | |||
| 33 | config SECURITY_APPARMOR_HASH | ||
| 34 | bool "SHA1 hash of loaded profiles" | ||
| 35 | depends on SECURITY_APPARMOR | ||
| 36 | depends on CRYPTO | ||
| 37 | select CRYPTO_SHA1 | ||
| 38 | default y | ||
| 39 | |||
| 40 | help | ||
| 41 | This option selects whether sha1 hashing is done against loaded | ||
| 42 | profiles and exported for inspection to user space via the apparmor | ||
| 43 | filesystem. | ||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 0831e049072d..d693df874818 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile | |||
| @@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o | |||
| 5 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ | 5 | apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ |
| 6 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ | 6 | path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ |
| 7 | resource.o sid.o file.o | 7 | resource.o sid.o file.o |
| 8 | apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o | ||
| 8 | 9 | ||
| 9 | clean-files := capability_names.h rlim_names.h | 10 | clean-files := capability_names.h rlim_names.h |
| 10 | 11 | ||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d708a55d072f..95c2b2689a03 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "include/apparmorfs.h" | 26 | #include "include/apparmorfs.h" |
| 27 | #include "include/audit.h" | 27 | #include "include/audit.h" |
| 28 | #include "include/context.h" | 28 | #include "include/context.h" |
| 29 | #include "include/crypto.h" | ||
| 29 | #include "include/policy.h" | 30 | #include "include/policy.h" |
| 30 | #include "include/resource.h" | 31 | #include "include/resource.h" |
| 31 | 32 | ||
| @@ -319,6 +320,34 @@ static const struct file_operations aa_fs_profattach_fops = { | |||
| 319 | .release = aa_fs_seq_profile_release, | 320 | .release = aa_fs_seq_profile_release, |
| 320 | }; | 321 | }; |
| 321 | 322 | ||
| 323 | static int aa_fs_seq_hash_show(struct seq_file *seq, void *v) | ||
| 324 | { | ||
| 325 | struct aa_replacedby *r = seq->private; | ||
| 326 | struct aa_profile *profile = aa_get_profile_rcu(&r->profile); | ||
| 327 | unsigned int i, size = aa_hash_size(); | ||
| 328 | |||
| 329 | if (profile->hash) { | ||
| 330 | for (i = 0; i < size; i++) | ||
| 331 | seq_printf(seq, "%.2x", profile->hash[i]); | ||
| 332 | seq_puts(seq, "\n"); | ||
| 333 | } | ||
| 334 | |||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static int aa_fs_seq_hash_open(struct inode *inode, struct file *file) | ||
| 339 | { | ||
| 340 | return single_open(file, aa_fs_seq_hash_show, inode->i_private); | ||
| 341 | } | ||
| 342 | |||
| 343 | static const struct file_operations aa_fs_seq_hash_fops = { | ||
| 344 | .owner = THIS_MODULE, | ||
| 345 | .open = aa_fs_seq_hash_open, | ||
| 346 | .read = seq_read, | ||
| 347 | .llseek = seq_lseek, | ||
| 348 | .release = single_release, | ||
| 349 | }; | ||
| 350 | |||
| 322 | /** fns to setup dynamic per profile/namespace files **/ | 351 | /** fns to setup dynamic per profile/namespace files **/ |
| 323 | void __aa_fs_profile_rmdir(struct aa_profile *profile) | 352 | void __aa_fs_profile_rmdir(struct aa_profile *profile) |
| 324 | { | 353 | { |
| @@ -420,6 +449,14 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) | |||
| 420 | goto fail; | 449 | goto fail; |
| 421 | profile->dents[AAFS_PROF_ATTACH] = dent; | 450 | profile->dents[AAFS_PROF_ATTACH] = dent; |
| 422 | 451 | ||
| 452 | if (profile->hash) { | ||
| 453 | dent = create_profile_file(dir, "sha1", profile, | ||
| 454 | &aa_fs_seq_hash_fops); | ||
| 455 | if (IS_ERR(dent)) | ||
| 456 | goto fail; | ||
| 457 | profile->dents[AAFS_PROF_HASH] = dent; | ||
| 458 | } | ||
| 459 | |||
| 423 | list_for_each_entry(child, &profile->base.profiles, base.list) { | 460 | list_for_each_entry(child, &profile->base.profiles, base.list) { |
| 424 | error = __aa_fs_profile_mkdir(child, prof_child_dir(profile)); | 461 | error = __aa_fs_profile_mkdir(child, prof_child_dir(profile)); |
| 425 | if (error) | 462 | if (error) |
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c new file mode 100644 index 000000000000..d6222ba4e919 --- /dev/null +++ b/security/apparmor/crypto.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * AppArmor security module | ||
| 3 | * | ||
| 4 | * This file contains AppArmor policy loading interface function definitions. | ||
| 5 | * | ||
| 6 | * Copyright 2013 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation, version 2 of the | ||
| 11 | * License. | ||
| 12 | * | ||
| 13 | * Fns to provide a checksum of policy that has been loaded this can be | ||
| 14 | * compared to userspace policy compiles to check loaded policy is what | ||
| 15 | * it should be. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/crypto.h> | ||
| 19 | |||
| 20 | #include "include/apparmor.h" | ||
| 21 | #include "include/crypto.h" | ||
| 22 | |||
| 23 | static unsigned int apparmor_hash_size; | ||
| 24 | |||
| 25 | static struct crypto_hash *apparmor_tfm; | ||
| 26 | |||
| 27 | unsigned int aa_hash_size(void) | ||
| 28 | { | ||
| 29 | return apparmor_hash_size; | ||
| 30 | } | ||
| 31 | |||
| 32 | int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, | ||
| 33 | size_t len) | ||
| 34 | { | ||
| 35 | struct scatterlist sg[2]; | ||
| 36 | struct hash_desc desc = { | ||
| 37 | .tfm = apparmor_tfm, | ||
| 38 | .flags = 0 | ||
| 39 | }; | ||
| 40 | int error = -ENOMEM; | ||
| 41 | u32 le32_version = cpu_to_le32(version); | ||
| 42 | |||
| 43 | if (!apparmor_tfm) | ||
| 44 | return 0; | ||
| 45 | |||
| 46 | sg_init_table(sg, 2); | ||
| 47 | sg_set_buf(&sg[0], &le32_version, 4); | ||
| 48 | sg_set_buf(&sg[1], (u8 *) start, len); | ||
| 49 | |||
| 50 | profile->hash = kzalloc(apparmor_hash_size, GFP_KERNEL); | ||
| 51 | if (!profile->hash) | ||
| 52 | goto fail; | ||
| 53 | |||
| 54 | error = crypto_hash_init(&desc); | ||
| 55 | if (error) | ||
| 56 | goto fail; | ||
| 57 | error = crypto_hash_update(&desc, &sg[0], 4); | ||
| 58 | if (error) | ||
| 59 | goto fail; | ||
| 60 | error = crypto_hash_update(&desc, &sg[1], len); | ||
| 61 | if (error) | ||
| 62 | goto fail; | ||
| 63 | error = crypto_hash_final(&desc, profile->hash); | ||
| 64 | if (error) | ||
| 65 | goto fail; | ||
| 66 | |||
| 67 | return 0; | ||
| 68 | |||
| 69 | fail: | ||
| 70 | kfree(profile->hash); | ||
| 71 | profile->hash = NULL; | ||
| 72 | |||
| 73 | return error; | ||
| 74 | } | ||
| 75 | |||
| 76 | static int __init init_profile_hash(void) | ||
| 77 | { | ||
| 78 | struct crypto_hash *tfm; | ||
| 79 | |||
| 80 | if (!apparmor_initialized) | ||
| 81 | return 0; | ||
| 82 | |||
| 83 | tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); | ||
| 84 | if (IS_ERR(tfm)) { | ||
| 85 | int error = PTR_ERR(tfm); | ||
| 86 | AA_ERROR("failed to setup profile sha1 hashing: %d\n", error); | ||
| 87 | return error; | ||
| 88 | } | ||
| 89 | apparmor_tfm = tfm; | ||
| 90 | apparmor_hash_size = crypto_hash_digestsize(apparmor_tfm); | ||
| 91 | |||
| 92 | aa_info_message("AppArmor sha1 policy hashing enabled"); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | late_initcall(init_profile_hash); | ||
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index f91712cf1b30..414e56878dd0 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h | |||
| @@ -82,6 +82,7 @@ enum aafs_prof_type { | |||
| 82 | AAFS_PROF_NAME, | 82 | AAFS_PROF_NAME, |
| 83 | AAFS_PROF_MODE, | 83 | AAFS_PROF_MODE, |
| 84 | AAFS_PROF_ATTACH, | 84 | AAFS_PROF_ATTACH, |
| 85 | AAFS_PROF_HASH, | ||
| 85 | AAFS_PROF_SIZEOF, | 86 | AAFS_PROF_SIZEOF, |
| 86 | }; | 87 | }; |
| 87 | 88 | ||
diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h new file mode 100644 index 000000000000..dc418e5024d9 --- /dev/null +++ b/security/apparmor/include/crypto.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /* | ||
| 2 | * AppArmor security module | ||
| 3 | * | ||
| 4 | * This file contains AppArmor policy loading interface function definitions. | ||
| 5 | * | ||
| 6 | * Copyright 2013 Canonical Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation, version 2 of the | ||
| 11 | * License. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __APPARMOR_CRYPTO_H | ||
| 15 | #define __APPARMOR_CRYPTO_H | ||
| 16 | |||
| 17 | #include "policy.h" | ||
| 18 | |||
| 19 | #ifdef CONFIG_SECURITY_APPARMOR_HASH | ||
| 20 | unsigned int aa_hash_size(void); | ||
| 21 | int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, | ||
| 22 | size_t len); | ||
| 23 | #else | ||
| 24 | static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version, | ||
| 25 | void *start, size_t len) | ||
| 26 | { | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | static inline unsigned int aa_hash_size(void) | ||
| 31 | { | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #endif /* __APPARMOR_CRYPTO_H */ | ||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 59b36372ae40..f2d4b6348cbc 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h | |||
| @@ -219,6 +219,7 @@ struct aa_profile { | |||
| 219 | struct aa_caps caps; | 219 | struct aa_caps caps; |
| 220 | struct aa_rlimit rlimits; | 220 | struct aa_rlimit rlimits; |
| 221 | 221 | ||
| 222 | unsigned char *hash; | ||
| 222 | char *dirname; | 223 | char *dirname; |
| 223 | struct dentry *dents[AAFS_PROF_SIZEOF]; | 224 | struct dentry *dents[AAFS_PROF_SIZEOF]; |
| 224 | }; | 225 | }; |
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index bdaef2e1b2a0..a689f10930b5 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "include/apparmor.h" | 24 | #include "include/apparmor.h" |
| 25 | #include "include/audit.h" | 25 | #include "include/audit.h" |
| 26 | #include "include/context.h" | 26 | #include "include/context.h" |
| 27 | #include "include/crypto.h" | ||
| 27 | #include "include/match.h" | 28 | #include "include/match.h" |
| 28 | #include "include/policy.h" | 29 | #include "include/policy.h" |
| 29 | #include "include/policy_unpack.h" | 30 | #include "include/policy_unpack.h" |
| @@ -758,10 +759,12 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) | |||
| 758 | 759 | ||
| 759 | *ns = NULL; | 760 | *ns = NULL; |
| 760 | while (e.pos < e.end) { | 761 | while (e.pos < e.end) { |
| 762 | void *start; | ||
| 761 | error = verify_header(&e, e.pos == e.start, ns); | 763 | error = verify_header(&e, e.pos == e.start, ns); |
| 762 | if (error) | 764 | if (error) |
| 763 | goto fail; | 765 | goto fail; |
| 764 | 766 | ||
| 767 | start = e.pos; | ||
| 765 | profile = unpack_profile(&e); | 768 | profile = unpack_profile(&e); |
| 766 | if (IS_ERR(profile)) { | 769 | if (IS_ERR(profile)) { |
| 767 | error = PTR_ERR(profile); | 770 | error = PTR_ERR(profile); |
| @@ -769,16 +772,18 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) | |||
| 769 | } | 772 | } |
| 770 | 773 | ||
| 771 | error = verify_profile(profile); | 774 | error = verify_profile(profile); |
| 772 | if (error) { | 775 | if (error) |
| 773 | aa_free_profile(profile); | 776 | goto fail_profile; |
| 774 | goto fail; | 777 | |
| 775 | } | 778 | error = aa_calc_profile_hash(profile, e.version, start, |
| 779 | e.pos - start); | ||
| 780 | if (error) | ||
| 781 | goto fail_profile; | ||
| 776 | 782 | ||
| 777 | ent = aa_load_ent_alloc(); | 783 | ent = aa_load_ent_alloc(); |
| 778 | if (!ent) { | 784 | if (!ent) { |
| 779 | error = -ENOMEM; | 785 | error = -ENOMEM; |
| 780 | aa_put_profile(profile); | 786 | goto fail_profile; |
| 781 | goto fail; | ||
| 782 | } | 787 | } |
| 783 | 788 | ||
| 784 | ent->new = profile; | 789 | ent->new = profile; |
| @@ -787,6 +792,9 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) | |||
| 787 | 792 | ||
| 788 | return 0; | 793 | return 0; |
| 789 | 794 | ||
| 795 | fail_profile: | ||
| 796 | aa_put_profile(profile); | ||
| 797 | |||
| 790 | fail: | 798 | fail: |
| 791 | list_for_each_entry_safe(ent, tmp, lh, list) { | 799 | list_for_each_entry_safe(ent, tmp, lh, list) { |
| 792 | list_del_init(&ent->list); | 800 | list_del_init(&ent->list); |
