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

ima: Move comprehensive rule validation checks out of the token parser

Use ima_validate_rule(), at the end of the token parsing stage, to
verify combinations of actions, hooks, and flags. This is useful to
increase readability by consolidating such checks into a single function
and also because rule conditionals can be specified in arbitrary order
making it difficult to do comprehensive rule validation until the entire
rule has been parsed.

This allows for the check that ties together the "keyrings" conditional
with the KEY_CHECK function hook to be moved into the final rule
validation.

The modsig check no longer needs to compiled conditionally because the
token parser will ensure that modsig support is enabled before accepting
"imasig|modsig" appraise type values. The final rule validation will
ensure that appraise_type and appraise_flag options are only present in
appraise rules.

Finally, this allows for the check that ties together the "pcr"
conditional with the measure action to be moved into the final rule
validation.

Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>

authored by

Tyler Hicks and committed by
Mimi Zohar
30031b0e aa0c0227

+37 -46
-6
security/integrity/ima/ima.h
··· 372 372 #endif /* CONFIG_IMA_APPRAISE */ 373 373 374 374 #ifdef CONFIG_IMA_APPRAISE_MODSIG 375 - bool ima_hook_supports_modsig(enum ima_hooks func); 376 375 int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len, 377 376 struct modsig **modsig); 378 377 void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size); ··· 381 382 u32 *data_len); 382 383 void ima_free_modsig(struct modsig *modsig); 383 384 #else 384 - static inline bool ima_hook_supports_modsig(enum ima_hooks func) 385 - { 386 - return false; 387 - } 388 - 389 385 static inline int ima_read_modsig(enum ima_hooks func, const void *buf, 390 386 loff_t buf_len, struct modsig **modsig) 391 387 {
-20
security/integrity/ima/ima_modsig.c
··· 32 32 u8 raw_pkcs7[]; 33 33 }; 34 34 35 - /** 36 - * ima_hook_supports_modsig - can the policy allow modsig for this hook? 37 - * 38 - * modsig is only supported by hooks using ima_post_read_file(), because only 39 - * they preload the contents of the file in a buffer. FILE_CHECK does that in 40 - * some cases, but not when reached from vfs_open(). POLICY_CHECK can support 41 - * it, but it's not useful in practice because it's a text file so deny. 42 - */ 43 - bool ima_hook_supports_modsig(enum ima_hooks func) 44 - { 45 - switch (func) { 46 - case KEXEC_KERNEL_CHECK: 47 - case KEXEC_INITRAMFS_CHECK: 48 - case MODULE_CHECK: 49 - return true; 50 - default: 51 - return false; 52 - } 53 - } 54 - 55 35 /* 56 36 * ima_read_modsig - Read modsig from buf. 57 37 *
+37 -20
security/integrity/ima/ima_policy.c
··· 984 984 985 985 static bool ima_validate_rule(struct ima_rule_entry *entry) 986 986 { 987 - /* Ensure that the action is set */ 987 + /* Ensure that the action is set and is compatible with the flags */ 988 988 if (entry->action == UNKNOWN) 989 + return false; 990 + 991 + if (entry->action != MEASURE && entry->flags & IMA_PCR) 992 + return false; 993 + 994 + if (entry->action != APPRAISE && 995 + entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST)) 996 + return false; 997 + 998 + /* 999 + * The IMA_FUNC bit must be set if and only if there's a valid hook 1000 + * function specified, and vice versa. Enforcing this property allows 1001 + * for the NONE case below to validate a rule without an explicit hook 1002 + * function. 1003 + */ 1004 + if (((entry->flags & IMA_FUNC) && entry->func == NONE) || 1005 + (!(entry->flags & IMA_FUNC) && entry->func != NONE)) 989 1006 return false; 990 1007 991 1008 /* ··· 1016 999 case BPRM_CHECK: 1017 1000 case CREDS_CHECK: 1018 1001 case POST_SETATTR: 1019 - case MODULE_CHECK: 1020 1002 case FIRMWARE_CHECK: 1003 + case POLICY_CHECK: 1004 + if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 1005 + IMA_UID | IMA_FOWNER | IMA_FSUUID | 1006 + IMA_INMASK | IMA_EUID | IMA_PCR | 1007 + IMA_FSNAME | IMA_DIGSIG_REQUIRED | 1008 + IMA_PERMIT_DIRECTIO)) 1009 + return false; 1010 + 1011 + break; 1012 + case MODULE_CHECK: 1021 1013 case KEXEC_KERNEL_CHECK: 1022 1014 case KEXEC_INITRAMFS_CHECK: 1023 - case POLICY_CHECK: 1024 - /* Validation of these hook functions is in ima_parse_rule() */ 1015 + if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | 1016 + IMA_UID | IMA_FOWNER | IMA_FSUUID | 1017 + IMA_INMASK | IMA_EUID | IMA_PCR | 1018 + IMA_FSNAME | IMA_DIGSIG_REQUIRED | 1019 + IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | 1020 + IMA_CHECK_BLACKLIST)) 1021 + return false; 1022 + 1025 1023 break; 1026 1024 case KEXEC_CMDLINE: 1027 1025 if (entry->action & ~(MEASURE | DONT_MEASURE)) ··· 1250 1218 keyrings_len = strlen(args[0].from) + 1; 1251 1219 1252 1220 if ((entry->keyrings) || 1253 - (entry->func != KEY_CHECK) || 1254 1221 (keyrings_len < 2)) { 1255 1222 result = -EINVAL; 1256 1223 break; ··· 1389 1358 AUDIT_SUBJ_TYPE); 1390 1359 break; 1391 1360 case Opt_appraise_type: 1392 - if (entry->action != APPRAISE) { 1393 - result = -EINVAL; 1394 - break; 1395 - } 1396 - 1397 1361 ima_log_string(ab, "appraise_type", args[0].from); 1398 1362 if ((strcmp(args[0].from, "imasig")) == 0) 1399 1363 entry->flags |= IMA_DIGSIG_REQUIRED; 1400 - else if (ima_hook_supports_modsig(entry->func) && 1364 + else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && 1401 1365 strcmp(args[0].from, "imasig|modsig") == 0) 1402 1366 entry->flags |= IMA_DIGSIG_REQUIRED | 1403 1367 IMA_MODSIG_ALLOWED; ··· 1400 1374 result = -EINVAL; 1401 1375 break; 1402 1376 case Opt_appraise_flag: 1403 - if (entry->action != APPRAISE) { 1404 - result = -EINVAL; 1405 - break; 1406 - } 1407 - 1408 1377 ima_log_string(ab, "appraise_flag", args[0].from); 1409 1378 if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) && 1410 1379 strstr(args[0].from, "blacklist")) ··· 1411 1390 entry->flags |= IMA_PERMIT_DIRECTIO; 1412 1391 break; 1413 1392 case Opt_pcr: 1414 - if (entry->action != MEASURE) { 1415 - result = -EINVAL; 1416 - break; 1417 - } 1418 1393 ima_log_string(ab, "pcr", args[0].from); 1419 1394 1420 1395 result = kstrtoint(args[0].from, 10, &entry->pcr);