Commit a60c538e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'integrity-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity subsystem updates from Mimi Zohar:
 "The large majority of the changes are EVM portable & immutable
  signature related: removing a dependency on loading an HMAC key,
  safely allowing file metadata included in the EVM portable & immutable
  signatures to be modified, allowing EVM signatures to fulfill IMA file
  signature policy requirements, including the EVM file metadata
  signature in lieu of an IMA file data signature in the measurement
  list, and adding dynamic debugging of EVM file metadata.

  In addition, in order to detect critical data or file change
  reversions, duplicate measurement records are permitted in the IMA
  measurement list.

  The remaining patches address compiler, sparse, and doc warnings"

* tag 'integrity-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity: (31 commits)
  evm: Check xattr size discrepancy between kernel and user
  evm: output EVM digest calculation info
  IMA: support for duplicate measurement records
  ima: Fix warning: no previous prototype for function 'ima_add_kexec_buffer'
  ima: differentiate between EVM failures in the audit log
  ima: Fix fall-through warning for Clang
  ima: Pass NULL instead of 0 to ima_get_action() in ima_file_mprotect()
  ima: Include header defining ima_post_key_create_or_update()
  ima/evm: Fix type mismatch
  ima: Set correct casting types
  doc: Fix warning in Documentation/security/IMA-templates.rst
  evm: Don't return an error in evm_write_xattrs() if audit is not enabled
  ima: Define new template evm-sig
  ima: Define new template fields xattrnames, xattrlengths and xattrvalues
  evm: Verify portable signatures against all protected xattrs
  ima: Define new template field imode
  ima: Define new template fields iuid and igid
  ima: Add ima_show_template_uint() template library function
  ima: Don't remove security.ima if file must not be appraised
  ima: Introduce template field evmsig and write to field sig as fallback
  ...
parents 9cd19f02 907a399d
......@@ -24,7 +24,7 @@ Description:
1 Enable digital signature validation
2 Permit modification of EVM-protected metadata at
runtime. Not supported if HMAC validation and
creation is enabled.
creation is enabled (deprecated).
31 Disable further runtime modification of EVM policy
=== ==================================================
......@@ -47,10 +47,38 @@ Description:
will enable digital signature validation, permit
modification of EVM-protected metadata and
disable all further modification of policy
disable all further modification of policy. This option is now
deprecated in favor of::
Note that once a key has been loaded, it will no longer be
possible to enable metadata modification.
echo 0x80000002 ><securityfs>/evm
as the outstanding issues that prevent the usage of EVM portable
signatures have been solved.
Echoing a value is additive, the new value is added to the
existing initialization flags.
For example, after::
echo 2 ><securityfs>/evm
another echo can be performed::
echo 1 ><securityfs>/evm
and the resulting value will be 3.
Note that once an HMAC key has been loaded, it will no longer
be possible to enable metadata modification. Signaling that an
HMAC key has been loaded will clear the corresponding flag.
For example, if the current value is 6 (2 and 4 set)::
echo 1 ><securityfs>/evm
will set the new value to 3 (4 cleared).
Loading an HMAC key is the only way to disable metadata
modification.
Until key loading has been signaled EVM can not create
or validate the 'security.evm' xattr, but returns
......
......@@ -70,9 +70,18 @@ descriptors by adding their identifier to the format string
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'd-modsig': the digest of the event without the appended modsig;
- 'n-ng': the name of the event, without size limitations;
- 'sig': the file signature;
- 'sig': the file signature, or the EVM portable signature if the file
signature is not found;
- '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:
......@@ -82,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
......
......@@ -23,18 +23,25 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
struct integrity_iint_cache *iint);
extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr);
extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid);
extern int evm_inode_setxattr(struct dentry *dentry, const char *name,
extern int evm_inode_setxattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
const void *value, size_t size);
extern void evm_inode_post_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len);
extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name);
extern int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
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
......@@ -71,7 +78,8 @@ static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
return;
}
static inline int evm_inode_setxattr(struct dentry *dentry, const char *name,
static inline int evm_inode_setxattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name,
const void *value, size_t size)
{
return 0;
......@@ -85,7 +93,8 @@ static inline void evm_inode_post_setxattr(struct dentry *dentry,
return;
}
static inline int evm_inode_removexattr(struct dentry *dentry,
static inline int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *xattr_name)
{
return 0;
......@@ -104,5 +113,22 @@ static inline int evm_inode_init_security(struct inode *inode,
return 0;
}
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 */
......@@ -13,6 +13,7 @@ enum integrity_status {
INTEGRITY_PASS = 0,
INTEGRITY_PASS_IMMUTABLE,
INTEGRITY_FAIL,
INTEGRITY_FAIL_IMMUTABLE,
INTEGRITY_NOLABEL,
INTEGRITY_NOXATTRS,
INTEGRITY_UNKNOWN,
......
......@@ -29,6 +29,7 @@
struct xattr_list {
struct list_head list;
char *name;
bool enabled;
};
extern int evm_initialized;
......
......@@ -10,6 +10,8 @@
* Using root's kernel master key (kmk), calculate the HMAC
*/
#define pr_fmt(fmt) "EVM: "fmt
#include <linux/export.h>
#include <linux/crypto.h>
#include <linux/xattr.h>
......@@ -175,6 +177,30 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
type != EVM_XATTR_PORTABLE_DIGSIG)
crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
crypto_shash_final(desc, digest);
pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
(int)sizeof(struct h_misc), &hmac_misc);
}
/*
* Dump large security xattr values as a continuous ascii hexademical string.
* (pr_debug is limited to 64 bytes.)
*/
static void dump_security_xattr(const char *prefix, const void *src,
size_t count)
{
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
char *asciihex, *p;
p = asciihex = kmalloc(count * 2 + 1, GFP_KERNEL);
if (!asciihex)
return;
p = bin2hex(p, src, count);
*p = 0;
pr_debug("%s: (%zu) %.*s\n", prefix, count, (int)count * 2, asciihex);
kfree(asciihex);
#endif
}
/*
......@@ -196,7 +222,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
size_t xattr_size = 0;
char *xattr_value = NULL;
int error;
int size;
int size, user_space_size;
bool ima_present = false;
if (!(inode->i_opflags & IOP_XATTR) ||
......@@ -216,6 +242,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;
......@@ -223,6 +256,16 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
req_xattr_value_len);
if (is_ima)
ima_present = true;
if (req_xattr_value_len < 64)
pr_debug("%s: (%zu) [%*phN]\n", req_xattr_name,
req_xattr_value_len,
(int)req_xattr_value_len,
req_xattr_value);
else
dump_security_xattr(req_xattr_name,
req_xattr_value,
req_xattr_value_len);
continue;
}
size = vfs_getxattr_alloc(&init_user_ns, dentry, xattr->name,
......@@ -234,11 +277,24 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (size < 0)
continue;
user_space_size = vfs_getxattr(&init_user_ns, dentry,
xattr->name, NULL, 0);
if (user_space_size != size)
pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
dentry->d_name.name, xattr->name, size,
user_space_size);
error = 0;
xattr_size = size;
crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
if (is_ima)
ima_present = true;
if (xattr_size < 64)
pr_debug("%s: (%zu) [%*phN]", xattr->name, xattr_size,
(int)xattr_size, xattr_value);
else
dump_security_xattr(xattr->name, xattr_value,
xattr_size);
}
hmac_add_misc(desc, inode, type, data->digest);
......
This diff is collapsed.
......@@ -66,12 +66,13 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
static ssize_t evm_write_key(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int i, ret;
unsigned int i;
int ret;
if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP_COMPLETE))
return -EPERM;
ret = kstrtoint_from_user(buf, count, 0, &i);
ret = kstrtouint_from_user(buf, count, 0, &i);
if (ret)
return ret;
......@@ -80,12 +81,12 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
if (!i || (i & ~EVM_INIT_MASK) != 0)
return -EINVAL;
/* Don't allow a request to freshly enable metadata writes if
* keys are loaded.
/*
* Don't allow a request to enable metadata writes if
* an HMAC key is loaded.
*/
if ((i & EVM_ALLOW_METADATA_WRITES) &&
((evm_initialized & EVM_KEY_MASK) != 0) &&
!(evm_initialized & EVM_ALLOW_METADATA_WRITES))
(evm_initialized & EVM_INIT_HMAC) != 0)
return -EPERM;
if (i & EVM_INIT_HMAC) {
......@@ -138,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) {
......@@ -148,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;
}
......@@ -189,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);
......@@ -198,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);
......@@ -244,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;
}
......@@ -255,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);
......
......@@ -208,7 +208,9 @@ int integrity_kernel_read(struct file *file, loff_t offset,
void __init integrity_load_keys(void)
{
ima_load_x509();
evm_load_x509();
if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
evm_load_x509();
}
static int __init integrity_fs_init(void)
......
......@@ -334,3 +334,10 @@ config IMA_SECURE_AND_OR_TRUSTED_BOOT
help
This option is selected by architectures to enable secure and/or
trusted boot based on IMA runtime policies.
config IMA_DISABLE_HTABLE
bool "Disable htable to allow measurement of duplicate records"
depends on IMA
default n
help
This option disables htable to allow measurement of duplicate records.
......@@ -242,12 +242,16 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
hash_start = 1;
fallthrough;
case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) {
*cause = "IMA-signature-required";
*status = INTEGRITY_FAIL;
break;
if (*status != INTEGRITY_PASS_IMMUTABLE) {
if (iint->flags & IMA_DIGSIG_REQUIRED) {
*cause = "IMA-signature-required";
*status = INTEGRITY_FAIL;
break;
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
} else {
set_bit(IMA_DIGSIG, &iint->atomic_flags);
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/*
......@@ -416,6 +420,10 @@ int ima_appraise_measurement(enum ima_hooks func,
case INTEGRITY_NOLABEL: /* No security.evm xattr. */
cause = "missing-HMAC";
goto out;
case INTEGRITY_FAIL_IMMUTABLE:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
cause = "invalid-fail-immutable";
goto out;
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC";
goto out;
......@@ -459,9 +467,12 @@ int ima_appraise_measurement(enum ima_hooks func,
status = INTEGRITY_PASS;
}
/* Permit new files with file signatures, but without data. */
/*
* Permit new files with file/EVM portable signatures, but
* without data.
*/
if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
status = INTEGRITY_PASS;
}
......@@ -522,8 +533,6 @@ void ima_inode_post_setattr(struct user_namespace *mnt_userns,
return;
action = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR);
if (!action)
__vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_IMA);
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
......@@ -570,6 +579,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
const struct evm_ima_xattr_data *xvalue = xattr_value;
int digsig = 0;
int result;
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
......@@ -577,9 +587,14 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (result == 1) {
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL;
ima_reset_appraise_flags(d_backing_inode(dentry),
xvalue->type == EVM_IMA_XATTR_DIGSIG);
result = 0;
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
} else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
}
if (result == 1 || evm_revalidate_status(xattr_name)) {
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
if (result == 1)
result = 0;
}
return result;
}
......@@ -589,9 +604,10 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
int result;
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1) {
if (result == 1 || evm_revalidate_status(xattr_name)) {
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
result = 0;
if (result == 1)
result = 0;
}
return result;
}
......@@ -11,6 +11,7 @@
#include <keys/asymmetric-type.h>
#include <linux/user_namespace.h>
#include <linux/ima.h>
#include "ima.h"
/**
......
......@@ -598,8 +598,8 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data,
u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 };
u8 *data_to_hash = field_data[i].data;
u32 datalen = field_data[i].len;
u32 datalen_to_hash =
!ima_canonical_fmt ? datalen : cpu_to_le32(datalen);
u32 datalen_to_hash = !ima_canonical_fmt ?
datalen : (__force u32)cpu_to_le32(datalen);
if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) {
rc = crypto_shash_update(shash,
......
......@@ -147,7 +147,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
* PCR used defaults to the same (config option) in
* little-endian format, unless set in policy
*/
pcr = !ima_canonical_fmt ? e->pcr : cpu_to_le32(e->pcr);
pcr = !ima_canonical_fmt ? e->pcr : (__force u32)cpu_to_le32(e->pcr);
ima_putc(m, &pcr, sizeof(e->pcr));
/* 2nd: template digest */
......@@ -155,7 +155,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
/* 3rd: template name size */
namelen = !ima_canonical_fmt ? strlen(template_name) :
cpu_to_le32(strlen(template_name));
(__force u32)cpu_to_le32(strlen(template_name));
ima_putc(m, &namelen, sizeof(namelen));
/* 4th: template name */
......@@ -167,7 +167,7 @@ int ima_measurements_show(struct seq_file *m, void *v)
if (!is_ima_template) {
template_data_len = !ima_canonical_fmt ? e->template_data_len :
cpu_to_le32(e->template_data_len);
(__force u32)cpu_to_le32(e->template_data_len);
ima_putc(m, &template_data_len, sizeof(e->template_data_len));
}
......
......@@ -108,6 +108,10 @@ void __init ima_load_x509(void)
ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
/* load also EVM key to avoid appraisal */
evm_load_x509();
ima_policy_flag |= unset_flags;
}
#endif
......
......@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <linux/kexec.h>
#include <linux/of.h>
#include <linux/ima.h>
#include "ima.h"
#ifdef CONFIG_IMA_KEXEC
......
......@@ -433,7 +433,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
&pcr, &template, 0);
&pcr, &template, NULL);
/* Is the mmap'ed file in policy? */
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
......
......@@ -168,7 +168,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
int result = 0, tpmresult = 0;
mutex_lock(&ima_extend_list_mutex);
if (!violation) {
if (!violation && !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
if (ima_lookup_digest_entry(digest, entry->pcr)) {
audit_cause = "hash_exists";
result = -EEXIST;
......@@ -176,7 +176,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
}
}
result = ima_add_digest_entry(entry, 1);
result = ima_add_digest_entry(entry,
!IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE));
if (result < 0) {
audit_cause = "ENOMEM";
audit_info = 0;
......
......@@ -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 */
};
......@@ -45,6 +47,23 @@ static const struct ima_template_field supported_fields[] = {
.field_show = ima_show_template_digest_ng},
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
.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},
};
/*
......@@ -52,7 +71,8 @@ static const struct ima_template_field supported_fields[] = {
* 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;
......@@ -403,9 +423,9 @@ int ima_restore_measurement_list(loff_t size, void *buf)
return 0;
if (ima_canonical_fmt) {
khdr->version = le16_to_cpu(khdr->version);
khdr->count = le64_to_cpu(khdr->count);
khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
khdr->version = le16_to_cpu((__force __le16)khdr->version);
khdr->count = le64_to_cpu((__force __le64)khdr->count);
khdr->buffer_size = le64_to_cpu((__force __le64)khdr->buffer_size);
}
if (khdr->version != 1) {
......@@ -495,7 +515,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
}
entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :
le32_to_cpu(*(u32 *)(hdr[HDR_PCR].data));
le32_to_cpu(*(__le32 *)(hdr[HDR_PCR].data));
ret = ima_restore_measurement_entry(entry);
if (ret < 0)
break;
......
......@@ -10,6 +10,8 @@
*/
#include "ima_template_lib.h"
#include <linux/xattr.h>
#include <linux/evm.h>
static bool ima_template_hash_algo_allowed(u8 algo)
{
......@@ -23,7 +25,8 @@ enum data_formats {
DATA_FMT_DIGEST = 0,
DATA_FMT_DIGEST_WITH_ALGO,
DATA_FMT_STRING,
DATA_FMT_HEX
DATA_FMT_HEX,
DATA_FMT_UINT
};
static int ima_write_template_field_data(const void *data, const u32 datalen,
......@@ -87,6 +90,36 @@ static void ima_show_template_data_ascii(struct seq_file *m,
case DATA_FMT_STRING:
seq_printf(m, "%s", buf_ptr);
break;
case DATA_FMT_UINT:
switch (field_data->len) {
case sizeof(u8):
seq_printf(m, "%u", *(u8 *)buf_ptr);
break;
case sizeof(u16):
if (ima_canonical_fmt)
seq_printf(m, "%u",
le16_to_cpu(*(__le16 *)buf_ptr));
else
seq_printf(m, "%u", *(u16 *)buf_ptr);
break;
case sizeof(u32):
if (ima_canonical_fmt)
seq_printf(m, "%u",
le32_to_cpu(*(__le32 *)buf_ptr));
else
seq_printf(m, "%u", *(u32 *)buf_ptr);
break;
case sizeof(u64):
if (ima_canonical_fmt)
seq_printf(m, "%llu",
le64_to_cpu(*(__le64 *)buf_ptr));
else
seq_printf(m, "%llu", *(u64 *)buf_ptr);
break;
default:
break;
}
break;
default:
break;
}
......@@ -101,7 +134,8 @@ static void ima_show_template_data_binary(struct seq_file *m,
strlen(field_data->data) : field_data->len;
if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
u32 field_len = !ima_canonical_fmt ? len : cpu_to_le32(len);
u32 field_len = !ima_canonical_fmt ?
len : (__force u32)cpu_to_le32(len);
ima_putc(m, &field_len, sizeof(field_len));
}
......@@ -162,6 +196,12 @@ void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
}
void ima_show_template_uint(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data)
{
ima_show_template_field_data(m, show, DATA_FMT_UINT, field_data);
}
/**
* ima_parse_buf() - Parses lengths and data from an input buffer
* @bufstartp: Buffer start address.
......@@ -188,9 +228,10 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
if (bufp > (bufendp - sizeof(u32)))
break;
fields[i].len = *(u32 *)bufp;
if (ima_canonical_fmt)
fields[i].len = le32_to_cpu(fields[i].len);
fields[i].len = le32_to_cpu(*(__le32 *)bufp);
else
fields[i].len = *(u32 *)bufp;
bufp += sizeof(u32);
}
......@@ -438,7 +479,7 @@ int ima_eventsig_init(struct ima_event_data *event_data,
struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
return 0;
return ima_eventevmsig_init(event_data, field_data);
return ima_write_template_field_data(xattr_value, event_data->xattr_len,
DATA_FMT_HEX, field_data);
......@@ -484,3 +525,163 @@ int ima_eventmodsig_init(struct ima_event_data *event_data,
return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
field_data);
}
/*
* ima_eventevmsig_init - include the EVM portable signature as part of the
* template data
*/
int ima_eventevmsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
struct evm_ima_xattr_data *xattr_data = NULL;
int rc = 0;
if (!event_data->file)
return 0;
rc = vfs_getxattr_alloc(&init_user_ns, file_dentry(event_data->file),
XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
if (rc <= 0)
return 0;
if (xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
kfree(xattr_data);
return 0;
}
rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
field_data);
kfree(xattr_data);
return rc;
}
static int ima_eventinodedac_init_common(struct ima_event_data *event_data,
struct ima_field_data *field_data,
bool get_uid)
{
unsigned int id;
if (!event_data->file)
return 0;
if (get_uid)
id = i_uid_read(file_inode(event_data->file));
else
id = i_gid_read(file_inode(event_data->file));
if (ima_canonical_fmt) {
if (sizeof(id) == sizeof(u16))
id = (__force u16)cpu_to_le16(id);
else
id = (__force u32)cpu_to_le32(id);
}
return ima_write_template_field_data((void *)&id, sizeof(id),
DATA_FMT_UINT, field_data);
}
/*
* ima_eventinodeuid_init - include the inode UID as part of the template
* data
*/
int ima_eventinodeuid_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
return ima_eventinodedac_init_common(event_data, field_data, true);
}
/*
* ima_eventinodegid_init - include the inode GID as part of the template
* data
*/
int ima_eventinodegid_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
return ima_eventinodedac_init_common(event_data, field_data, false);
}
/*
* ima_eventinodemode_init - include the inode mode as part of the template
* data
*/
int ima_eventinodemode_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
struct inode *inode;
u16 mode;
if (!event_data->file)
return 0;
inode = file_inode(event_data->file);
mode = inode->i_mode;
if (ima_canonical_fmt)
mode = (__force u16)cpu_to_le16(mode);
return ima_write_template_field_data((char *)&mode, sizeof(mode),
DATA_FMT_UINT, field_data);
}
static int ima_eventinodexattrs_init_common(struct ima_event_data *event_data,
struct ima_field_data *field_data,
char type)
{
u8 *buffer = NULL;
int rc;
if (!event_data->file)
return 0;
rc = evm_read_protected_xattrs(file_dentry(event_data->file), NULL, 0,
type, ima_canonical_fmt);
if (rc < 0)
return 0;
buffer = kmalloc(rc, GFP_KERNEL);
if (!buffer)
return 0;
rc = evm_read_protected_xattrs(file_dentry(event_data->file), buffer,
rc, type, ima_canonical_fmt);
if (rc < 0) {
rc = 0;
goto out;
}
rc = ima_write_template_field_data((char *)buffer, rc, DATA_FMT_HEX,
field_data);
out:
kfree(buffer);
return rc;
}
/*
* ima_eventinodexattrnames_init - include a list of xattr names as part of the
* template data
*/
int ima_eventinodexattrnames_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
return ima_eventinodexattrs_init_common(event_data, field_data, 'n');
}
/*
* ima_eventinodexattrlengths_init - include a list of xattr lengths as part of
* the template data
*/
int ima_eventinodexattrlengths_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
return ima_eventinodexattrs_init_common(event_data, field_data, 'l');
}
/*
* ima_eventinodexattrvalues_init - include a list of xattr values as part of
* the template data
*/
int ima_eventinodexattrvalues_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
return ima_eventinodexattrs_init_common(event_data, field_data, 'v');
}
......@@ -27,6 +27,8 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_uint(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
int maxfields, struct ima_field_data *fields, int *curfields,
unsigned long *len_mask, int enforce_mask, char *bufname);
......@@ -46,4 +48,18 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventmodsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventevmsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodeuid_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodegid_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodemode_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodexattrnames_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodexattrlengths_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventinodexattrvalues_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
......@@ -1354,7 +1354,7 @@ int security_inode_setxattr(struct user_namespace *mnt_userns,
ret = ima_inode_setxattr(dentry, name, value, size);
if (ret)
return ret;
return evm_inode_setxattr(dentry, name, value, size);
return evm_inode_setxattr(mnt_userns, dentry, name, value, size);
}
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
......@@ -1399,7 +1399,7 @@ int security_inode_removexattr(struct user_namespace *mnt_userns,
ret = ima_inode_removexattr(dentry, name);
if (ret)
return ret;
return evm_inode_removexattr(dentry, name);
return evm_inode_removexattr(mnt_userns, dentry, name);
}
int security_inode_need_killpriv(struct dentry *dentry)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment