Skip to content

Commit dc0983f

Browse files
committed
Merge branch 'verify-evm-portable-sig-v2' into next-integrity
From the cover letter: The recent patch set 'evm: Improve usability of portable signatures' added the possibility to include EVM portable signatures in the IMA measurement list. However, the information necessary to verify the signature were not included in the IMA measurement list. This patch set introduces new template fields to accomplish this goal: - 'iuid': the inode UID; - 'igid': the inode GID; - 'imode': the inode mode; - 'xattrnames': a list of xattr names (separated by |), only if the xattr is present; - 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present; - 'xattrvalues': a list of xattr values; Patch 1 adds an helper function to show integers in the measurement list. Patches 2, 3 and 5 introduce new template fields. Patch 4 make it possible to verify EVM portable signatures which protect xattrs belonging to LSMs not enabled in the target platform. Patch 6 introduces the new IMA template evm-sig. Patch 7 fixes a small issue in evm_write_xattrs() when audit is not enabled. Link: https://lore.kernel.org/linux-integrity/20210528073812.407936-1-roberto.sassu@huawei.com/
2 parents 5a25d8c + d721c15 commit dc0983f

9 files changed

Lines changed: 363 additions & 15 deletions

File tree

Documentation/security/IMA-templates.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ descriptors by adding their identifier to the format string
7575
- 'modsig' the appended file signature;
7676
- 'buf': the buffer data that was used to generate the hash without size limitations;
7777
- 'evmsig': the EVM portable signature;
78+
- 'iuid': the inode UID;
79+
- 'igid': the inode GID;
80+
- 'imode': the inode mode;
81+
- 'xattrnames': a list of xattr names (separated by |), only if the xattr is
82+
present;
83+
- 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present;
84+
- 'xattrvalues': a list of xattr values;
7885
7986

8087
Below, there is the list of defined template descriptors:
@@ -84,6 +91,7 @@ Below, there is the list of defined template descriptors:
8491
- "ima-sig": its format is ``d-ng|n-ng|sig``;
8592
- "ima-buf": its format is ``d-ng|n-ng|buf``;
8693
- "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
94+
- "evm-sig": its format is ``d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode``;
8795

8896

8997
Use

include/linux/evm.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ extern int evm_inode_init_security(struct inode *inode,
3838
const struct xattr *xattr_array,
3939
struct xattr *evm);
4040
extern bool evm_revalidate_status(const char *xattr_name);
41+
extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
42+
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
43+
int buffer_size, char type,
44+
bool canonical_fmt);
4145
#ifdef CONFIG_FS_POSIX_ACL
4246
extern int posix_xattr_acl(const char *xattrname);
4347
#else
@@ -114,5 +118,17 @@ static inline bool evm_revalidate_status(const char *xattr_name)
114118
return false;
115119
}
116120

121+
static inline int evm_protected_xattr_if_enabled(const char *req_xattr_name)
122+
{
123+
return false;
124+
}
125+
126+
static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
127+
int buffer_size, char type,
128+
bool canonical_fmt)
129+
{
130+
return -EOPNOTSUPP;
131+
}
132+
117133
#endif /* CONFIG_EVM */
118134
#endif /* LINUX_EVM_H */

security/integrity/evm/evm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
struct xattr_list {
3030
struct list_head list;
3131
char *name;
32+
bool enabled;
3233
};
3334

3435
extern int evm_initialized;

security/integrity/evm/evm_crypto.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
216216
if (strcmp(xattr->name, XATTR_NAME_IMA) == 0)
217217
is_ima = true;
218218

219+
/*
220+
* Skip non-enabled xattrs for locally calculated
221+
* signatures/HMACs.
222+
*/
223+
if (type != EVM_XATTR_PORTABLE_DIGSIG && !xattr->enabled)
224+
continue;
225+
219226
if ((req_xattr_name && req_xattr_value)
220227
&& !strcmp(xattr->name, req_xattr_name)) {
221228
error = 0;

security/integrity/evm/evm_main.c

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,44 @@ static const char * const integrity_status_msg[] = {
3434
int evm_hmac_attrs;
3535

3636
static struct xattr_list evm_config_default_xattrnames[] = {
37+
{.name = XATTR_NAME_SELINUX,
3738
#ifdef CONFIG_SECURITY_SELINUX
38-
{.name = XATTR_NAME_SELINUX},
39+
.enabled = true
3940
#endif
41+
},
42+
{.name = XATTR_NAME_SMACK,
4043
#ifdef CONFIG_SECURITY_SMACK
41-
{.name = XATTR_NAME_SMACK},
44+
.enabled = true
45+
#endif
46+
},
47+
{.name = XATTR_NAME_SMACKEXEC,
4248
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
43-
{.name = XATTR_NAME_SMACKEXEC},
44-
{.name = XATTR_NAME_SMACKTRANSMUTE},
45-
{.name = XATTR_NAME_SMACKMMAP},
49+
.enabled = true
4650
#endif
51+
},
52+
{.name = XATTR_NAME_SMACKTRANSMUTE,
53+
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
54+
.enabled = true
4755
#endif
56+
},
57+
{.name = XATTR_NAME_SMACKMMAP,
58+
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
59+
.enabled = true
60+
#endif
61+
},
62+
{.name = XATTR_NAME_APPARMOR,
4863
#ifdef CONFIG_SECURITY_APPARMOR
49-
{.name = XATTR_NAME_APPARMOR},
64+
.enabled = true
5065
#endif
66+
},
67+
{.name = XATTR_NAME_IMA,
5168
#ifdef CONFIG_IMA_APPRAISE
52-
{.name = XATTR_NAME_IMA},
69+
.enabled = true
5370
#endif
54-
{.name = XATTR_NAME_CAPS},
71+
},
72+
{.name = XATTR_NAME_CAPS,
73+
.enabled = true
74+
},
5575
};
5676

5777
LIST_HEAD(evm_config_xattrnames);
@@ -76,7 +96,9 @@ static void __init evm_init_config(void)
7696

7797
pr_info("Initialising EVM extended attributes:\n");
7898
for (i = 0; i < xattrs; i++) {
79-
pr_info("%s\n", evm_config_default_xattrnames[i].name);
99+
pr_info("%s%s\n", evm_config_default_xattrnames[i].name,
100+
!evm_config_default_xattrnames[i].enabled ?
101+
" (disabled)" : "");
80102
list_add_tail(&evm_config_default_xattrnames[i].list,
81103
&evm_config_xattrnames);
82104
}
@@ -257,14 +279,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
257279
return evm_status;
258280
}
259281

260-
static int evm_protected_xattr(const char *req_xattr_name)
282+
static int evm_protected_xattr_common(const char *req_xattr_name,
283+
bool all_xattrs)
261284
{
262285
int namelen;
263286
int found = 0;
264287
struct xattr_list *xattr;
265288

266289
namelen = strlen(req_xattr_name);
267290
list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
291+
if (!all_xattrs && !xattr->enabled)
292+
continue;
293+
268294
if ((strlen(xattr->name) == namelen)
269295
&& (strncmp(req_xattr_name, xattr->name, namelen) == 0)) {
270296
found = 1;
@@ -281,6 +307,85 @@ static int evm_protected_xattr(const char *req_xattr_name)
281307
return found;
282308
}
283309

310+
static int evm_protected_xattr(const char *req_xattr_name)
311+
{
312+
return evm_protected_xattr_common(req_xattr_name, false);
313+
}
314+
315+
int evm_protected_xattr_if_enabled(const char *req_xattr_name)
316+
{
317+
return evm_protected_xattr_common(req_xattr_name, true);
318+
}
319+
320+
/**
321+
* evm_read_protected_xattrs - read EVM protected xattr names, lengths, values
322+
* @dentry: dentry of the read xattrs
323+
* @inode: inode of the read xattrs
324+
* @buffer: buffer xattr names, lengths or values are copied to
325+
* @buffer_size: size of buffer
326+
* @type: n: names, l: lengths, v: values
327+
* @canonical_fmt: data format (true: little endian, false: native format)
328+
*
329+
* Read protected xattr names (separated by |), lengths (u32) or values for a
330+
* given dentry and return the total size of copied data. If buffer is NULL,
331+
* just return the total size.
332+
*
333+
* Returns the total size on success, a negative value on error.
334+
*/
335+
int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
336+
int buffer_size, char type, bool canonical_fmt)
337+
{
338+
struct xattr_list *xattr;
339+
int rc, size, total_size = 0;
340+
341+
list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
342+
rc = __vfs_getxattr(dentry, d_backing_inode(dentry),
343+
xattr->name, NULL, 0);
344+
if (rc < 0 && rc == -ENODATA)
345+
continue;
346+
else if (rc < 0)
347+
return rc;
348+
349+
switch (type) {
350+
case 'n':
351+
size = strlen(xattr->name) + 1;
352+
if (buffer) {
353+
if (total_size)
354+
*(buffer + total_size - 1) = '|';
355+
356+
memcpy(buffer + total_size, xattr->name, size);
357+
}
358+
break;
359+
case 'l':
360+
size = sizeof(u32);
361+
if (buffer) {
362+
if (canonical_fmt)
363+
rc = cpu_to_le32(rc);
364+
365+
*(u32 *)(buffer + total_size) = rc;
366+
}
367+
break;
368+
case 'v':
369+
size = rc;
370+
if (buffer) {
371+
rc = __vfs_getxattr(dentry,
372+
d_backing_inode(dentry), xattr->name,
373+
buffer + total_size,
374+
buffer_size - total_size);
375+
if (rc < 0)
376+
return rc;
377+
}
378+
break;
379+
default:
380+
return -EINVAL;
381+
}
382+
383+
total_size += size;
384+
}
385+
386+
return total_size;
387+
}
388+
284389
/**
285390
* evm_verifyxattr - verify the integrity of the requested xattr
286391
* @dentry: object of the verify xattr

security/integrity/evm/evm_secfs.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,12 @@ static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
139139
if (rc)
140140
return -ERESTARTSYS;
141141

142-
list_for_each_entry(xattr, &evm_config_xattrnames, list)
142+
list_for_each_entry(xattr, &evm_config_xattrnames, list) {
143+
if (!xattr->enabled)
144+
continue;
145+
143146
size += strlen(xattr->name) + 1;
147+
}
144148

145149
temp = kmalloc(size + 1, GFP_KERNEL);
146150
if (!temp) {
@@ -149,6 +153,9 @@ static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
149153
}
150154

151155
list_for_each_entry(xattr, &evm_config_xattrnames, list) {
156+
if (!xattr->enabled)
157+
continue;
158+
152159
sprintf(temp + offset, "%s\n", xattr->name);
153160
offset += strlen(xattr->name) + 1;
154161
}
@@ -190,7 +197,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
190197

191198
ab = audit_log_start(audit_context(), GFP_KERNEL,
192199
AUDIT_INTEGRITY_EVM_XATTR);
193-
if (!ab)
200+
if (!ab && IS_ENABLED(CONFIG_AUDIT))
194201
return -ENOMEM;
195202

196203
xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
@@ -199,6 +206,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
199206
goto out;
200207
}
201208

209+
xattr->enabled = true;
202210
xattr->name = memdup_user_nul(buf, count);
203211
if (IS_ERR(xattr->name)) {
204212
err = PTR_ERR(xattr->name);
@@ -245,6 +253,10 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
245253
list_for_each_entry(tmp, &evm_config_xattrnames, list) {
246254
if (strcmp(xattr->name, tmp->name) == 0) {
247255
err = -EEXIST;
256+
if (!tmp->enabled) {
257+
tmp->enabled = true;
258+
err = count;
259+
}
248260
mutex_unlock(&xattr_list_mutex);
249261
goto out;
250262
}
@@ -256,7 +268,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
256268
audit_log_end(ab);
257269
return count;
258270
out:
259-
audit_log_format(ab, " res=%d", err);
271+
audit_log_format(ab, " res=%d", (err < 0) ? err : 0);
260272
audit_log_end(ab);
261273
if (xattr) {
262274
kfree(xattr->name);

security/integrity/ima/ima_template.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ static struct ima_template_desc builtin_templates[] = {
2222
{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
2323
{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
2424
{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
25+
{.name = "evm-sig",
26+
.fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"},
2527
{.name = "", .fmt = ""}, /* placeholder for a custom format */
2628
};
2729

@@ -47,14 +49,30 @@ static const struct ima_template_field supported_fields[] = {
4749
.field_show = ima_show_template_sig},
4850
{.field_id = "evmsig", .field_init = ima_eventevmsig_init,
4951
.field_show = ima_show_template_sig},
52+
{.field_id = "iuid", .field_init = ima_eventinodeuid_init,
53+
.field_show = ima_show_template_uint},
54+
{.field_id = "igid", .field_init = ima_eventinodegid_init,
55+
.field_show = ima_show_template_uint},
56+
{.field_id = "imode", .field_init = ima_eventinodemode_init,
57+
.field_show = ima_show_template_uint},
58+
{.field_id = "xattrnames",
59+
.field_init = ima_eventinodexattrnames_init,
60+
.field_show = ima_show_template_string},
61+
{.field_id = "xattrlengths",
62+
.field_init = ima_eventinodexattrlengths_init,
63+
.field_show = ima_show_template_sig},
64+
{.field_id = "xattrvalues",
65+
.field_init = ima_eventinodexattrvalues_init,
66+
.field_show = ima_show_template_sig},
5067
};
5168

5269
/*
5370
* Used when restoring measurements carried over from a kexec. 'd' and 'n' don't
5471
* need to be accounted for since they shouldn't be defined in the same template
5572
* description as 'd-ng' and 'n-ng' respectively.
5673
*/
57-
#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
74+
#define MAX_TEMPLATE_NAME_LEN \
75+
sizeof("d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode")
5876

5977
static struct ima_template_desc *ima_template;
6078
static struct ima_template_desc *ima_buf_template;

0 commit comments

Comments
 (0)