Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+199 -6
+12
security/apparmor/Kconfig
··· 29 29 boot. 30 30 31 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.
+1
security/apparmor/Makefile
··· 5 5 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ 6 6 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ 7 7 resource.o sid.o file.o 8 + apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o 8 9 9 10 clean-files := capability_names.h rlim_names.h 10 11
+37
security/apparmor/apparmorfs.c
··· 26 26 #include "include/apparmorfs.h" 27 27 #include "include/audit.h" 28 28 #include "include/context.h" 29 + #include "include/crypto.h" 29 30 #include "include/policy.h" 30 31 #include "include/resource.h" 31 32 ··· 320 319 .release = aa_fs_seq_profile_release, 321 320 }; 322 321 322 + static int aa_fs_seq_hash_show(struct seq_file *seq, void *v) 323 + { 324 + struct aa_replacedby *r = seq->private; 325 + struct aa_profile *profile = aa_get_profile_rcu(&r->profile); 326 + unsigned int i, size = aa_hash_size(); 327 + 328 + if (profile->hash) { 329 + for (i = 0; i < size; i++) 330 + seq_printf(seq, "%.2x", profile->hash[i]); 331 + seq_puts(seq, "\n"); 332 + } 333 + 334 + return 0; 335 + } 336 + 337 + static int aa_fs_seq_hash_open(struct inode *inode, struct file *file) 338 + { 339 + return single_open(file, aa_fs_seq_hash_show, inode->i_private); 340 + } 341 + 342 + static const struct file_operations aa_fs_seq_hash_fops = { 343 + .owner = THIS_MODULE, 344 + .open = aa_fs_seq_hash_open, 345 + .read = seq_read, 346 + .llseek = seq_lseek, 347 + .release = single_release, 348 + }; 349 + 323 350 /** fns to setup dynamic per profile/namespace files **/ 324 351 void __aa_fs_profile_rmdir(struct aa_profile *profile) 325 352 { ··· 448 419 if (IS_ERR(dent)) 449 420 goto fail; 450 421 profile->dents[AAFS_PROF_ATTACH] = dent; 422 + 423 + if (profile->hash) { 424 + dent = create_profile_file(dir, "sha1", profile, 425 + &aa_fs_seq_hash_fops); 426 + if (IS_ERR(dent)) 427 + goto fail; 428 + profile->dents[AAFS_PROF_HASH] = dent; 429 + } 451 430 452 431 list_for_each_entry(child, &profile->base.profiles, base.list) { 453 432 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
+97
security/apparmor/crypto.c
··· 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);
+1
security/apparmor/include/apparmorfs.h
··· 82 82 AAFS_PROF_NAME, 83 83 AAFS_PROF_MODE, 84 84 AAFS_PROF_ATTACH, 85 + AAFS_PROF_HASH, 85 86 AAFS_PROF_SIZEOF, 86 87 }; 87 88
+36
security/apparmor/include/crypto.h
··· 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 */
+1
security/apparmor/include/policy.h
··· 219 219 struct aa_caps caps; 220 220 struct aa_rlimit rlimits; 221 221 222 + unsigned char *hash; 222 223 char *dirname; 223 224 struct dentry *dents[AAFS_PROF_SIZEOF]; 224 225 };
+14 -6
security/apparmor/policy_unpack.c
··· 24 24 #include "include/apparmor.h" 25 25 #include "include/audit.h" 26 26 #include "include/context.h" 27 + #include "include/crypto.h" 27 28 #include "include/match.h" 28 29 #include "include/policy.h" 29 30 #include "include/policy_unpack.h" ··· 759 758 760 759 *ns = NULL; 761 760 while (e.pos < e.end) { 761 + void *start; 762 762 error = verify_header(&e, e.pos == e.start, ns); 763 763 if (error) 764 764 goto fail; 765 765 766 + start = e.pos; 766 767 profile = unpack_profile(&e); 767 768 if (IS_ERR(profile)) { 768 769 error = PTR_ERR(profile); ··· 772 769 } 773 770 774 771 error = verify_profile(profile); 775 - if (error) { 776 - aa_free_profile(profile); 777 - goto fail; 778 - } 772 + if (error) 773 + goto fail_profile; 774 + 775 + error = aa_calc_profile_hash(profile, e.version, start, 776 + e.pos - start); 777 + if (error) 778 + goto fail_profile; 779 779 780 780 ent = aa_load_ent_alloc(); 781 781 if (!ent) { 782 782 error = -ENOMEM; 783 - aa_put_profile(profile); 784 - goto fail; 783 + goto fail_profile; 785 784 } 786 785 787 786 ent->new = profile; ··· 791 786 } 792 787 793 788 return 0; 789 + 790 + fail_profile: 791 + aa_put_profile(profile); 794 792 795 793 fail: 796 794 list_for_each_entry_safe(ent, tmp, lh, list) {