diff options
author | James Morris <james.l.morris@oracle.com> | 2014-10-02 05:47:23 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2014-10-02 05:47:23 -0400 |
commit | c867d07e3c861e75509650b8a359351d634db93a (patch) | |
tree | f912043f48b9232db284ff67311eae8692918729 /security | |
parent | 858f61c4298d858376ca7b9fc2e05677faabd2d5 (diff) | |
parent | 1b68bdf9cded82d37e443a20c5ed47bbb084d5dc (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
Diffstat (limited to 'security')
-rw-r--r-- | security/integrity/ima/ima.h | 9 | ||||
-rw-r--r-- | security/integrity/ima/ima_api.c | 5 | ||||
-rw-r--r-- | security/integrity/ima/ima_appraise.c | 6 | ||||
-rw-r--r-- | security/integrity/ima/ima_init.c | 25 | ||||
-rw-r--r-- | security/integrity/ima/ima_main.c | 73 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 23 |
6 files changed, 94 insertions, 47 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 8e4bb883fc13..8ee997dff139 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | |||
43 | #define IMA_TEMPLATE_IMA_NAME "ima" | 43 | #define IMA_TEMPLATE_IMA_NAME "ima" |
44 | #define IMA_TEMPLATE_IMA_FMT "d|n" | 44 | #define IMA_TEMPLATE_IMA_FMT "d|n" |
45 | 45 | ||
46 | /* current content of the policy */ | ||
47 | extern int ima_policy_flag; | ||
48 | |||
46 | /* set during initialization */ | 49 | /* set during initialization */ |
47 | extern int ima_initialized; | 50 | extern int ima_initialized; |
48 | extern int ima_used_chip; | 51 | extern int ima_used_chip; |
@@ -153,14 +156,16 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | |||
153 | int flags); | 156 | int flags); |
154 | void ima_init_policy(void); | 157 | void ima_init_policy(void); |
155 | void ima_update_policy(void); | 158 | void ima_update_policy(void); |
159 | void ima_update_policy_flag(void); | ||
156 | ssize_t ima_parse_add_rule(char *); | 160 | ssize_t ima_parse_add_rule(char *); |
157 | void ima_delete_rules(void); | 161 | void ima_delete_rules(void); |
158 | 162 | ||
159 | /* Appraise integrity measurements */ | 163 | /* Appraise integrity measurements */ |
160 | #define IMA_APPRAISE_ENFORCE 0x01 | 164 | #define IMA_APPRAISE_ENFORCE 0x01 |
161 | #define IMA_APPRAISE_FIX 0x02 | 165 | #define IMA_APPRAISE_FIX 0x02 |
162 | #define IMA_APPRAISE_MODULES 0x04 | 166 | #define IMA_APPRAISE_LOG 0x04 |
163 | #define IMA_APPRAISE_FIRMWARE 0x08 | 167 | #define IMA_APPRAISE_MODULES 0x08 |
168 | #define IMA_APPRAISE_FIRMWARE 0x10 | ||
164 | 169 | ||
165 | #ifdef CONFIG_IMA_APPRAISE | 170 | #ifdef CONFIG_IMA_APPRAISE |
166 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 171 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 65c41a968cc1..86885979918c 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function) | |||
179 | return ima_match_policy(inode, function, mask, flags); | 179 | return ima_match_policy(inode, function, mask, flags); |
180 | } | 180 | } |
181 | 181 | ||
182 | int ima_must_measure(struct inode *inode, int mask, int function) | ||
183 | { | ||
184 | return ima_match_policy(inode, function, mask, IMA_MEASURE); | ||
185 | } | ||
186 | |||
187 | /* | 182 | /* |
188 | * ima_collect_measurement - collect file measurement | 183 | * ima_collect_measurement - collect file measurement |
189 | * | 184 | * |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 013ec3f0e42d..922685483bd3 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str) | |||
23 | { | 23 | { |
24 | if (strncmp(str, "off", 3) == 0) | 24 | if (strncmp(str, "off", 3) == 0) |
25 | ima_appraise = 0; | 25 | ima_appraise = 0; |
26 | else if (strncmp(str, "log", 3) == 0) | ||
27 | ima_appraise = IMA_APPRAISE_LOG; | ||
26 | else if (strncmp(str, "fix", 3) == 0) | 28 | else if (strncmp(str, "fix", 3) == 0) |
27 | ima_appraise = IMA_APPRAISE_FIX; | 29 | ima_appraise = IMA_APPRAISE_FIX; |
28 | return 1; | 30 | return 1; |
@@ -316,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry) | |||
316 | struct integrity_iint_cache *iint; | 318 | struct integrity_iint_cache *iint; |
317 | int must_appraise, rc; | 319 | int must_appraise, rc; |
318 | 320 | ||
319 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) | 321 | if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) |
320 | || !inode->i_op->removexattr) | 322 | || !inode->i_op->removexattr) |
321 | return; | 323 | return; |
322 | 324 | ||
@@ -354,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) | |||
354 | { | 356 | { |
355 | struct integrity_iint_cache *iint; | 357 | struct integrity_iint_cache *iint; |
356 | 358 | ||
357 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)) | 359 | if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)) |
358 | return; | 360 | return; |
359 | 361 | ||
360 | iint = integrity_iint_find(inode); | 362 | iint = integrity_iint_find(inode); |
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index e8f9d70a465d..9164fc8cac84 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
@@ -43,7 +43,7 @@ int ima_used_chip; | |||
43 | * a different value.) Violations add a zero entry to the measurement | 43 | * a different value.) Violations add a zero entry to the measurement |
44 | * list and extend the aggregate PCR value with ff...ff's. | 44 | * list and extend the aggregate PCR value with ff...ff's. |
45 | */ | 45 | */ |
46 | static void __init ima_add_boot_aggregate(void) | 46 | static int __init ima_add_boot_aggregate(void) |
47 | { | 47 | { |
48 | static const char op[] = "add_boot_aggregate"; | 48 | static const char op[] = "add_boot_aggregate"; |
49 | const char *audit_cause = "ENOMEM"; | 49 | const char *audit_cause = "ENOMEM"; |
@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void) | |||
72 | 72 | ||
73 | result = ima_alloc_init_template(iint, NULL, boot_aggregate_name, | 73 | result = ima_alloc_init_template(iint, NULL, boot_aggregate_name, |
74 | NULL, 0, &entry); | 74 | NULL, 0, &entry); |
75 | if (result < 0) | 75 | if (result < 0) { |
76 | return; | 76 | audit_cause = "alloc_entry"; |
77 | goto err_out; | ||
78 | } | ||
77 | 79 | ||
78 | result = ima_store_template(entry, violation, NULL, | 80 | result = ima_store_template(entry, violation, NULL, |
79 | boot_aggregate_name); | 81 | boot_aggregate_name); |
80 | if (result < 0) | 82 | if (result < 0) { |
81 | ima_free_template_entry(entry); | 83 | ima_free_template_entry(entry); |
82 | return; | 84 | audit_cause = "store_entry"; |
85 | goto err_out; | ||
86 | } | ||
87 | return 0; | ||
83 | err_out: | 88 | err_out: |
84 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, | 89 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, |
85 | audit_cause, result, 0); | 90 | audit_cause, result, 0); |
91 | return result; | ||
86 | } | 92 | } |
87 | 93 | ||
88 | int __init ima_init(void) | 94 | int __init ima_init(void) |
@@ -98,6 +104,10 @@ int __init ima_init(void) | |||
98 | if (!ima_used_chip) | 104 | if (!ima_used_chip) |
99 | pr_info("No TPM chip found, activating TPM-bypass!\n"); | 105 | pr_info("No TPM chip found, activating TPM-bypass!\n"); |
100 | 106 | ||
107 | rc = ima_init_keyring(INTEGRITY_KEYRING_IMA); | ||
108 | if (rc) | ||
109 | return rc; | ||
110 | |||
101 | rc = ima_init_crypto(); | 111 | rc = ima_init_crypto(); |
102 | if (rc) | 112 | if (rc) |
103 | return rc; | 113 | return rc; |
@@ -105,7 +115,10 @@ int __init ima_init(void) | |||
105 | if (rc != 0) | 115 | if (rc != 0) |
106 | return rc; | 116 | return rc; |
107 | 117 | ||
108 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | 118 | rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */ |
119 | if (rc != 0) | ||
120 | return rc; | ||
121 | |||
109 | ima_init_policy(); | 122 | ima_init_policy(); |
110 | 123 | ||
111 | return ima_fs_init(); | 124 | return ima_fs_init(); |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 673a37e92ba3..62f59eca32d3 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup); | |||
77 | * could result in a file measurement error. | 77 | * could result in a file measurement error. |
78 | * | 78 | * |
79 | */ | 79 | */ |
80 | static void ima_rdwr_violation_check(struct file *file) | 80 | static void ima_rdwr_violation_check(struct file *file, |
81 | struct integrity_iint_cache *iint, | ||
82 | int must_measure, | ||
83 | char **pathbuf, | ||
84 | const char **pathname) | ||
81 | { | 85 | { |
82 | struct inode *inode = file_inode(file); | 86 | struct inode *inode = file_inode(file); |
83 | fmode_t mode = file->f_mode; | 87 | fmode_t mode = file->f_mode; |
84 | bool send_tomtou = false, send_writers = false; | 88 | bool send_tomtou = false, send_writers = false; |
85 | char *pathbuf = NULL; | ||
86 | const char *pathname; | ||
87 | |||
88 | if (!S_ISREG(inode->i_mode) || !ima_initialized) | ||
89 | return; | ||
90 | 89 | ||
91 | if (mode & FMODE_WRITE) { | 90 | if (mode & FMODE_WRITE) { |
92 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { | 91 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
93 | struct integrity_iint_cache *iint; | 92 | if (!iint) |
94 | iint = integrity_iint_find(inode); | 93 | iint = integrity_iint_find(inode); |
95 | /* IMA_MEASURE is set from reader side */ | 94 | /* IMA_MEASURE is set from reader side */ |
96 | if (iint && (iint->flags & IMA_MEASURE)) | 95 | if (iint && (iint->flags & IMA_MEASURE)) |
97 | send_tomtou = true; | 96 | send_tomtou = true; |
98 | } | 97 | } |
99 | } else { | 98 | } else { |
100 | if ((atomic_read(&inode->i_writecount) > 0) && | 99 | if ((atomic_read(&inode->i_writecount) > 0) && must_measure) |
101 | ima_must_measure(inode, MAY_READ, FILE_CHECK)) | ||
102 | send_writers = true; | 100 | send_writers = true; |
103 | } | 101 | } |
104 | 102 | ||
105 | if (!send_tomtou && !send_writers) | 103 | if (!send_tomtou && !send_writers) |
106 | return; | 104 | return; |
107 | 105 | ||
108 | pathname = ima_d_path(&file->f_path, &pathbuf); | 106 | *pathname = ima_d_path(&file->f_path, pathbuf); |
109 | 107 | ||
110 | if (send_tomtou) | 108 | if (send_tomtou) |
111 | ima_add_violation(file, pathname, "invalid_pcr", "ToMToU"); | 109 | ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU"); |
112 | if (send_writers) | 110 | if (send_writers) |
113 | ima_add_violation(file, pathname, | 111 | ima_add_violation(file, *pathname, |
114 | "invalid_pcr", "open_writers"); | 112 | "invalid_pcr", "open_writers"); |
115 | kfree(pathbuf); | ||
116 | } | 113 | } |
117 | 114 | ||
118 | static void ima_check_last_writer(struct integrity_iint_cache *iint, | 115 | static void ima_check_last_writer(struct integrity_iint_cache *iint, |
@@ -160,15 +157,16 @@ static int process_measurement(struct file *file, int mask, int function, | |||
160 | int opened) | 157 | int opened) |
161 | { | 158 | { |
162 | struct inode *inode = file_inode(file); | 159 | struct inode *inode = file_inode(file); |
163 | struct integrity_iint_cache *iint; | 160 | struct integrity_iint_cache *iint = NULL; |
164 | struct ima_template_desc *template_desc; | 161 | struct ima_template_desc *template_desc; |
165 | char *pathbuf = NULL; | 162 | char *pathbuf = NULL; |
166 | const char *pathname = NULL; | 163 | const char *pathname = NULL; |
167 | int rc = -ENOMEM, action, must_appraise; | 164 | int rc = -ENOMEM, action, must_appraise; |
168 | struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; | 165 | struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL; |
169 | int xattr_len = 0; | 166 | int xattr_len = 0; |
167 | bool violation_check; | ||
170 | 168 | ||
171 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | 169 | if (!ima_policy_flag || !S_ISREG(inode->i_mode)) |
172 | return 0; | 170 | return 0; |
173 | 171 | ||
174 | /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action | 172 | /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action |
@@ -176,7 +174,9 @@ static int process_measurement(struct file *file, int mask, int function, | |||
176 | * Included is the appraise submask. | 174 | * Included is the appraise submask. |
177 | */ | 175 | */ |
178 | action = ima_get_action(inode, mask, function); | 176 | action = ima_get_action(inode, mask, function); |
179 | if (!action) | 177 | violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) && |
178 | (ima_policy_flag & IMA_MEASURE)); | ||
179 | if (!action && !violation_check) | ||
180 | return 0; | 180 | return 0; |
181 | 181 | ||
182 | must_appraise = action & IMA_APPRAISE; | 182 | must_appraise = action & IMA_APPRAISE; |
@@ -187,9 +187,20 @@ static int process_measurement(struct file *file, int mask, int function, | |||
187 | 187 | ||
188 | mutex_lock(&inode->i_mutex); | 188 | mutex_lock(&inode->i_mutex); |
189 | 189 | ||
190 | iint = integrity_inode_get(inode); | 190 | if (action) { |
191 | if (!iint) | 191 | iint = integrity_inode_get(inode); |
192 | goto out; | 192 | if (!iint) |
193 | goto out; | ||
194 | } | ||
195 | |||
196 | if (violation_check) { | ||
197 | ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, | ||
198 | &pathbuf, &pathname); | ||
199 | if (!action) { | ||
200 | rc = 0; | ||
201 | goto out_free; | ||
202 | } | ||
203 | } | ||
193 | 204 | ||
194 | /* Determine if already appraised/measured based on bitmask | 205 | /* Determine if already appraised/measured based on bitmask |
195 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, | 206 | * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, |
@@ -218,7 +229,8 @@ static int process_measurement(struct file *file, int mask, int function, | |||
218 | goto out_digsig; | 229 | goto out_digsig; |
219 | } | 230 | } |
220 | 231 | ||
221 | pathname = ima_d_path(&file->f_path, &pathbuf); | 232 | if (!pathname) /* ima_rdwr_violation possibly pre-fetched */ |
233 | pathname = ima_d_path(&file->f_path, &pathbuf); | ||
222 | 234 | ||
223 | if (action & IMA_MEASURE) | 235 | if (action & IMA_MEASURE) |
224 | ima_store_measurement(iint, file, pathname, | 236 | ima_store_measurement(iint, file, pathname, |
@@ -228,13 +240,15 @@ static int process_measurement(struct file *file, int mask, int function, | |||
228 | xattr_value, xattr_len, opened); | 240 | xattr_value, xattr_len, opened); |
229 | if (action & IMA_AUDIT) | 241 | if (action & IMA_AUDIT) |
230 | ima_audit_measurement(iint, pathname); | 242 | ima_audit_measurement(iint, pathname); |
231 | kfree(pathbuf); | 243 | |
232 | out_digsig: | 244 | out_digsig: |
233 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) | 245 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) |
234 | rc = -EACCES; | 246 | rc = -EACCES; |
247 | kfree(xattr_value); | ||
248 | out_free: | ||
249 | kfree(pathbuf); | ||
235 | out: | 250 | out: |
236 | mutex_unlock(&inode->i_mutex); | 251 | mutex_unlock(&inode->i_mutex); |
237 | kfree(xattr_value); | ||
238 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) | 252 | if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) |
239 | return -EACCES; | 253 | return -EACCES; |
240 | return 0; | 254 | return 0; |
@@ -288,7 +302,6 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
288 | */ | 302 | */ |
289 | int ima_file_check(struct file *file, int mask, int opened) | 303 | int ima_file_check(struct file *file, int mask, int opened) |
290 | { | 304 | { |
291 | ima_rdwr_violation_check(file); | ||
292 | return process_measurement(file, | 305 | return process_measurement(file, |
293 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), | 306 | mask & (MAY_READ | MAY_WRITE | MAY_EXEC), |
294 | FILE_CHECK, opened); | 307 | FILE_CHECK, opened); |
@@ -334,14 +347,10 @@ static int __init init_ima(void) | |||
334 | 347 | ||
335 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | 348 | hash_setup(CONFIG_IMA_DEFAULT_HASH); |
336 | error = ima_init(); | 349 | error = ima_init(); |
337 | if (error) | 350 | if (!error) { |
338 | goto out; | 351 | ima_initialized = 1; |
339 | 352 | ima_update_policy_flag(); | |
340 | error = ima_init_keyring(INTEGRITY_KEYRING_IMA); | 353 | } |
341 | if (error) | ||
342 | goto out; | ||
343 | ima_initialized = 1; | ||
344 | out: | ||
345 | return error; | 354 | return error; |
346 | } | 355 | } |
347 | 356 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 07099a8bc283..cdc620b2152f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #define DONT_APPRAISE 0x0008 | 35 | #define DONT_APPRAISE 0x0008 |
36 | #define AUDIT 0x0040 | 36 | #define AUDIT 0x0040 |
37 | 37 | ||
38 | int ima_policy_flag; | ||
39 | |||
38 | #define MAX_LSM_RULES 6 | 40 | #define MAX_LSM_RULES 6 |
39 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | 41 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, |
40 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | 42 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE |
@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | |||
295 | return action; | 297 | return action; |
296 | } | 298 | } |
297 | 299 | ||
300 | /* | ||
301 | * Initialize the ima_policy_flag variable based on the currently | ||
302 | * loaded policy. Based on this flag, the decision to short circuit | ||
303 | * out of a function or not call the function in the first place | ||
304 | * can be made earlier. | ||
305 | */ | ||
306 | void ima_update_policy_flag(void) | ||
307 | { | ||
308 | struct ima_rule_entry *entry; | ||
309 | |||
310 | ima_policy_flag = 0; | ||
311 | list_for_each_entry(entry, ima_rules, list) { | ||
312 | if (entry->action & IMA_DO_MASK) | ||
313 | ima_policy_flag |= entry->action; | ||
314 | } | ||
315 | |||
316 | if (!ima_appraise) | ||
317 | ima_policy_flag &= ~IMA_APPRAISE; | ||
318 | } | ||
319 | |||
298 | /** | 320 | /** |
299 | * ima_init_policy - initialize the default measure rules. | 321 | * ima_init_policy - initialize the default measure rules. |
300 | * | 322 | * |
@@ -341,6 +363,7 @@ void ima_update_policy(void) | |||
341 | 363 | ||
342 | if (ima_rules == &ima_default_rules) { | 364 | if (ima_rules == &ima_default_rules) { |
343 | ima_rules = &ima_policy_rules; | 365 | ima_rules = &ima_policy_rules; |
366 | ima_update_policy_flag(); | ||
344 | cause = "complete"; | 367 | cause = "complete"; |
345 | result = 0; | 368 | result = 0; |
346 | } | 369 | } |