Skip to content

Commit 40224c4

Browse files
Curtis Veitmimizohar
authored andcommitted
ima: add gid support
IMA currently supports the concept of rules based on uid where the rule is based on the uid of the file owner or the uid of the user accessing the file. Provide the ability to have similar rules based on gid. Signed-off-by: Curtis Veit <[email protected]> Co-developed-by: Alex Henrie <[email protected]> Signed-off-by: Alex Henrie <[email protected]> Reviewed-by: Petr Vorel <[email protected]> Signed-off-by: Mimi Zohar <[email protected]>
1 parent 30d8764 commit 40224c4

File tree

2 files changed

+180
-29
lines changed

2 files changed

+180
-29
lines changed

Documentation/ABI/testing/ima_policy

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ Description:
2222
action: measure | dont_measure | appraise | dont_appraise |
2323
audit | hash | dont_hash
2424
condition:= base | lsm [option]
25-
base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
26-
[euid=] [fowner=] [fsname=]]
25+
base: [[func=] [mask=] [fsmagic=] [fsuuid=] [fsname=]
26+
[uid=] [euid=] [gid=] [egid=]
27+
[fowner=] [fgroup=]]
2728
lsm: [[subj_user=] [subj_role=] [subj_type=]
2829
[obj_user=] [obj_role=] [obj_type=]]
2930
option: [[appraise_type=]] [template=] [permit_directio]
@@ -40,7 +41,10 @@ Description:
4041
fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6)
4142
uid:= decimal value
4243
euid:= decimal value
44+
gid:= decimal value
45+
egid:= decimal value
4346
fowner:= decimal value
47+
fgroup:= decimal value
4448
lsm: are LSM specific
4549
option:
4650
appraise_type:= [imasig] [imasig|modsig]

security/integrity/ima/ima_policy.c

Lines changed: 174 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
#define IMA_KEYRINGS 0x0400
3737
#define IMA_LABEL 0x0800
3838
#define IMA_VALIDATE_ALGOS 0x1000
39+
#define IMA_GID 0x2000
40+
#define IMA_EGID 0x4000
41+
#define IMA_FGROUP 0x8000
3942

4043
#define UNKNOWN 0
4144
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -78,9 +81,13 @@ struct ima_rule_entry {
7881
unsigned long fsmagic;
7982
uuid_t fsuuid;
8083
kuid_t uid;
84+
kgid_t gid;
8185
kuid_t fowner;
86+
kgid_t fgroup;
8287
bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */
88+
bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid);
8389
bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */
90+
bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
8491
int pcr;
8592
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
8693
struct {
@@ -104,7 +111,8 @@ static_assert(
104111

105112
/*
106113
* Without LSM specific knowledge, the default policy can only be
107-
* written in terms of .action, .func, .mask, .fsmagic, .uid, and .fowner
114+
* written in terms of .action, .func, .mask, .fsmagic, .uid, .gid,
115+
* .fowner, and .fgroup
108116
*/
109117

110118
/*
@@ -582,10 +590,23 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
582590
} else if (!rule->uid_op(cred->euid, rule->uid))
583591
return false;
584592
}
585-
593+
if ((rule->flags & IMA_GID) && !rule->gid_op(cred->gid, rule->gid))
594+
return false;
595+
if (rule->flags & IMA_EGID) {
596+
if (has_capability_noaudit(current, CAP_SETGID)) {
597+
if (!rule->gid_op(cred->egid, rule->gid)
598+
&& !rule->gid_op(cred->sgid, rule->gid)
599+
&& !rule->gid_op(cred->gid, rule->gid))
600+
return false;
601+
} else if (!rule->gid_op(cred->egid, rule->gid))
602+
return false;
603+
}
586604
if ((rule->flags & IMA_FOWNER) &&
587605
!rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner))
588606
return false;
607+
if ((rule->flags & IMA_FGROUP) &&
608+
!rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup))
609+
return false;
589610
for (i = 0; i < MAX_LSM_RULES; i++) {
590611
int rc = 0;
591612
u32 osid;
@@ -991,16 +1012,19 @@ void ima_update_policy(void)
9911012
}
9921013

9931014
/* Keep the enumeration in sync with the policy_tokens! */
994-
enum {
1015+
enum policy_opt {
9951016
Opt_measure, Opt_dont_measure,
9961017
Opt_appraise, Opt_dont_appraise,
9971018
Opt_audit, Opt_hash, Opt_dont_hash,
9981019
Opt_obj_user, Opt_obj_role, Opt_obj_type,
9991020
Opt_subj_user, Opt_subj_role, Opt_subj_type,
1000-
Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname,
1001-
Opt_fsuuid, Opt_uid_eq, Opt_euid_eq, Opt_fowner_eq,
1002-
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
1003-
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
1021+
Opt_func, Opt_mask, Opt_fsmagic, Opt_fsname, Opt_fsuuid,
1022+
Opt_uid_eq, Opt_euid_eq, Opt_gid_eq, Opt_egid_eq,
1023+
Opt_fowner_eq, Opt_fgroup_eq,
1024+
Opt_uid_gt, Opt_euid_gt, Opt_gid_gt, Opt_egid_gt,
1025+
Opt_fowner_gt, Opt_fgroup_gt,
1026+
Opt_uid_lt, Opt_euid_lt, Opt_gid_lt, Opt_egid_lt,
1027+
Opt_fowner_lt, Opt_fgroup_lt,
10041028
Opt_appraise_type, Opt_appraise_flag, Opt_appraise_algos,
10051029
Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings,
10061030
Opt_label, Opt_err
@@ -1027,13 +1051,22 @@ static const match_table_t policy_tokens = {
10271051
{Opt_fsuuid, "fsuuid=%s"},
10281052
{Opt_uid_eq, "uid=%s"},
10291053
{Opt_euid_eq, "euid=%s"},
1054+
{Opt_gid_eq, "gid=%s"},
1055+
{Opt_egid_eq, "egid=%s"},
10301056
{Opt_fowner_eq, "fowner=%s"},
1057+
{Opt_fgroup_eq, "fgroup=%s"},
10311058
{Opt_uid_gt, "uid>%s"},
10321059
{Opt_euid_gt, "euid>%s"},
1060+
{Opt_gid_gt, "gid>%s"},
1061+
{Opt_egid_gt, "egid>%s"},
10331062
{Opt_fowner_gt, "fowner>%s"},
1063+
{Opt_fgroup_gt, "fgroup>%s"},
10341064
{Opt_uid_lt, "uid<%s"},
10351065
{Opt_euid_lt, "euid<%s"},
1066+
{Opt_gid_lt, "gid<%s"},
1067+
{Opt_egid_lt, "egid<%s"},
10361068
{Opt_fowner_lt, "fowner<%s"},
1069+
{Opt_fgroup_lt, "fgroup<%s"},
10371070
{Opt_appraise_type, "appraise_type=%s"},
10381071
{Opt_appraise_flag, "appraise_flag=%s"},
10391072
{Opt_appraise_algos, "appraise_algos=%s"},
@@ -1077,22 +1110,36 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
10771110
}
10781111

10791112
static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value,
1080-
bool (*rule_operator)(kuid_t, kuid_t))
1113+
enum policy_opt rule_operator)
10811114
{
10821115
if (!ab)
10831116
return;
10841117

1085-
if (rule_operator == &uid_gt)
1118+
switch (rule_operator) {
1119+
case Opt_uid_gt:
1120+
case Opt_euid_gt:
1121+
case Opt_gid_gt:
1122+
case Opt_egid_gt:
1123+
case Opt_fowner_gt:
1124+
case Opt_fgroup_gt:
10861125
audit_log_format(ab, "%s>", key);
1087-
else if (rule_operator == &uid_lt)
1126+
break;
1127+
case Opt_uid_lt:
1128+
case Opt_euid_lt:
1129+
case Opt_gid_lt:
1130+
case Opt_egid_lt:
1131+
case Opt_fowner_lt:
1132+
case Opt_fgroup_lt:
10881133
audit_log_format(ab, "%s<", key);
1089-
else
1134+
break;
1135+
default:
10901136
audit_log_format(ab, "%s=", key);
1137+
}
10911138
audit_log_format(ab, "%s ", value);
10921139
}
10931140
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
10941141
{
1095-
ima_log_string_op(ab, key, value, NULL);
1142+
ima_log_string_op(ab, key, value, Opt_err);
10961143
}
10971144

10981145
/*
@@ -1167,7 +1214,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11671214
if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
11681215
IMA_UID | IMA_FOWNER | IMA_FSUUID |
11691216
IMA_INMASK | IMA_EUID | IMA_PCR |
1170-
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
1217+
IMA_FSNAME | IMA_GID | IMA_EGID |
1218+
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
11711219
IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS))
11721220
return false;
11731221

@@ -1178,7 +1226,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11781226
if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC |
11791227
IMA_UID | IMA_FOWNER | IMA_FSUUID |
11801228
IMA_INMASK | IMA_EUID | IMA_PCR |
1181-
IMA_FSNAME | IMA_DIGSIG_REQUIRED |
1229+
IMA_FSNAME | IMA_GID | IMA_EGID |
1230+
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
11821231
IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED |
11831232
IMA_CHECK_BLACKLIST | IMA_VALIDATE_ALGOS))
11841233
return false;
@@ -1190,15 +1239,16 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
11901239

11911240
if (entry->flags & ~(IMA_FUNC | IMA_FSMAGIC | IMA_UID |
11921241
IMA_FOWNER | IMA_FSUUID | IMA_EUID |
1193-
IMA_PCR | IMA_FSNAME))
1242+
IMA_PCR | IMA_FSNAME | IMA_GID | IMA_EGID |
1243+
IMA_FGROUP))
11941244
return false;
11951245

11961246
break;
11971247
case KEY_CHECK:
11981248
if (entry->action & ~(MEASURE | DONT_MEASURE))
11991249
return false;
12001250

1201-
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_PCR |
1251+
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR |
12021252
IMA_KEYRINGS))
12031253
return false;
12041254

@@ -1210,7 +1260,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
12101260
if (entry->action & ~(MEASURE | DONT_MEASURE))
12111261
return false;
12121262

1213-
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_PCR |
1263+
if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_GID | IMA_PCR |
12141264
IMA_LABEL))
12151265
return false;
12161266

@@ -1280,17 +1330,21 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
12801330
struct audit_buffer *ab;
12811331
char *from;
12821332
char *p;
1283-
bool uid_token;
1333+
bool eid_token; /* either euid or egid */
12841334
struct ima_template_desc *template_desc;
12851335
int result = 0;
12861336

12871337
ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
12881338
AUDIT_INTEGRITY_POLICY_RULE);
12891339

12901340
entry->uid = INVALID_UID;
1341+
entry->gid = INVALID_GID;
12911342
entry->fowner = INVALID_UID;
1343+
entry->fgroup = INVALID_GID;
12921344
entry->uid_op = &uid_eq;
1345+
entry->gid_op = &gid_eq;
12931346
entry->fowner_op = &uid_eq;
1347+
entry->fgroup_op = &gid_eq;
12941348
entry->action = UNKNOWN;
12951349
while ((p = strsep(&rule, " \t")) != NULL) {
12961350
substring_t args[MAX_OPT_ARGS];
@@ -1508,12 +1562,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
15081562
fallthrough;
15091563
case Opt_uid_eq:
15101564
case Opt_euid_eq:
1511-
uid_token = (token == Opt_uid_eq) ||
1512-
(token == Opt_uid_gt) ||
1513-
(token == Opt_uid_lt);
1565+
eid_token = (token == Opt_euid_eq) ||
1566+
(token == Opt_euid_gt) ||
1567+
(token == Opt_euid_lt);
15141568

1515-
ima_log_string_op(ab, uid_token ? "uid" : "euid",
1516-
args[0].from, entry->uid_op);
1569+
ima_log_string_op(ab, eid_token ? "euid" : "uid",
1570+
args[0].from, token);
15171571

15181572
if (uid_valid(entry->uid)) {
15191573
result = -EINVAL;
@@ -1528,8 +1582,43 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
15281582
(uid_t)lnum != lnum)
15291583
result = -EINVAL;
15301584
else
1531-
entry->flags |= uid_token
1532-
? IMA_UID : IMA_EUID;
1585+
entry->flags |= eid_token
1586+
? IMA_EUID : IMA_UID;
1587+
}
1588+
break;
1589+
case Opt_gid_gt:
1590+
case Opt_egid_gt:
1591+
entry->gid_op = &gid_gt;
1592+
fallthrough;
1593+
case Opt_gid_lt:
1594+
case Opt_egid_lt:
1595+
if ((token == Opt_gid_lt) || (token == Opt_egid_lt))
1596+
entry->gid_op = &gid_lt;
1597+
fallthrough;
1598+
case Opt_gid_eq:
1599+
case Opt_egid_eq:
1600+
eid_token = (token == Opt_egid_eq) ||
1601+
(token == Opt_egid_gt) ||
1602+
(token == Opt_egid_lt);
1603+
1604+
ima_log_string_op(ab, eid_token ? "egid" : "gid",
1605+
args[0].from, token);
1606+
1607+
if (gid_valid(entry->gid)) {
1608+
result = -EINVAL;
1609+
break;
1610+
}
1611+
1612+
result = kstrtoul(args[0].from, 10, &lnum);
1613+
if (!result) {
1614+
entry->gid = make_kgid(current_user_ns(),
1615+
(gid_t)lnum);
1616+
if (!gid_valid(entry->gid) ||
1617+
(((gid_t)lnum) != lnum))
1618+
result = -EINVAL;
1619+
else
1620+
entry->flags |= eid_token
1621+
? IMA_EGID : IMA_GID;
15331622
}
15341623
break;
15351624
case Opt_fowner_gt:
@@ -1540,8 +1629,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
15401629
entry->fowner_op = &uid_lt;
15411630
fallthrough;
15421631
case Opt_fowner_eq:
1543-
ima_log_string_op(ab, "fowner", args[0].from,
1544-
entry->fowner_op);
1632+
ima_log_string_op(ab, "fowner", args[0].from, token);
15451633

15461634
if (uid_valid(entry->fowner)) {
15471635
result = -EINVAL;
@@ -1559,6 +1647,32 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
15591647
entry->flags |= IMA_FOWNER;
15601648
}
15611649
break;
1650+
case Opt_fgroup_gt:
1651+
entry->fgroup_op = &gid_gt;
1652+
fallthrough;
1653+
case Opt_fgroup_lt:
1654+
if (token == Opt_fgroup_lt)
1655+
entry->fgroup_op = &gid_lt;
1656+
fallthrough;
1657+
case Opt_fgroup_eq:
1658+
ima_log_string_op(ab, "fgroup", args[0].from, token);
1659+
1660+
if (gid_valid(entry->fgroup)) {
1661+
result = -EINVAL;
1662+
break;
1663+
}
1664+
1665+
result = kstrtoul(args[0].from, 10, &lnum);
1666+
if (!result) {
1667+
entry->fgroup = make_kgid(current_user_ns(),
1668+
(gid_t)lnum);
1669+
if (!gid_valid(entry->fgroup) ||
1670+
(((gid_t)lnum) != lnum))
1671+
result = -EINVAL;
1672+
else
1673+
entry->flags |= IMA_FGROUP;
1674+
}
1675+
break;
15621676
case Opt_obj_user:
15631677
ima_log_string(ab, "obj_user", args[0].from);
15641678
result = ima_lsm_rule_init(entry, args,
@@ -1945,6 +2059,28 @@ int ima_policy_show(struct seq_file *m, void *v)
19452059
seq_puts(m, " ");
19462060
}
19472061

2062+
if (entry->flags & IMA_GID) {
2063+
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid));
2064+
if (entry->gid_op == &gid_gt)
2065+
seq_printf(m, pt(Opt_gid_gt), tbuf);
2066+
else if (entry->gid_op == &gid_lt)
2067+
seq_printf(m, pt(Opt_gid_lt), tbuf);
2068+
else
2069+
seq_printf(m, pt(Opt_gid_eq), tbuf);
2070+
seq_puts(m, " ");
2071+
}
2072+
2073+
if (entry->flags & IMA_EGID) {
2074+
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->gid));
2075+
if (entry->gid_op == &gid_gt)
2076+
seq_printf(m, pt(Opt_egid_gt), tbuf);
2077+
else if (entry->gid_op == &gid_lt)
2078+
seq_printf(m, pt(Opt_egid_lt), tbuf);
2079+
else
2080+
seq_printf(m, pt(Opt_egid_eq), tbuf);
2081+
seq_puts(m, " ");
2082+
}
2083+
19482084
if (entry->flags & IMA_FOWNER) {
19492085
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
19502086
if (entry->fowner_op == &uid_gt)
@@ -1956,6 +2092,17 @@ int ima_policy_show(struct seq_file *m, void *v)
19562092
seq_puts(m, " ");
19572093
}
19582094

2095+
if (entry->flags & IMA_FGROUP) {
2096+
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup));
2097+
if (entry->fgroup_op == &gid_gt)
2098+
seq_printf(m, pt(Opt_fgroup_gt), tbuf);
2099+
else if (entry->fgroup_op == &gid_lt)
2100+
seq_printf(m, pt(Opt_fgroup_lt), tbuf);
2101+
else
2102+
seq_printf(m, pt(Opt_fgroup_eq), tbuf);
2103+
seq_puts(m, " ");
2104+
}
2105+
19592106
if (entry->flags & IMA_VALIDATE_ALGOS) {
19602107
seq_puts(m, "appraise_algos=");
19612108
ima_policy_show_appraise_algos(m, entry->allowed_algos);

0 commit comments

Comments
 (0)