Skip to content

Commit 583a80a

Browse files
nightmaredmimizohar
authored andcommitted
IMA: add a policy option to restrict xattr hash algorithms on appraisal
The kernel has the ability to restrict the set of hash algorithms it accepts for the security.ima xattr when it appraises files. Define a new IMA policy rule option "appraise_algos=", using the mentioned mechanism to expose a user-toggable policy knob to opt-in to that restriction and select the desired set of algorithms that must be accepted. When a policy rule uses the 'appraise_algos' option, appraisal of a file referenced by that rule will now fail if the digest algorithm employed to hash the file was not one of those explicitly listed in the option. In its absence, any hash algorithm compiled in the kernel will be accepted. For example, on a system where SELinux is properly deployed, the rule appraise func=BPRM_CHECK obj_type=iptables_exec_t \ appraise_algos=sha256,sha384 will block the execution of iptables if the xattr security.ima of its executables were not hashed with either sha256 or sha384. Signed-off-by: THOBY Simon <Simon.THOBY@viveris.fr> Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
1 parent 1624dc0 commit 583a80a

2 files changed

Lines changed: 75 additions & 5 deletions

File tree

Documentation/ABI/testing/ima_policy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Description:
2727
lsm: [[subj_user=] [subj_role=] [subj_type=]
2828
[obj_user=] [obj_role=] [obj_type=]]
2929
option: [[appraise_type=]] [template=] [permit_directio]
30-
[appraise_flag=] [keyrings=]
30+
[appraise_flag=] [appraise_algos=] [keyrings=]
3131
base:
3232
func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
3333
[FIRMWARE_CHECK]
@@ -55,6 +55,10 @@ Description:
5555
label:= [selinux]|[kernel_info]|[data_label]
5656
data_label:= a unique string used for grouping and limiting critical data.
5757
For example, "selinux" to measure critical data for SELinux.
58+
appraise_algos:= comma-separated list of hash algorithms
59+
For example, "sha256,sha512" to only accept to appraise
60+
files where the security.ima xattr was hashed with one
61+
of these two algorithms.
5862

5963
default policy:
6064
# PROC_SUPER_MAGIC

security/integrity/ima/ima_policy.c

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,7 @@ enum {
960960
Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
961961
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
962962
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
963-
Opt_appraise_type, Opt_appraise_flag,
963+
Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
964964
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
965965
Opt_label, Opt_err
966966
};
@@ -995,6 +995,7 @@ static const match_table_t policy_tokens = {
995995
{Opt_fowner_lt, "fowner<%s"},
996996
{Opt_appraise_type, "appraise_type=%s"},
997997
{Opt_appraise_flag, "appraise_flag=%s"},
998+
{Opt_appraise_algos, "appraise_algos=%s"},
998999
{Opt_permit_directio, "permit_directio"},
9991000
{Opt_pcr, "pcr=%s"},
10001001
{Opt_template, "template=%s"},
@@ -1095,7 +1096,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
10951096
return false;
10961097

10971098
if (entry->action != APPRAISE &&
1098-
entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST))
1099+
entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED |
1100+
IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
10991101
return false;
11001102

11011103
/*
@@ -1125,7 +1127,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11251127
IMA_UID | IMA_FOWNER | IMA_FSUUID |
11261128
IMA_INMASK | IMA_EUID | IMA_PCR |
11271129
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
1128-
IMA_PERMIT_DIRECTIO))
1130+
IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
11291131
return false;
11301132

11311133
break;
@@ -1137,7 +1139,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11371139
IMA_INMASK | IMA_EUID | IMA_PCR |
11381140
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
11391141
IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
1140-
IMA_CHECK_BLACKLIST))
1142+
IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
11411143
return false;
11421144

11431145
break;
@@ -1187,6 +1189,28 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11871189
return true;
11881190
}
11891191

1192+
static unsigned int ima_parse_appraise_algos(char *arg)
1193+
{
1194+
unsigned int res = 0;
1195+
int idx;
1196+
char *token;
1197+
1198+
while ((token = strsep(&arg, ",")) != NULL) {
1199+
idx = match_string(hash_algo_name, HASH_ALGO__LAST, token);
1200+
1201+
if (idx < 0) {
1202+
pr_err("unknown hash algorithm \"%s\"",
1203+
token);
1204+
return 0;
1205+
}
1206+
1207+
/* Add the hash algorithm to the 'allowed' bitfield */
1208+
res |= (1U << idx);
1209+
}
1210+
1211+
return res;
1212+
}
1213+
11901214
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
11911215
{
11921216
struct audit_buffer *ab;
@@ -1522,6 +1546,25 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
15221546
else
15231547
result = -EINVAL;
15241548
break;
1549+
case Opt_appraise_algos:
1550+
ima_log_string(ab, "appraise_algos", args[0].from);
1551+
1552+
if (entry->allowed_algos) {
1553+
result = -EINVAL;
1554+
break;
1555+
}
1556+
1557+
entry->allowed_algos =
1558+
ima_parse_appraise_algos(args[0].from);
1559+
/* invalid or empty list of algorithms */
1560+
if (!entry->allowed_algos) {
1561+
result = -EINVAL;
1562+
break;
1563+
}
1564+
1565+
entry->flags |= IMA_VALIDATE_ALGOS;
1566+
1567+
break;
15251568
case Opt_permit_directio:
15261569
entry->flags |= IMA_PERMIT_DIRECTIO;
15271570
break;
@@ -1714,6 +1757,23 @@ static void ima_show_rule_opt_list(struct seq_file *m,
17141757
seq_printf(m, "%s%s", i ? "|" : "", opt_list->items[i]);
17151758
}
17161759

1760+
static void ima_policy_show_appraise_algos(struct seq_file *m,
1761+
unsigned int allowed_hashes)
1762+
{
1763+
int idx, list_size = 0;
1764+
1765+
for (idx = 0; idx < HASH_ALGO__LAST; idx++) {
1766+
if (!(allowed_hashes & (1U << idx)))
1767+
continue;
1768+
1769+
/* only add commas if the list contains multiple entries */
1770+
if (list_size++)
1771+
seq_puts(m, ",");
1772+
1773+
seq_puts(m, hash_algo_name[idx]);
1774+
}
1775+
}
1776+
17171777
int ima_policy_show(struct seq_file *m, void *v)
17181778
{
17191779
struct ima_rule_entry *entry = v;
@@ -1825,6 +1885,12 @@ int ima_policy_show(struct seq_file *m, void *v)
18251885
seq_puts(m, " ");
18261886
}
18271887

1888+
if (entry->flags & IMA_VALIDATE_ALGOS) {
1889+
seq_puts(m, "appraise_algos=");
1890+
ima_policy_show_appraise_algos(m, entry->allowed_algos);
1891+
seq_puts(m, " ");
1892+
}
1893+
18281894
for (i = 0; i < MAX_LSM_RULES; i++) {
18291895
if (entry->lsm[i].rule) {
18301896
switch (i) {

0 commit comments

Comments
 (0)