diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /security/integrity | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/ima/Kconfig | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 6 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_audit.c | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima_crypto.c | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima_iint.c | 86 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 1 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 310 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima_queue.c | 1 |
11 files changed, 171 insertions, 252 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 53d9764e8f09..3d7846de8069 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -3,6 +3,7 @@ | |||
3 | config IMA | 3 | config IMA |
4 | bool "Integrity Measurement Architecture(IMA)" | 4 | bool "Integrity Measurement Architecture(IMA)" |
5 | depends on ACPI | 5 | depends on ACPI |
6 | depends on SECURITY | ||
6 | select SECURITYFS | 7 | select SECURITYFS |
7 | select CRYPTO | 8 | select CRYPTO |
8 | select CRYPTO_HMAC | 9 | select CRYPTO_HMAC |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 165eb5397ea5..47fb65d1fcbd 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -65,7 +65,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
65 | const char *cause, int result, int info); | 65 | const char *cause, int result, int info); |
66 | 66 | ||
67 | /* Internal IMA function definitions */ | 67 | /* Internal IMA function definitions */ |
68 | void ima_iintcache_init(void); | ||
69 | int ima_init(void); | 68 | int ima_init(void); |
70 | void ima_cleanup(void); | 69 | void ima_cleanup(void); |
71 | int ima_fs_init(void); | 70 | int ima_fs_init(void); |
@@ -97,7 +96,6 @@ static inline unsigned long ima_hash_key(u8 *digest) | |||
97 | 96 | ||
98 | /* iint cache flags */ | 97 | /* iint cache flags */ |
99 | #define IMA_MEASURED 1 | 98 | #define IMA_MEASURED 1 |
100 | #define IMA_IINT_DUMP_STACK 512 | ||
101 | 99 | ||
102 | /* integrity data associated with an inode */ | 100 | /* integrity data associated with an inode */ |
103 | struct ima_iint_cache { | 101 | struct ima_iint_cache { |
@@ -128,13 +126,11 @@ void ima_template_show(struct seq_file *m, void *e, | |||
128 | */ | 126 | */ |
129 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | 127 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); |
130 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | 128 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); |
131 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode); | ||
132 | void ima_iint_delete(struct inode *inode); | ||
133 | void iint_free(struct kref *kref); | 129 | void iint_free(struct kref *kref); |
134 | void iint_rcu_free(struct rcu_head *rcu); | 130 | void iint_rcu_free(struct rcu_head *rcu); |
135 | 131 | ||
136 | /* IMA policy related functions */ | 132 | /* IMA policy related functions */ |
137 | enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | 133 | enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; |
138 | 134 | ||
139 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); |
140 | void ima_init_policy(void); | 136 | void ima_init_policy(void); |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 3cd58b60afd2..52015d098fdf 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * and store_template. | 13 | * and store_template. |
14 | */ | 14 | */ |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | ||
16 | 17 | ||
17 | #include "ima.h" | 18 | #include "ima.h" |
18 | static const char *IMA_TEMPLATE_NAME = "ima"; | 19 | static const char *IMA_TEMPLATE_NAME = "ima"; |
@@ -95,12 +96,12 @@ err_out: | |||
95 | * ima_must_measure - measure decision based on policy. | 96 | * ima_must_measure - measure decision based on policy. |
96 | * @inode: pointer to inode to measure | 97 | * @inode: pointer to inode to measure |
97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | 98 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) |
98 | * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP) | 99 | * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) |
99 | * | 100 | * |
100 | * The policy is defined in terms of keypairs: | 101 | * The policy is defined in terms of keypairs: |
101 | * subj=, obj=, type=, func=, mask=, fsmagic= | 102 | * subj=, obj=, type=, func=, mask=, fsmagic= |
102 | * subj,obj, and type: are LSM specific. | 103 | * subj,obj, and type: are LSM specific. |
103 | * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP | 104 | * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP |
104 | * mask: contains the permission mask | 105 | * mask: contains the permission mask |
105 | * fsmagic: hex value | 106 | * fsmagic: hex value |
106 | * | 107 | * |
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index ff513ff737f5..5af76340470c 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/gfp.h> | ||
14 | #include <linux/audit.h> | 15 | #include <linux/audit.h> |
15 | #include "ima.h" | 16 | #include "ima.h" |
16 | 17 | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 46642a19bc78..952e51373f58 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/crypto.h> | 18 | #include <linux/crypto.h> |
19 | #include <linux/scatterlist.h> | 19 | #include <linux/scatterlist.h> |
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/slab.h> | ||
21 | #include "ima.h" | 22 | #include "ima.h" |
22 | 23 | ||
23 | static int init_desc(struct hash_desc *desc) | 24 | static int init_desc(struct hash_desc *desc) |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 0c72c9c38956..07cb9c338cc4 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * current measurement list and IMA statistics | 16 | * current measurement list and IMA statistics |
17 | */ | 17 | */ |
18 | #include <linux/fcntl.h> | 18 | #include <linux/fcntl.h> |
19 | #include <linux/slab.h> | ||
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
20 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
21 | #include <linux/rculist.h> | 22 | #include <linux/rculist.h> |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index a4e2b1dac943..2c744d488014 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
@@ -14,13 +14,12 @@ | |||
14 | * - cache integrity information associated with an inode | 14 | * - cache integrity information associated with an inode |
15 | * using a radix tree. | 15 | * using a radix tree. |
16 | */ | 16 | */ |
17 | #include <linux/slab.h> | ||
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
18 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
19 | #include <linux/radix-tree.h> | 20 | #include <linux/radix-tree.h> |
20 | #include "ima.h" | 21 | #include "ima.h" |
21 | 22 | ||
22 | #define ima_iint_delete ima_inode_free | ||
23 | |||
24 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | 23 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); |
25 | DEFINE_SPINLOCK(ima_iint_lock); | 24 | DEFINE_SPINLOCK(ima_iint_lock); |
26 | 25 | ||
@@ -45,22 +44,18 @@ out: | |||
45 | return iint; | 44 | return iint; |
46 | } | 45 | } |
47 | 46 | ||
48 | /* Allocate memory for the iint associated with the inode | 47 | /** |
49 | * from the iint_cache slab, initialize the iint, and | 48 | * ima_inode_alloc - allocate an iint associated with an inode |
50 | * insert it into the radix tree. | 49 | * @inode: pointer to the inode |
51 | * | ||
52 | * On success return a pointer to the iint; on failure return NULL. | ||
53 | */ | 50 | */ |
54 | struct ima_iint_cache *ima_iint_insert(struct inode *inode) | 51 | int ima_inode_alloc(struct inode *inode) |
55 | { | 52 | { |
56 | struct ima_iint_cache *iint = NULL; | 53 | struct ima_iint_cache *iint = NULL; |
57 | int rc = 0; | 54 | int rc = 0; |
58 | 55 | ||
59 | if (!ima_initialized) | ||
60 | return iint; | ||
61 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | 56 | iint = kmem_cache_alloc(iint_cache, GFP_NOFS); |
62 | if (!iint) | 57 | if (!iint) |
63 | return iint; | 58 | return -ENOMEM; |
64 | 59 | ||
65 | rc = radix_tree_preload(GFP_NOFS); | 60 | rc = radix_tree_preload(GFP_NOFS); |
66 | if (rc < 0) | 61 | if (rc < 0) |
@@ -69,67 +64,14 @@ struct ima_iint_cache *ima_iint_insert(struct inode *inode) | |||
69 | spin_lock(&ima_iint_lock); | 64 | spin_lock(&ima_iint_lock); |
70 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | 65 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); |
71 | spin_unlock(&ima_iint_lock); | 66 | spin_unlock(&ima_iint_lock); |
67 | radix_tree_preload_end(); | ||
72 | out: | 68 | out: |
73 | if (rc < 0) { | 69 | if (rc < 0) |
74 | kmem_cache_free(iint_cache, iint); | 70 | kmem_cache_free(iint_cache, iint); |
75 | if (rc == -EEXIST) { | ||
76 | spin_lock(&ima_iint_lock); | ||
77 | iint = radix_tree_lookup(&ima_iint_store, | ||
78 | (unsigned long)inode); | ||
79 | spin_unlock(&ima_iint_lock); | ||
80 | } else | ||
81 | iint = NULL; | ||
82 | } | ||
83 | radix_tree_preload_end(); | ||
84 | return iint; | ||
85 | } | ||
86 | 71 | ||
87 | /** | 72 | return rc; |
88 | * ima_inode_alloc - allocate an iint associated with an inode | ||
89 | * @inode: pointer to the inode | ||
90 | * | ||
91 | * Return 0 on success, 1 on failure. | ||
92 | */ | ||
93 | int ima_inode_alloc(struct inode *inode) | ||
94 | { | ||
95 | struct ima_iint_cache *iint; | ||
96 | |||
97 | if (!ima_initialized) | ||
98 | return 0; | ||
99 | |||
100 | iint = ima_iint_insert(inode); | ||
101 | if (!iint) | ||
102 | return 1; | ||
103 | return 0; | ||
104 | } | 73 | } |
105 | 74 | ||
106 | /* ima_iint_find_insert_get - get the iint associated with an inode | ||
107 | * | ||
108 | * Most insertions are done at inode_alloc, except those allocated | ||
109 | * before late_initcall. When the iint does not exist, allocate it, | ||
110 | * initialize and insert it, and increment the iint refcount. | ||
111 | * | ||
112 | * (Can't initialize at security_initcall before any inodes are | ||
113 | * allocated, got to wait at least until proc_init.) | ||
114 | * | ||
115 | * Return the iint. | ||
116 | */ | ||
117 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode) | ||
118 | { | ||
119 | struct ima_iint_cache *iint = NULL; | ||
120 | |||
121 | iint = ima_iint_find_get(inode); | ||
122 | if (iint) | ||
123 | return iint; | ||
124 | |||
125 | iint = ima_iint_insert(inode); | ||
126 | if (iint) | ||
127 | kref_get(&iint->refcount); | ||
128 | |||
129 | return iint; | ||
130 | } | ||
131 | EXPORT_SYMBOL_GPL(ima_iint_find_insert_get); | ||
132 | |||
133 | /* iint_free - called when the iint refcount goes to zero */ | 75 | /* iint_free - called when the iint refcount goes to zero */ |
134 | void iint_free(struct kref *kref) | 76 | void iint_free(struct kref *kref) |
135 | { | 77 | { |
@@ -164,17 +106,15 @@ void iint_rcu_free(struct rcu_head *rcu_head) | |||
164 | } | 106 | } |
165 | 107 | ||
166 | /** | 108 | /** |
167 | * ima_iint_delete - called on integrity_inode_free | 109 | * ima_inode_free - called on security_inode_free |
168 | * @inode: pointer to the inode | 110 | * @inode: pointer to the inode |
169 | * | 111 | * |
170 | * Free the integrity information(iint) associated with an inode. | 112 | * Free the integrity information(iint) associated with an inode. |
171 | */ | 113 | */ |
172 | void ima_iint_delete(struct inode *inode) | 114 | void ima_inode_free(struct inode *inode) |
173 | { | 115 | { |
174 | struct ima_iint_cache *iint; | 116 | struct ima_iint_cache *iint; |
175 | 117 | ||
176 | if (!ima_initialized) | ||
177 | return; | ||
178 | spin_lock(&ima_iint_lock); | 118 | spin_lock(&ima_iint_lock); |
179 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | 119 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); |
180 | spin_unlock(&ima_iint_lock); | 120 | spin_unlock(&ima_iint_lock); |
@@ -196,9 +136,11 @@ static void init_once(void *foo) | |||
196 | kref_set(&iint->refcount, 1); | 136 | kref_set(&iint->refcount, 1); |
197 | } | 137 | } |
198 | 138 | ||
199 | void __init ima_iintcache_init(void) | 139 | static int __init ima_iintcache_init(void) |
200 | { | 140 | { |
201 | iint_cache = | 141 | iint_cache = |
202 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | 142 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, |
203 | SLAB_PANIC, init_once); | 143 | SLAB_PANIC, init_once); |
144 | return 0; | ||
204 | } | 145 | } |
146 | security_initcall(ima_iintcache_init); | ||
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index a40da7ae5900..b1bcb702a27c 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/scatterlist.h> | 18 | #include <linux/scatterlist.h> |
19 | #include <linux/slab.h> | ||
19 | #include <linux/err.h> | 20 | #include <linux/err.h> |
20 | #include "ima.h" | 21 | #include "ima.h" |
21 | 22 | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index b85e61bcf246..b2c89d9de2a4 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -13,14 +13,15 @@ | |||
13 | * License. | 13 | * License. |
14 | * | 14 | * |
15 | * File: ima_main.c | 15 | * File: ima_main.c |
16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, | 16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, |
17 | * and ima_path_check. | 17 | * and ima_file_check. |
18 | */ | 18 | */ |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/file.h> | 20 | #include <linux/file.h> |
21 | #include <linux/binfmts.h> | 21 | #include <linux/binfmts.h> |
22 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
23 | #include <linux/mman.h> | 23 | #include <linux/mman.h> |
24 | #include <linux/slab.h> | ||
24 | 25 | ||
25 | #include "ima.h" | 26 | #include "ima.h" |
26 | 27 | ||
@@ -35,50 +36,53 @@ static int __init hash_setup(char *str) | |||
35 | } | 36 | } |
36 | __setup("ima_hash=", hash_setup); | 37 | __setup("ima_hash=", hash_setup); |
37 | 38 | ||
38 | /** | 39 | struct ima_imbalance { |
39 | * ima_file_free - called on __fput() | 40 | struct hlist_node node; |
40 | * @file: pointer to file structure being freed | 41 | unsigned long fsmagic; |
42 | }; | ||
43 | |||
44 | /* | ||
45 | * ima_limit_imbalance - emit one imbalance message per filesystem type | ||
41 | * | 46 | * |
42 | * Flag files that changed, based on i_version; | 47 | * Maintain list of filesystem types that do not measure files properly. |
43 | * and decrement the iint readcount/writecount. | 48 | * Return false if unknown, true if known. |
44 | */ | 49 | */ |
45 | void ima_file_free(struct file *file) | 50 | static bool ima_limit_imbalance(struct file *file) |
46 | { | 51 | { |
47 | struct inode *inode = file->f_dentry->d_inode; | 52 | static DEFINE_SPINLOCK(ima_imbalance_lock); |
48 | struct ima_iint_cache *iint; | 53 | static HLIST_HEAD(ima_imbalance_list); |
49 | 54 | ||
50 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 55 | struct super_block *sb = file->f_dentry->d_sb; |
51 | return; | 56 | struct ima_imbalance *entry; |
52 | iint = ima_iint_find_get(inode); | 57 | struct hlist_node *node; |
53 | if (!iint) | 58 | bool found = false; |
54 | return; | 59 | |
55 | 60 | rcu_read_lock(); | |
56 | mutex_lock(&iint->mutex); | 61 | hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) { |
57 | if (iint->opencount <= 0) { | 62 | if (entry->fsmagic == sb->s_magic) { |
58 | printk(KERN_INFO | 63 | found = true; |
59 | "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n", | 64 | break; |
60 | __FUNCTION__, file->f_dentry->d_name.name, | ||
61 | iint->readcount, iint->writecount, | ||
62 | iint->opencount, atomic_long_read(&file->f_count)); | ||
63 | if (!(iint->flags & IMA_IINT_DUMP_STACK)) { | ||
64 | dump_stack(); | ||
65 | iint->flags |= IMA_IINT_DUMP_STACK; | ||
66 | } | 65 | } |
67 | } | 66 | } |
68 | iint->opencount--; | 67 | rcu_read_unlock(); |
69 | 68 | if (found) | |
70 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 69 | goto out; |
71 | iint->readcount--; | ||
72 | 70 | ||
73 | if (file->f_mode & FMODE_WRITE) { | 71 | entry = kmalloc(sizeof(*entry), GFP_NOFS); |
74 | iint->writecount--; | 72 | if (!entry) |
75 | if (iint->writecount == 0) { | 73 | goto out; |
76 | if (iint->version != inode->i_version) | 74 | entry->fsmagic = sb->s_magic; |
77 | iint->flags &= ~IMA_MEASURED; | 75 | spin_lock(&ima_imbalance_lock); |
78 | } | 76 | /* |
79 | } | 77 | * we could have raced and something else might have added this fs |
80 | mutex_unlock(&iint->mutex); | 78 | * to the list, but we don't really care |
81 | kref_put(&iint->refcount, iint_free); | 79 | */ |
80 | hlist_add_head_rcu(&entry->node, &ima_imbalance_list); | ||
81 | spin_unlock(&ima_imbalance_lock); | ||
82 | printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n", | ||
83 | entry->fsmagic); | ||
84 | out: | ||
85 | return found; | ||
82 | } | 86 | } |
83 | 87 | ||
84 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | 88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. |
@@ -111,196 +115,142 @@ static void ima_read_write_check(enum iint_pcr_error error, | |||
111 | } | 115 | } |
112 | } | 116 | } |
113 | 117 | ||
114 | static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | 118 | /* |
115 | const unsigned char *filename) | 119 | * Update the counts given an fmode_t |
120 | */ | ||
121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | ||
116 | { | 122 | { |
117 | int rc = 0; | 123 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
118 | |||
119 | iint->opencount++; | ||
120 | iint->readcount++; | ||
121 | |||
122 | rc = ima_collect_measurement(iint, file); | ||
123 | if (!rc) | ||
124 | ima_store_measurement(iint, file, filename); | ||
125 | return rc; | ||
126 | } | ||
127 | 124 | ||
128 | static void ima_update_counts(struct ima_iint_cache *iint, int mask) | ||
129 | { | ||
130 | iint->opencount++; | 125 | iint->opencount++; |
131 | if ((mask & MAY_WRITE) || (mask == 0)) | 126 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
132 | iint->writecount++; | ||
133 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
134 | iint->readcount++; | 127 | iint->readcount++; |
128 | if (mode & FMODE_WRITE) | ||
129 | iint->writecount++; | ||
135 | } | 130 | } |
136 | 131 | ||
137 | /** | 132 | /* |
138 | * ima_path_check - based on policy, collect/store measurement. | 133 | * ima_counts_get - increment file counts |
139 | * @path: contains a pointer to the path to be measured | ||
140 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
141 | * | ||
142 | * Measure the file being open for readonly, based on the | ||
143 | * ima_must_measure() policy decision. | ||
144 | * | 134 | * |
145 | * Keep read/write counters for all files, but only | 135 | * Maintain read/write counters for all files, but only |
146 | * invalidate the PCR for measured files: | 136 | * invalidate the PCR for measured files: |
147 | * - Opening a file for write when already open for read, | 137 | * - Opening a file for write when already open for read, |
148 | * results in a time of measure, time of use (ToMToU) error. | 138 | * results in a time of measure, time of use (ToMToU) error. |
149 | * - Opening a file for read when already open for write, | 139 | * - Opening a file for read when already open for write, |
150 | * could result in a file measurement error. | 140 | * could result in a file measurement error. |
151 | * | 141 | * |
152 | * Always return 0 and audit dentry_open failures. | ||
153 | * (Return code will be based upon measurement appraisal.) | ||
154 | */ | 142 | */ |
155 | int ima_path_check(struct path *path, int mask, int update_counts) | 143 | void ima_counts_get(struct file *file) |
156 | { | 144 | { |
157 | struct inode *inode = path->dentry->d_inode; | 145 | struct dentry *dentry = file->f_path.dentry; |
146 | struct inode *inode = dentry->d_inode; | ||
147 | fmode_t mode = file->f_mode; | ||
158 | struct ima_iint_cache *iint; | 148 | struct ima_iint_cache *iint; |
159 | struct file *file = NULL; | ||
160 | int rc; | 149 | int rc; |
161 | 150 | ||
162 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 151 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
163 | return 0; | 152 | return; |
164 | iint = ima_iint_find_insert_get(inode); | 153 | iint = ima_iint_find_get(inode); |
165 | if (!iint) | 154 | if (!iint) |
166 | return 0; | 155 | return; |
167 | |||
168 | mutex_lock(&iint->mutex); | 156 | mutex_lock(&iint->mutex); |
169 | if (update_counts) | 157 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); |
170 | ima_update_counts(iint, mask); | ||
171 | |||
172 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); | ||
173 | if (rc < 0) | 158 | if (rc < 0) |
174 | goto out; | 159 | goto out; |
175 | 160 | ||
176 | if ((mask & MAY_WRITE) || (mask == 0)) | 161 | if (mode & FMODE_WRITE) { |
177 | ima_read_write_check(TOMTOU, iint, inode, | 162 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); |
178 | path->dentry->d_name.name); | ||
179 | |||
180 | if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ) | ||
181 | goto out; | 163 | goto out; |
182 | |||
183 | ima_read_write_check(OPEN_WRITERS, iint, inode, | ||
184 | path->dentry->d_name.name); | ||
185 | if (!(iint->flags & IMA_MEASURED)) { | ||
186 | struct dentry *dentry = dget(path->dentry); | ||
187 | struct vfsmount *mnt = mntget(path->mnt); | ||
188 | |||
189 | file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE, | ||
190 | current_cred()); | ||
191 | if (IS_ERR(file)) { | ||
192 | int audit_info = 0; | ||
193 | |||
194 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
195 | dentry->d_name.name, | ||
196 | "add_measurement", | ||
197 | "dentry_open failed", | ||
198 | 1, audit_info); | ||
199 | file = NULL; | ||
200 | goto out; | ||
201 | } | ||
202 | rc = get_path_measurement(iint, file, dentry->d_name.name); | ||
203 | } | 164 | } |
165 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | ||
204 | out: | 166 | out: |
167 | ima_inc_counts(iint, file->f_mode); | ||
205 | mutex_unlock(&iint->mutex); | 168 | mutex_unlock(&iint->mutex); |
206 | if (file) | 169 | |
207 | fput(file); | ||
208 | kref_put(&iint->refcount, iint_free); | 170 | kref_put(&iint->refcount, iint_free); |
209 | return 0; | ||
210 | } | 171 | } |
211 | EXPORT_SYMBOL_GPL(ima_path_check); | ||
212 | 172 | ||
213 | static int process_measurement(struct file *file, const unsigned char *filename, | 173 | /* |
214 | int mask, int function) | 174 | * Decrement ima counts |
175 | */ | ||
176 | static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | ||
177 | struct file *file) | ||
215 | { | 178 | { |
216 | struct inode *inode = file->f_dentry->d_inode; | 179 | mode_t mode = file->f_mode; |
217 | struct ima_iint_cache *iint; | 180 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
218 | int rc; | ||
219 | 181 | ||
220 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 182 | iint->opencount--; |
221 | return 0; | 183 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
222 | iint = ima_iint_find_insert_get(inode); | 184 | iint->readcount--; |
223 | if (!iint) | 185 | if (mode & FMODE_WRITE) { |
224 | return -ENOMEM; | 186 | iint->writecount--; |
225 | 187 | if (iint->writecount == 0) { | |
226 | mutex_lock(&iint->mutex); | 188 | if (iint->version != inode->i_version) |
227 | rc = ima_must_measure(iint, inode, mask, function); | 189 | iint->flags &= ~IMA_MEASURED; |
228 | if (rc != 0) | 190 | } |
229 | goto out; | 191 | } |
230 | 192 | ||
231 | rc = ima_collect_measurement(iint, file); | 193 | if (((iint->opencount < 0) || |
232 | if (!rc) | 194 | (iint->readcount < 0) || |
233 | ima_store_measurement(iint, file, filename); | 195 | (iint->writecount < 0)) && |
234 | out: | 196 | !ima_limit_imbalance(file)) { |
235 | mutex_unlock(&iint->mutex); | 197 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", |
236 | kref_put(&iint->refcount, iint_free); | 198 | __FUNCTION__, iint->readcount, iint->writecount, |
237 | return rc; | 199 | iint->opencount); |
200 | dump_stack(); | ||
201 | } | ||
238 | } | 202 | } |
239 | 203 | ||
240 | /* | 204 | /** |
241 | * ima_counts_put - decrement file counts | 205 | * ima_file_free - called on __fput() |
206 | * @file: pointer to file structure being freed | ||
242 | * | 207 | * |
243 | * File counts are incremented in ima_path_check. On file open | 208 | * Flag files that changed, based on i_version; |
244 | * error, such as ETXTBSY, decrement the counts to prevent | 209 | * and decrement the iint readcount/writecount. |
245 | * unnecessary imbalance messages. | ||
246 | */ | 210 | */ |
247 | void ima_counts_put(struct path *path, int mask) | 211 | void ima_file_free(struct file *file) |
248 | { | 212 | { |
249 | struct inode *inode = path->dentry->d_inode; | 213 | struct inode *inode = file->f_dentry->d_inode; |
250 | struct ima_iint_cache *iint; | 214 | struct ima_iint_cache *iint; |
251 | 215 | ||
252 | /* The inode may already have been freed, freeing the iint | 216 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
253 | * with it. Verify the inode is not NULL before dereferencing | ||
254 | * it. | ||
255 | */ | ||
256 | if (!ima_initialized || !inode || !S_ISREG(inode->i_mode)) | ||
257 | return; | 217 | return; |
258 | iint = ima_iint_find_insert_get(inode); | 218 | iint = ima_iint_find_get(inode); |
259 | if (!iint) | 219 | if (!iint) |
260 | return; | 220 | return; |
261 | 221 | ||
262 | mutex_lock(&iint->mutex); | 222 | mutex_lock(&iint->mutex); |
263 | iint->opencount--; | 223 | ima_dec_counts(iint, inode, file); |
264 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
265 | iint->writecount--; | ||
266 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
267 | iint->readcount--; | ||
268 | mutex_unlock(&iint->mutex); | 224 | mutex_unlock(&iint->mutex); |
269 | |||
270 | kref_put(&iint->refcount, iint_free); | 225 | kref_put(&iint->refcount, iint_free); |
271 | } | 226 | } |
272 | 227 | ||
273 | /* | 228 | static int process_measurement(struct file *file, const unsigned char *filename, |
274 | * ima_counts_get - increment file counts | 229 | int mask, int function) |
275 | * | ||
276 | * - for IPC shm and shmat file. | ||
277 | * - for nfsd exported files. | ||
278 | * | ||
279 | * Increment the counts for these files to prevent unnecessary | ||
280 | * imbalance messages. | ||
281 | */ | ||
282 | void ima_counts_get(struct file *file) | ||
283 | { | 230 | { |
284 | struct inode *inode = file->f_dentry->d_inode; | 231 | struct inode *inode = file->f_dentry->d_inode; |
285 | struct ima_iint_cache *iint; | 232 | struct ima_iint_cache *iint; |
233 | int rc; | ||
286 | 234 | ||
287 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 235 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
288 | return; | 236 | return 0; |
289 | iint = ima_iint_find_insert_get(inode); | 237 | iint = ima_iint_find_get(inode); |
290 | if (!iint) | 238 | if (!iint) |
291 | return; | 239 | return -ENOMEM; |
240 | |||
292 | mutex_lock(&iint->mutex); | 241 | mutex_lock(&iint->mutex); |
293 | iint->opencount++; | 242 | rc = ima_must_measure(iint, inode, mask, function); |
294 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 243 | if (rc != 0) |
295 | iint->readcount++; | 244 | goto out; |
296 | 245 | ||
297 | if (file->f_mode & FMODE_WRITE) | 246 | rc = ima_collect_measurement(iint, file); |
298 | iint->writecount++; | 247 | if (!rc) |
248 | ima_store_measurement(iint, file, filename); | ||
249 | out: | ||
299 | mutex_unlock(&iint->mutex); | 250 | mutex_unlock(&iint->mutex); |
300 | |||
301 | kref_put(&iint->refcount, iint_free); | 251 | kref_put(&iint->refcount, iint_free); |
252 | return rc; | ||
302 | } | 253 | } |
303 | EXPORT_SYMBOL_GPL(ima_counts_get); | ||
304 | 254 | ||
305 | /** | 255 | /** |
306 | * ima_file_mmap - based on policy, collect/store measurement. | 256 | * ima_file_mmap - based on policy, collect/store measurement. |
@@ -347,11 +297,31 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
347 | return 0; | 297 | return 0; |
348 | } | 298 | } |
349 | 299 | ||
300 | /** | ||
301 | * ima_path_check - based on policy, collect/store measurement. | ||
302 | * @file: pointer to the file to be measured | ||
303 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
304 | * | ||
305 | * Measure files based on the ima_must_measure() policy decision. | ||
306 | * | ||
307 | * Always return 0 and audit dentry_open failures. | ||
308 | * (Return code will be based upon measurement appraisal.) | ||
309 | */ | ||
310 | int ima_file_check(struct file *file, int mask) | ||
311 | { | ||
312 | int rc; | ||
313 | |||
314 | rc = process_measurement(file, file->f_dentry->d_name.name, | ||
315 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | ||
316 | FILE_CHECK); | ||
317 | return 0; | ||
318 | } | ||
319 | EXPORT_SYMBOL_GPL(ima_file_check); | ||
320 | |||
350 | static int __init init_ima(void) | 321 | static int __init init_ima(void) |
351 | { | 322 | { |
352 | int error; | 323 | int error; |
353 | 324 | ||
354 | ima_iintcache_init(); | ||
355 | error = ima_init(); | 325 | error = ima_init(); |
356 | ima_initialized = 1; | 326 | ima_initialized = 1; |
357 | return error; | 327 | return error; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e1278399b345..8643a93c5963 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
16 | #include <linux/magic.h> | 16 | #include <linux/magic.h> |
17 | #include <linux/parser.h> | 17 | #include <linux/parser.h> |
18 | #include <linux/slab.h> | ||
18 | 19 | ||
19 | #include "ima.h" | 20 | #include "ima.h" |
20 | 21 | ||
@@ -67,7 +68,7 @@ static struct ima_measure_rule_entry default_rules[] = { | |||
67 | .flags = IMA_FUNC | IMA_MASK}, | 68 | .flags = IMA_FUNC | IMA_MASK}, |
68 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | 69 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, |
69 | .flags = IMA_FUNC | IMA_MASK}, | 70 | .flags = IMA_FUNC | IMA_MASK}, |
70 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, | 71 | {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = 0, |
71 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 72 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
72 | }; | 73 | }; |
73 | 74 | ||
@@ -282,8 +283,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
282 | break; | 283 | break; |
283 | case Opt_func: | 284 | case Opt_func: |
284 | audit_log_format(ab, "func=%s ", args[0].from); | 285 | audit_log_format(ab, "func=%s ", args[0].from); |
285 | if (strcmp(args[0].from, "PATH_CHECK") == 0) | 286 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
286 | entry->func = PATH_CHECK; | 287 | entry->func = FILE_CHECK; |
288 | /* PATH_CHECK is for backwards compat */ | ||
289 | else if (strcmp(args[0].from, "PATH_CHECK") == 0) | ||
290 | entry->func = FILE_CHECK; | ||
287 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | 291 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) |
288 | entry->func = FILE_MMAP; | 292 | entry->func = FILE_MMAP; |
289 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | 293 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) |
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index a0880e9c8e05..46ba62b1adf5 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/rculist.h> | 22 | #include <linux/rculist.h> |
23 | #include <linux/slab.h> | ||
23 | #include "ima.h" | 24 | #include "ima.h" |
24 | 25 | ||
25 | LIST_HEAD(ima_measurements); /* list of all measurements */ | 26 | LIST_HEAD(ima_measurements); /* list of all measurements */ |