diff options
author | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2012-12-03 17:08:11 -0500 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2013-01-22 16:10:36 -0500 |
commit | d79d72e02485c00b886179538dc8deaffa3be507 (patch) | |
tree | 92690d5cbd6e4a0a3bee369033fe18d9b2d065f7 /security | |
parent | f578c08ec959cb0cdadf02bdc9689a4df3e9b9d4 (diff) |
ima: per hook cache integrity appraisal status
With the new IMA policy 'appraise_type=' option, different hooks
can require different methods for appraising a file's integrity.
For example, the existing 'ima_appraise_tcb' policy defines a
generic rule, requiring all root files to be appraised, without
specfying the appraisal method. A more specific rule could require
all kernel modules, for example, to be signed.
appraise fowner=0 func=MODULE_CHECK appraise_type=imasig
appraise fowner=0
As a result, the integrity appraisal results for the same inode, but
for different hooks, could differ. This patch caches the integrity
appraisal results on a per hook basis.
Changelog v2:
- Rename ima_cache_status() to ima_set_cache_status()
- Rename and move get_appraise_status() to ima_get_cache_status()
Changelog v0:
- include IMA_APPRAISE/APPRAISED_SUBMASK in IMA_DO/DONE_MASK (Dmitry)
- Support independent MODULE_CHECK appraise status.
- fixed IMA_XXXX_APPRAISE/APPRAISED flags
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/iint.c | 10 | ||||
-rw-r--r-- | security/integrity/ima/ima.h | 13 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 71 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 19 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 22 | ||||
-rw-r--r-- | security/integrity/integrity.h | 26 |
6 files changed, 136 insertions, 25 deletions
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index d82a5a13d855..74522dbd10a6 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -72,7 +72,10 @@ static void iint_free(struct integrity_iint_cache *iint) | |||
72 | { | 72 | { |
73 | iint->version = 0; | 73 | iint->version = 0; |
74 | iint->flags = 0UL; | 74 | iint->flags = 0UL; |
75 | iint->ima_status = INTEGRITY_UNKNOWN; | 75 | iint->ima_file_status = INTEGRITY_UNKNOWN; |
76 | iint->ima_mmap_status = INTEGRITY_UNKNOWN; | ||
77 | iint->ima_bprm_status = INTEGRITY_UNKNOWN; | ||
78 | iint->ima_module_status = INTEGRITY_UNKNOWN; | ||
76 | iint->evm_status = INTEGRITY_UNKNOWN; | 79 | iint->evm_status = INTEGRITY_UNKNOWN; |
77 | kmem_cache_free(iint_cache, iint); | 80 | kmem_cache_free(iint_cache, iint); |
78 | } | 81 | } |
@@ -149,7 +152,10 @@ static void init_once(void *foo) | |||
149 | memset(iint, 0, sizeof *iint); | 152 | memset(iint, 0, sizeof *iint); |
150 | iint->version = 0; | 153 | iint->version = 0; |
151 | iint->flags = 0UL; | 154 | iint->flags = 0UL; |
152 | iint->ima_status = INTEGRITY_UNKNOWN; | 155 | iint->ima_file_status = INTEGRITY_UNKNOWN; |
156 | iint->ima_mmap_status = INTEGRITY_UNKNOWN; | ||
157 | iint->ima_bprm_status = INTEGRITY_UNKNOWN; | ||
158 | iint->ima_module_status = INTEGRITY_UNKNOWN; | ||
153 | iint->evm_status = INTEGRITY_UNKNOWN; | 159 | iint->evm_status = INTEGRITY_UNKNOWN; |
154 | } | 160 | } |
155 | 161 | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 991844db98d9..ab68bed8ac36 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -142,13 +142,16 @@ void ima_delete_rules(void); | |||
142 | #define IMA_APPRAISE_FIX 0x02 | 142 | #define IMA_APPRAISE_FIX 0x02 |
143 | 143 | ||
144 | #ifdef CONFIG_IMA_APPRAISE | 144 | #ifdef CONFIG_IMA_APPRAISE |
145 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | 145 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
146 | struct file *file, const unsigned char *filename); | 146 | struct file *file, const unsigned char *filename); |
147 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); | 147 | int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); |
148 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); | 148 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); |
149 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | ||
150 | int func); | ||
149 | 151 | ||
150 | #else | 152 | #else |
151 | static inline int ima_appraise_measurement(struct integrity_iint_cache *iint, | 153 | static inline int ima_appraise_measurement(int func, |
154 | struct integrity_iint_cache *iint, | ||
152 | struct file *file, | 155 | struct file *file, |
153 | const unsigned char *filename) | 156 | const unsigned char *filename) |
154 | { | 157 | { |
@@ -165,6 +168,12 @@ static inline void ima_update_xattr(struct integrity_iint_cache *iint, | |||
165 | struct file *file) | 168 | struct file *file) |
166 | { | 169 | { |
167 | } | 170 | } |
171 | |||
172 | static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache | ||
173 | *iint, int func) | ||
174 | { | ||
175 | return INTEGRITY_UNKNOWN; | ||
176 | } | ||
168 | #endif | 177 | #endif |
169 | 178 | ||
170 | /* LSM based policy rules require audit */ | 179 | /* LSM based policy rules require audit */ |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 8004332ccb8f..2d4becab8918 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -51,6 +51,62 @@ static int ima_fix_xattr(struct dentry *dentry, | |||
51 | sizeof(iint->ima_xattr), 0); | 51 | sizeof(iint->ima_xattr), 0); |
52 | } | 52 | } |
53 | 53 | ||
54 | /* Return specific func appraised cached result */ | ||
55 | enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | ||
56 | int func) | ||
57 | { | ||
58 | switch(func) { | ||
59 | case MMAP_CHECK: | ||
60 | return iint->ima_mmap_status; | ||
61 | case BPRM_CHECK: | ||
62 | return iint->ima_bprm_status; | ||
63 | case MODULE_CHECK: | ||
64 | return iint->ima_module_status; | ||
65 | case FILE_CHECK: | ||
66 | default: | ||
67 | return iint->ima_file_status; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static void ima_set_cache_status(struct integrity_iint_cache *iint, | ||
72 | int func, enum integrity_status status) | ||
73 | { | ||
74 | switch(func) { | ||
75 | case MMAP_CHECK: | ||
76 | iint->ima_mmap_status = status; | ||
77 | break; | ||
78 | case BPRM_CHECK: | ||
79 | iint->ima_bprm_status = status; | ||
80 | break; | ||
81 | case MODULE_CHECK: | ||
82 | iint->ima_module_status = status; | ||
83 | break; | ||
84 | case FILE_CHECK: | ||
85 | default: | ||
86 | iint->ima_file_status = status; | ||
87 | break; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | ||
92 | { | ||
93 | switch(func) { | ||
94 | case MMAP_CHECK: | ||
95 | iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED); | ||
96 | break; | ||
97 | case BPRM_CHECK: | ||
98 | iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED); | ||
99 | break; | ||
100 | case MODULE_CHECK: | ||
101 | iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); | ||
102 | break; | ||
103 | case FILE_CHECK: | ||
104 | default: | ||
105 | iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
54 | /* | 110 | /* |
55 | * ima_appraise_measurement - appraise file measurement | 111 | * ima_appraise_measurement - appraise file measurement |
56 | * | 112 | * |
@@ -59,7 +115,7 @@ static int ima_fix_xattr(struct dentry *dentry, | |||
59 | * | 115 | * |
60 | * Return 0 on success, error code otherwise | 116 | * Return 0 on success, error code otherwise |
61 | */ | 117 | */ |
62 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | 118 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
63 | struct file *file, const unsigned char *filename) | 119 | struct file *file, const unsigned char *filename) |
64 | { | 120 | { |
65 | struct dentry *dentry = file->f_dentry; | 121 | struct dentry *dentry = file->f_dentry; |
@@ -75,9 +131,6 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint, | |||
75 | if (!inode->i_op->getxattr) | 131 | if (!inode->i_op->getxattr) |
76 | return INTEGRITY_UNKNOWN; | 132 | return INTEGRITY_UNKNOWN; |
77 | 133 | ||
78 | if (iint->flags & IMA_APPRAISED) | ||
79 | return iint->ima_status; | ||
80 | |||
81 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, | 134 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, |
82 | 0, GFP_NOFS); | 135 | 0, GFP_NOFS); |
83 | if (rc <= 0) { | 136 | if (rc <= 0) { |
@@ -99,7 +152,6 @@ int ima_appraise_measurement(struct integrity_iint_cache *iint, | |||
99 | cause = "invalid-HMAC"; | 152 | cause = "invalid-HMAC"; |
100 | goto out; | 153 | goto out; |
101 | } | 154 | } |
102 | |||
103 | switch (xattr_value->type) { | 155 | switch (xattr_value->type) { |
104 | case IMA_XATTR_DIGEST: | 156 | case IMA_XATTR_DIGEST: |
105 | if (iint->flags & IMA_DIGSIG_REQUIRED) { | 157 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
@@ -148,9 +200,9 @@ out: | |||
148 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | 200 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, |
149 | op, cause, rc, 0); | 201 | op, cause, rc, 0); |
150 | } else { | 202 | } else { |
151 | iint->flags |= IMA_APPRAISED; | 203 | ima_cache_flags(iint, func); |
152 | } | 204 | } |
153 | iint->ima_status = status; | 205 | ima_set_cache_status(iint, func, status); |
154 | kfree(xattr_value); | 206 | kfree(xattr_value); |
155 | return status; | 207 | return status; |
156 | } | 208 | } |
@@ -196,10 +248,11 @@ void ima_inode_post_setattr(struct dentry *dentry) | |||
196 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | 248 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); |
197 | iint = integrity_iint_find(inode); | 249 | iint = integrity_iint_find(inode); |
198 | if (iint) { | 250 | if (iint) { |
251 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | | ||
252 | IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | | ||
253 | IMA_ACTION_FLAGS); | ||
199 | if (must_appraise) | 254 | if (must_appraise) |
200 | iint->flags |= IMA_APPRAISE; | 255 | iint->flags |= IMA_APPRAISE; |
201 | else | ||
202 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); | ||
203 | } | 256 | } |
204 | if (!must_appraise) | 257 | if (!must_appraise) |
205 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); | 258 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 3cdd78768c29..66b7f408eff2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -151,8 +151,10 @@ static int process_measurement(struct file *file, const char *filename, | |||
151 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 151 | if (!ima_initialized || !S_ISREG(inode->i_mode)) |
152 | return 0; | 152 | return 0; |
153 | 153 | ||
154 | /* Determine if in appraise/audit/measurement policy, | 154 | /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action |
155 | * returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */ | 155 | * bitmask based on the appraise/audit/measurement policy. |
156 | * Included is the appraise submask. | ||
157 | */ | ||
156 | action = ima_get_action(inode, mask, function); | 158 | action = ima_get_action(inode, mask, function); |
157 | if (!action) | 159 | if (!action) |
158 | return 0; | 160 | return 0; |
@@ -166,16 +168,17 @@ static int process_measurement(struct file *file, const char *filename, | |||
166 | goto out; | 168 | goto out; |
167 | 169 | ||
168 | /* Determine if already appraised/measured based on bitmask | 170 | /* Determine if already appraised/measured based on bitmask |
169 | * (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED, | 171 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, |
170 | * IMA_AUDIT, IMA_AUDITED) */ | 172 | * IMA_AUDIT, IMA_AUDITED) |
173 | */ | ||
171 | iint->flags |= action; | 174 | iint->flags |= action; |
172 | action &= IMA_DO_MASK; | 175 | action &= IMA_DO_MASK; |
173 | action &= ~((iint->flags & IMA_DONE_MASK) >> 1); | 176 | action &= ~((iint->flags & IMA_DONE_MASK) >> 1); |
174 | 177 | ||
175 | /* Nothing to do, just return existing appraised status */ | 178 | /* Nothing to do, just return existing appraised status */ |
176 | if (!action) { | 179 | if (!action) { |
177 | if (iint->flags & IMA_APPRAISED) | 180 | if (must_appraise) |
178 | rc = iint->ima_status; | 181 | rc = ima_get_cache_status(iint, function); |
179 | goto out_digsig; | 182 | goto out_digsig; |
180 | } | 183 | } |
181 | 184 | ||
@@ -191,8 +194,8 @@ static int process_measurement(struct file *file, const char *filename, | |||
191 | 194 | ||
192 | if (action & IMA_MEASURE) | 195 | if (action & IMA_MEASURE) |
193 | ima_store_measurement(iint, file, pathname); | 196 | ima_store_measurement(iint, file, pathname); |
194 | if (action & IMA_APPRAISE) | 197 | if (action & IMA_APPRAISE_SUBMASK) |
195 | rc = ima_appraise_measurement(iint, file, pathname); | 198 | rc = ima_appraise_measurement(function, iint, file, pathname); |
196 | if (action & IMA_AUDIT) | 199 | if (action & IMA_AUDIT) |
197 | ima_audit_measurement(iint, pathname); | 200 | ima_audit_measurement(iint, pathname); |
198 | kfree(pathbuf); | 201 | kfree(pathbuf); |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 1a2543a8ee53..4d7c0ae656d3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -218,6 +218,25 @@ retry: | |||
218 | return true; | 218 | return true; |
219 | } | 219 | } |
220 | 220 | ||
221 | /* | ||
222 | * In addition to knowing that we need to appraise the file in general, | ||
223 | * we need to differentiate between calling hooks. | ||
224 | */ | ||
225 | static int get_subaction(int func) | ||
226 | { | ||
227 | switch(func) { | ||
228 | case MMAP_CHECK: | ||
229 | return IMA_MMAP_APPRAISE; | ||
230 | case BPRM_CHECK: | ||
231 | return IMA_BPRM_APPRAISE; | ||
232 | case MODULE_CHECK: | ||
233 | return IMA_MODULE_APPRAISE; | ||
234 | case FILE_CHECK: | ||
235 | default: | ||
236 | return IMA_FILE_APPRAISE; | ||
237 | } | ||
238 | } | ||
239 | |||
221 | /** | 240 | /** |
222 | * ima_match_policy - decision based on LSM and other conditions | 241 | * ima_match_policy - decision based on LSM and other conditions |
223 | * @inode: pointer to an inode for which the policy decision is being made | 242 | * @inode: pointer to an inode for which the policy decision is being made |
@@ -248,6 +267,9 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | |||
248 | action |= entry->flags & IMA_ACTION_FLAGS; | 267 | action |= entry->flags & IMA_ACTION_FLAGS; |
249 | 268 | ||
250 | action |= entry->action & IMA_DO_MASK; | 269 | action |= entry->action & IMA_DO_MASK; |
270 | if (entry->action & IMA_APPRAISE) | ||
271 | action |= get_subaction(func); | ||
272 | |||
251 | if (entry->action & IMA_DO_MASK) | 273 | if (entry->action & IMA_DO_MASK) |
252 | actmask &= ~(entry->action | entry->action << 1); | 274 | actmask &= ~(entry->action | entry->action << 1); |
253 | else | 275 | else |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 329ad263e130..0ae08fc88585 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -30,9 +30,24 @@ | |||
30 | #define IMA_DIGSIG 0x01000000 | 30 | #define IMA_DIGSIG 0x01000000 |
31 | #define IMA_DIGSIG_REQUIRED 0x02000000 | 31 | #define IMA_DIGSIG_REQUIRED 0x02000000 |
32 | 32 | ||
33 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT) | 33 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ |
34 | #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \ | 34 | IMA_APPRAISE_SUBMASK) |
35 | | IMA_COLLECTED) | 35 | #define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ |
36 | IMA_COLLECTED | IMA_APPRAISED_SUBMASK) | ||
37 | |||
38 | /* iint subaction appraise cache flags */ | ||
39 | #define IMA_FILE_APPRAISE 0x00000100 | ||
40 | #define IMA_FILE_APPRAISED 0x00000200 | ||
41 | #define IMA_MMAP_APPRAISE 0x00000400 | ||
42 | #define IMA_MMAP_APPRAISED 0x00000800 | ||
43 | #define IMA_BPRM_APPRAISE 0x00001000 | ||
44 | #define IMA_BPRM_APPRAISED 0x00002000 | ||
45 | #define IMA_MODULE_APPRAISE 0x00004000 | ||
46 | #define IMA_MODULE_APPRAISED 0x00008000 | ||
47 | #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ | ||
48 | IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE) | ||
49 | #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ | ||
50 | IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED) | ||
36 | 51 | ||
37 | enum evm_ima_xattr_type { | 52 | enum evm_ima_xattr_type { |
38 | IMA_XATTR_DIGEST = 0x01, | 53 | IMA_XATTR_DIGEST = 0x01, |
@@ -52,7 +67,10 @@ struct integrity_iint_cache { | |||
52 | u64 version; /* track inode changes */ | 67 | u64 version; /* track inode changes */ |
53 | unsigned long flags; | 68 | unsigned long flags; |
54 | struct evm_ima_xattr_data ima_xattr; | 69 | struct evm_ima_xattr_data ima_xattr; |
55 | enum integrity_status ima_status:4; | 70 | enum integrity_status ima_file_status:4; |
71 | enum integrity_status ima_mmap_status:4; | ||
72 | enum integrity_status ima_bprm_status:4; | ||
73 | enum integrity_status ima_module_status:4; | ||
56 | enum integrity_status evm_status:4; | 74 | enum integrity_status evm_status:4; |
57 | }; | 75 | }; |
58 | 76 | ||