aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-08-14 14:27:36 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:08 -0400
commitf8eb8a1324e81927b2c64823b2fc38386efd3fef (patch)
tree78ef80523807aeb5b084b29f8b698601c71292b2 /security
parent84f1f787421cd83bb7dfb34d584586f6a5fe7baa (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')
-rw-r--r--security/apparmor/Kconfig12
-rw-r--r--security/apparmor/Makefile1
-rw-r--r--security/apparmor/apparmorfs.c37
-rw-r--r--security/apparmor/crypto.c97
-rw-r--r--security/apparmor/include/apparmorfs.h1
-rw-r--r--security/apparmor/include/crypto.h36
-rw-r--r--security/apparmor/include/policy.h1
-rw-r--r--security/apparmor/policy_unpack.c20
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
33config 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
5apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ 5apparmor-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
8apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
8 9
9clean-files := capability_names.h rlim_names.h 10clean-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
323static 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
338static 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
343static 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 **/
323void __aa_fs_profile_rmdir(struct aa_profile *profile) 352void __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
23static unsigned int apparmor_hash_size;
24
25static struct crypto_hash *apparmor_tfm;
26
27unsigned int aa_hash_size(void)
28{
29 return apparmor_hash_size;
30}
31
32int 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
69fail:
70 kfree(profile->hash);
71 profile->hash = NULL;
72
73 return error;
74}
75
76static 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
97late_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
20unsigned int aa_hash_size(void);
21int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
22 size_t len);
23#else
24static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version,
25 void *start, size_t len)
26{
27 return 0;
28}
29
30static 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
795fail_profile:
796 aa_put_profile(profile);
797
790fail: 798fail:
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);