Skip to content

Commit

Permalink
Merge branch 'verify-evm-portable-sig-v2' into next-integrity
Browse files Browse the repository at this point in the history
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/[email protected]/
  • Loading branch information
mimizohar committed Jun 3, 2021
2 parents 5a25d8c + d721c15 commit dc0983f
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 15 deletions.
8 changes: 8 additions & 0 deletions Documentation/security/IMA-templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ descriptors by adding their identifier to the format string
- 'modsig' the appended file signature;
- 'buf': the buffer data that was used to generate the hash without size limitations;
- 'evmsig': the EVM portable signature;
- '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;

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


Use
Expand Down
16 changes: 16 additions & 0 deletions include/linux/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);
extern bool evm_revalidate_status(const char *xattr_name);
extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
int buffer_size, char type,
bool canonical_fmt);
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
Expand Down Expand Up @@ -114,5 +118,17 @@ static inline bool evm_revalidate_status(const char *xattr_name)
return false;
}

static inline int evm_protected_xattr_if_enabled(const char *req_xattr_name)
{
return false;
}

static inline int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
int buffer_size, char type,
bool canonical_fmt)
{
return -EOPNOTSUPP;
}

#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */
1 change: 1 addition & 0 deletions security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
struct xattr_list {
struct list_head list;
char *name;
bool enabled;
};

extern int evm_initialized;
Expand Down
7 changes: 7 additions & 0 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (strcmp(xattr->name, XATTR_NAME_IMA) == 0)
is_ima = true;

/*
* Skip non-enabled xattrs for locally calculated
* signatures/HMACs.
*/
if (type != EVM_XATTR_PORTABLE_DIGSIG && !xattr->enabled)
continue;

if ((req_xattr_name && req_xattr_value)
&& !strcmp(xattr->name, req_xattr_name)) {
error = 0;
Expand Down
125 changes: 115 additions & 10 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,44 @@ static const char * const integrity_status_msg[] = {
int evm_hmac_attrs;

static struct xattr_list evm_config_default_xattrnames[] = {
{.name = XATTR_NAME_SELINUX,
#ifdef CONFIG_SECURITY_SELINUX
{.name = XATTR_NAME_SELINUX},
.enabled = true
#endif
},
{.name = XATTR_NAME_SMACK,
#ifdef CONFIG_SECURITY_SMACK
{.name = XATTR_NAME_SMACK},
.enabled = true
#endif
},
{.name = XATTR_NAME_SMACKEXEC,
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
{.name = XATTR_NAME_SMACKEXEC},
{.name = XATTR_NAME_SMACKTRANSMUTE},
{.name = XATTR_NAME_SMACKMMAP},
.enabled = true
#endif
},
{.name = XATTR_NAME_SMACKTRANSMUTE,
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
.enabled = true
#endif
},
{.name = XATTR_NAME_SMACKMMAP,
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
.enabled = true
#endif
},
{.name = XATTR_NAME_APPARMOR,
#ifdef CONFIG_SECURITY_APPARMOR
{.name = XATTR_NAME_APPARMOR},
.enabled = true
#endif
},
{.name = XATTR_NAME_IMA,
#ifdef CONFIG_IMA_APPRAISE
{.name = XATTR_NAME_IMA},
.enabled = true
#endif
{.name = XATTR_NAME_CAPS},
},
{.name = XATTR_NAME_CAPS,
.enabled = true
},
};

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

pr_info("Initialising EVM extended attributes:\n");
for (i = 0; i < xattrs; i++) {
pr_info("%s\n", evm_config_default_xattrnames[i].name);
pr_info("%s%s\n", evm_config_default_xattrnames[i].name,
!evm_config_default_xattrnames[i].enabled ?
" (disabled)" : "");
list_add_tail(&evm_config_default_xattrnames[i].list,
&evm_config_xattrnames);
}
Expand Down Expand Up @@ -257,14 +279,18 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
return evm_status;
}

static int evm_protected_xattr(const char *req_xattr_name)
static int evm_protected_xattr_common(const char *req_xattr_name,
bool all_xattrs)
{
int namelen;
int found = 0;
struct xattr_list *xattr;

namelen = strlen(req_xattr_name);
list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
if (!all_xattrs && !xattr->enabled)
continue;

if ((strlen(xattr->name) == namelen)
&& (strncmp(req_xattr_name, xattr->name, namelen) == 0)) {
found = 1;
Expand All @@ -281,6 +307,85 @@ static int evm_protected_xattr(const char *req_xattr_name)
return found;
}

static int evm_protected_xattr(const char *req_xattr_name)
{
return evm_protected_xattr_common(req_xattr_name, false);
}

int evm_protected_xattr_if_enabled(const char *req_xattr_name)
{
return evm_protected_xattr_common(req_xattr_name, true);
}

/**
* evm_read_protected_xattrs - read EVM protected xattr names, lengths, values
* @dentry: dentry of the read xattrs
* @inode: inode of the read xattrs
* @buffer: buffer xattr names, lengths or values are copied to
* @buffer_size: size of buffer
* @type: n: names, l: lengths, v: values
* @canonical_fmt: data format (true: little endian, false: native format)
*
* Read protected xattr names (separated by |), lengths (u32) or values for a
* given dentry and return the total size of copied data. If buffer is NULL,
* just return the total size.
*
* Returns the total size on success, a negative value on error.
*/
int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
int buffer_size, char type, bool canonical_fmt)
{
struct xattr_list *xattr;
int rc, size, total_size = 0;

list_for_each_entry_lockless(xattr, &evm_config_xattrnames, list) {
rc = __vfs_getxattr(dentry, d_backing_inode(dentry),
xattr->name, NULL, 0);
if (rc < 0 && rc == -ENODATA)
continue;
else if (rc < 0)
return rc;

switch (type) {
case 'n':
size = strlen(xattr->name) + 1;
if (buffer) {
if (total_size)
*(buffer + total_size - 1) = '|';

memcpy(buffer + total_size, xattr->name, size);
}
break;
case 'l':
size = sizeof(u32);
if (buffer) {
if (canonical_fmt)
rc = cpu_to_le32(rc);

*(u32 *)(buffer + total_size) = rc;
}
break;
case 'v':
size = rc;
if (buffer) {
rc = __vfs_getxattr(dentry,
d_backing_inode(dentry), xattr->name,
buffer + total_size,
buffer_size - total_size);
if (rc < 0)
return rc;
}
break;
default:
return -EINVAL;
}

total_size += size;
}

return total_size;
}

/**
* evm_verifyxattr - verify the integrity of the requested xattr
* @dentry: object of the verify xattr
Expand Down
18 changes: 15 additions & 3 deletions security/integrity/evm/evm_secfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,12 @@ static ssize_t evm_read_xattrs(struct file *filp, char __user *buf,
if (rc)
return -ERESTARTSYS;

list_for_each_entry(xattr, &evm_config_xattrnames, list)
list_for_each_entry(xattr, &evm_config_xattrnames, list) {
if (!xattr->enabled)
continue;

size += strlen(xattr->name) + 1;
}

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

list_for_each_entry(xattr, &evm_config_xattrnames, list) {
if (!xattr->enabled)
continue;

sprintf(temp + offset, "%s\n", xattr->name);
offset += strlen(xattr->name) + 1;
}
Expand Down Expand Up @@ -190,7 +197,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,

ab = audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_INTEGRITY_EVM_XATTR);
if (!ab)
if (!ab && IS_ENABLED(CONFIG_AUDIT))
return -ENOMEM;

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

xattr->enabled = true;
xattr->name = memdup_user_nul(buf, count);
if (IS_ERR(xattr->name)) {
err = PTR_ERR(xattr->name);
Expand Down Expand Up @@ -245,6 +253,10 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
list_for_each_entry(tmp, &evm_config_xattrnames, list) {
if (strcmp(xattr->name, tmp->name) == 0) {
err = -EEXIST;
if (!tmp->enabled) {
tmp->enabled = true;
err = count;
}
mutex_unlock(&xattr_list_mutex);
goto out;
}
Expand All @@ -256,7 +268,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
audit_log_end(ab);
return count;
out:
audit_log_format(ab, " res=%d", err);
audit_log_format(ab, " res=%d", (err < 0) ? err : 0);
audit_log_end(ab);
if (xattr) {
kfree(xattr->name);
Expand Down
20 changes: 19 additions & 1 deletion security/integrity/ima/ima_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ static struct ima_template_desc builtin_templates[] = {
{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
{.name = "evm-sig",
.fmt = "d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode"},
{.name = "", .fmt = ""}, /* placeholder for a custom format */
};

Expand All @@ -47,14 +49,30 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_sig},
{.field_id = "evmsig", .field_init = ima_eventevmsig_init,
.field_show = ima_show_template_sig},
{.field_id = "iuid", .field_init = ima_eventinodeuid_init,
.field_show = ima_show_template_uint},
{.field_id = "igid", .field_init = ima_eventinodegid_init,
.field_show = ima_show_template_uint},
{.field_id = "imode", .field_init = ima_eventinodemode_init,
.field_show = ima_show_template_uint},
{.field_id = "xattrnames",
.field_init = ima_eventinodexattrnames_init,
.field_show = ima_show_template_string},
{.field_id = "xattrlengths",
.field_init = ima_eventinodexattrlengths_init,
.field_show = ima_show_template_sig},
{.field_id = "xattrvalues",
.field_init = ima_eventinodexattrvalues_init,
.field_show = ima_show_template_sig},
};

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

static struct ima_template_desc *ima_template;
static struct ima_template_desc *ima_buf_template;
Expand Down
Loading

0 comments on commit dc0983f

Please sign in to comment.