integrity-v5.14
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEjSMCCC7+cjo3nszSa3kkZrA+cVoFAmDY+ykUHHpvaGFyQGxp bnV4LmlibS5jb20ACgkQa3kkZrA+cVoEpg/+LalOM88YDTFNSpAlzEr31pyDU30p xB9xMyN7lgJcsuGeKWyt+gjEoTR53+JQeaGHgTo8uG4pCto7wBIAOttwkHV5O0Re QUQC++nc6jqgn2tRi/V+UV0plgJMV0Xt4ucGS+gH8hujvih4vQ+X3RFJasAy1ZWS 1aWOev8wLkwfwU5YsOX+7OZE0qgH4QCh+i6SF402dpMUV1n/2hbFjcV1qOtvgDfS 7KHJYZfTV5yPfk0i5nSpwsfctthQJ5+ADdGBIwp03iH6amBZ3pvAwvbPGxE9TM4M teVIOU0BwMj5LiVvlXApbpA0k8N3e0TU+Rqgyr7hQHOYBBOxye+eZlV5SjHhfeuf n9jCuHGEIzeQNicR+R2PHqnAC/1HEeyb4V/2+vGfIXM593CzqoMD5ITL+PLi5bA3 5ONeLW1n2Tsi85xbUO9dH5wvgAd9HaHGRcxCOr3nT6qbwiCiKiEpkiArGNgTrsR3 22OGji9d6WR6maMpRdCIlFZCAoOmMjNMftV3CaAIHCkysHmV7hYh3/hNbk9Syg5+ 7y6fFxiyTjhKA3WOAcnTXlOIuVGYmFknmla66Z80XzZ3dHUlElOt4sXJfKekRmZz i/jECFcCuCOgfZTxzZ1FUIRJ+lumlq5J8mu0kWtbEyamjgXWl4Ustx6ae86tg6al uhQULzRTISHQG3M= =M7c5 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
a60c538ed2
@ -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);
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
* evm_inode_removexattr, and evm_verifyxattr
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "EVM: "fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/audit.h>
|
||||
@ -18,6 +20,7 @@
|
||||
#include <linux/integrity.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/hash_info.h>
|
||||
@ -27,29 +30,50 @@
|
||||
int evm_initialized;
|
||||
|
||||
static const char * const integrity_status_msg[] = {
|
||||
"pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
|
||||
"pass", "pass_immutable", "fail", "fail_immutable", "no_label",
|
||||
"no_xattrs", "unknown"
|
||||
};
|
||||
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);
|
||||
@ -74,7 +98,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);
|
||||
}
|
||||
@ -90,6 +116,24 @@ static bool evm_key_loaded(void)
|
||||
return (bool)(evm_initialized & EVM_KEY_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function determines whether or not it is safe to ignore verification
|
||||
* errors, based on the ability of EVM to calculate HMACs. If the HMAC key
|
||||
* is not loaded, and it cannot be loaded in the future due to the
|
||||
* EVM_SETUP_COMPLETE initialization flag, allowing an operation despite the
|
||||
* attrs/xattrs being found invalid will not make them valid.
|
||||
*/
|
||||
static bool evm_hmac_disabled(void)
|
||||
{
|
||||
if (evm_initialized & EVM_INIT_HMAC)
|
||||
return false;
|
||||
|
||||
if (!(evm_initialized & EVM_SETUP_COMPLETE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int evm_find_protected_xattrs(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
@ -137,7 +181,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
enum integrity_status evm_status = INTEGRITY_PASS;
|
||||
struct evm_digest digest;
|
||||
struct inode *inode;
|
||||
int rc, xattr_len;
|
||||
int rc, xattr_len, evm_immutable = 0;
|
||||
|
||||
if (iint && (iint->evm_status == INTEGRITY_PASS ||
|
||||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
|
||||
@ -182,8 +226,10 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
if (rc)
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
case EVM_XATTR_PORTABLE_DIGSIG:
|
||||
evm_immutable = 1;
|
||||
fallthrough;
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
/* accept xattr with non-empty signature field */
|
||||
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
|
||||
evm_status = INTEGRITY_FAIL;
|
||||
@ -220,9 +266,16 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
evm_status = (rc == -ENODATA) ?
|
||||
INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
|
||||
if (rc) {
|
||||
if (rc == -ENODATA)
|
||||
evm_status = INTEGRITY_NOXATTRS;
|
||||
else if (evm_immutable)
|
||||
evm_status = INTEGRITY_FAIL_IMMUTABLE;
|
||||
else
|
||||
evm_status = INTEGRITY_FAIL;
|
||||
}
|
||||
pr_debug("digest: (%d) [%*phN]\n", digest.hdr.length, digest.hdr.length,
|
||||
digest.digest);
|
||||
out:
|
||||
if (iint)
|
||||
iint->evm_status = evm_status;
|
||||
@ -230,7 +283,8 @@ out:
|
||||
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;
|
||||
@ -238,6 +292,9 @@ static int evm_protected_xattr(const char *req_xattr_name)
|
||||
|
||||
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;
|
||||
@ -254,6 +311,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 = (__force int)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
|
||||
@ -304,6 +440,92 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
|
||||
return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* evm_xattr_acl_change - check if passed ACL changes the inode mode
|
||||
* @mnt_userns: user namespace of the idmapped mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @xattr_name: requested xattr
|
||||
* @xattr_value: requested xattr value
|
||||
* @xattr_value_len: requested xattr value length
|
||||
*
|
||||
* Check if passed ACL changes the inode mode, which is protected by EVM.
|
||||
*
|
||||
* Returns 1 if passed ACL causes inode mode change, 0 otherwise.
|
||||
*/
|
||||
static int evm_xattr_acl_change(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
umode_t mode;
|
||||
struct posix_acl *acl = NULL, *acl_res;
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* user_ns is not relevant here, ACL_USER/ACL_GROUP don't have impact
|
||||
* on the inode mode (see posix_acl_equiv_mode()).
|
||||
*/
|
||||
acl = posix_acl_from_xattr(&init_user_ns, xattr_value, xattr_value_len);
|
||||
if (IS_ERR_OR_NULL(acl))
|
||||
return 1;
|
||||
|
||||
acl_res = acl;
|
||||
/*
|
||||
* Passing mnt_userns is necessary to correctly determine the GID in
|
||||
* an idmapped mount, as the GID is used to clear the setgid bit in
|
||||
* the inode mode.
|
||||
*/
|
||||
rc = posix_acl_update_mode(mnt_userns, inode, &mode, &acl_res);
|
||||
|
||||
posix_acl_release(acl);
|
||||
|
||||
if (rc)
|
||||
return 1;
|
||||
|
||||
if (inode->i_mode != mode)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* evm_xattr_change - check if passed xattr value differs from current value
|
||||
* @mnt_userns: user namespace of the idmapped mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @xattr_name: requested xattr
|
||||
* @xattr_value: requested xattr value
|
||||
* @xattr_value_len: requested xattr value length
|
||||
*
|
||||
* Check if passed xattr value differs from current value.
|
||||
*
|
||||
* Returns 1 if passed xattr value differs from current value, 0 otherwise.
|
||||
*/
|
||||
static int evm_xattr_change(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
char *xattr_data = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (posix_xattr_acl(xattr_name))
|
||||
return evm_xattr_acl_change(mnt_userns, dentry, xattr_name,
|
||||
xattr_value, xattr_value_len);
|
||||
|
||||
rc = vfs_getxattr_alloc(&init_user_ns, dentry, xattr_name, &xattr_data,
|
||||
0, GFP_NOFS);
|
||||
if (rc < 0)
|
||||
return 1;
|
||||
|
||||
if (rc == xattr_value_len)
|
||||
rc = !!memcmp(xattr_value, xattr_data, rc);
|
||||
else
|
||||
rc = 1;
|
||||
|
||||
kfree(xattr_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* evm_protect_xattr - protect the EVM extended attribute
|
||||
*
|
||||
@ -316,7 +538,8 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
|
||||
* For posix xattr acls only, permit security.evm, even if it currently
|
||||
* doesn't exist, to be updated unless the EVM signature is immutable.
|
||||
*/
|
||||
static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||||
static int evm_protect_xattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
enum integrity_status evm_status;
|
||||
@ -338,6 +561,10 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||||
if (evm_status == INTEGRITY_NOXATTRS) {
|
||||
struct integrity_iint_cache *iint;
|
||||
|
||||
/* Exception if the HMAC is not going to be calculated. */
|
||||
if (evm_hmac_disabled())
|
||||
return 0;
|
||||
|
||||
iint = integrity_iint_find(d_backing_inode(dentry));
|
||||
if (iint && (iint->flags & IMA_NEW_FILE))
|
||||
return 0;
|
||||
@ -354,7 +581,25 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||||
-EPERM, 0);
|
||||
}
|
||||
out:
|
||||
if (evm_status != INTEGRITY_PASS)
|
||||
/* Exception if the HMAC is not going to be calculated. */
|
||||
if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
|
||||
evm_status == INTEGRITY_UNKNOWN))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Writing other xattrs is safe for portable signatures, as portable
|
||||
* signatures are immutable and can never be updated.
|
||||
*/
|
||||
if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
|
||||
return 0;
|
||||
|
||||
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
|
||||
!evm_xattr_change(mnt_userns, dentry, xattr_name, xattr_value,
|
||||
xattr_value_len))
|
||||
return 0;
|
||||
|
||||
if (evm_status != INTEGRITY_PASS &&
|
||||
evm_status != INTEGRITY_PASS_IMMUTABLE)
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
|
||||
dentry->d_name.name, "appraise_metadata",
|
||||
integrity_status_msg[evm_status],
|
||||
@ -364,6 +609,7 @@ out:
|
||||
|
||||
/**
|
||||
* evm_inode_setxattr - protect the EVM extended attribute
|
||||
* @mnt_userns: user namespace of the idmapped mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
* @xattr_value: pointer to the new extended attribute value
|
||||
@ -375,8 +621,9 @@ out:
|
||||
* userspace from writing HMAC value. Writing 'security.evm' requires
|
||||
* requires CAP_SYS_ADMIN privileges.
|
||||
*/
|
||||
int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
int evm_inode_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
const char *xattr_name, const void *xattr_value,
|
||||
size_t xattr_value_len)
|
||||
{
|
||||
const struct evm_ima_xattr_data *xattr_data = xattr_value;
|
||||
|
||||
@ -393,19 +640,21 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG)
|
||||
return -EPERM;
|
||||
}
|
||||
return evm_protect_xattr(dentry, xattr_name, xattr_value,
|
||||
return evm_protect_xattr(mnt_userns, dentry, xattr_name, xattr_value,
|
||||
xattr_value_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_removexattr - protect the EVM extended attribute
|
||||
* @mnt_userns: user namespace of the idmapped mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
*
|
||||
* Removing 'security.evm' requires CAP_SYS_ADMIN privileges and that
|
||||
* the current value is valid.
|
||||
*/
|
||||
int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
int evm_inode_removexattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *xattr_name)
|
||||
{
|
||||
/* Policy permits modification of the protected xattrs even though
|
||||
* there's no HMAC key loaded
|
||||
@ -413,7 +662,7 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
|
||||
return 0;
|
||||
|
||||
return evm_protect_xattr(dentry, xattr_name, NULL, 0);
|
||||
return evm_protect_xattr(mnt_userns, dentry, xattr_name, NULL, 0);
|
||||
}
|
||||
|
||||
static void evm_reset_status(struct inode *inode)
|
||||
@ -425,6 +674,31 @@ static void evm_reset_status(struct inode *inode)
|
||||
iint->evm_status = INTEGRITY_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_revalidate_status - report whether EVM status re-validation is necessary
|
||||
* @xattr_name: pointer to the affected extended attribute name
|
||||
*
|
||||
* Report whether callers of evm_verifyxattr() should re-validate the
|
||||
* EVM status.
|
||||
*
|
||||
* Return true if re-validation is necessary, false otherwise.
|
||||
*/
|
||||
bool evm_revalidate_status(const char *xattr_name)
|
||||
{
|
||||
if (!evm_key_loaded())
|
||||
return false;
|
||||
|
||||
/* evm_inode_post_setattr() passes NULL */
|
||||
if (!xattr_name)
|
||||
return true;
|
||||
|
||||
if (!evm_protected_xattr(xattr_name) && !posix_xattr_acl(xattr_name) &&
|
||||
strcmp(xattr_name, XATTR_NAME_EVM))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
|
||||
* @dentry: pointer to the affected dentry
|
||||
@ -441,12 +715,17 @@ static void evm_reset_status(struct inode *inode)
|
||||
void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
const void *xattr_value, size_t xattr_value_len)
|
||||
{
|
||||
if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name)
|
||||
&& !posix_xattr_acl(xattr_name)))
|
||||
if (!evm_revalidate_status(xattr_name))
|
||||
return;
|
||||
|
||||
evm_reset_status(dentry->d_inode);
|
||||
|
||||
if (!strcmp(xattr_name, XATTR_NAME_EVM))
|
||||
return;
|
||||
|
||||
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||
return;
|
||||
|
||||
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
|
||||
}
|
||||
|
||||
@ -462,14 +741,33 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
|
||||
*/
|
||||
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
|
||||
{
|
||||
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
|
||||
if (!evm_revalidate_status(xattr_name))
|
||||
return;
|
||||
|
||||
evm_reset_status(dentry->d_inode);
|
||||
|
||||
if (!strcmp(xattr_name, XATTR_NAME_EVM))
|
||||
return;
|
||||
|
||||
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||
return;
|
||||
|
||||
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
|
||||
}
|
||||
|
||||
static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) &&
|
||||
(!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) &&
|
||||
(!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
|
||||
* @dentry: pointer to the affected dentry
|
||||
@ -491,9 +789,21 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
|
||||
return 0;
|
||||
evm_status = evm_verify_current_integrity(dentry);
|
||||
/*
|
||||
* Writing attrs is safe for portable signatures, as portable signatures
|
||||
* are immutable and can never be updated.
|
||||
*/
|
||||
if ((evm_status == INTEGRITY_PASS) ||
|
||||
(evm_status == INTEGRITY_NOXATTRS))
|
||||
(evm_status == INTEGRITY_NOXATTRS) ||
|
||||
(evm_status == INTEGRITY_FAIL_IMMUTABLE) ||
|
||||
(evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
|
||||
evm_status == INTEGRITY_UNKNOWN)))
|
||||
return 0;
|
||||
|
||||
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
|
||||
!evm_attr_change(dentry, attr))
|
||||
return 0;
|
||||
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
|
||||
dentry->d_name.name, "appraise_metadata",
|
||||
integrity_status_msg[evm_status], -EPERM, 0);
|
||||
@ -513,7 +823,12 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
*/
|
||||
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
|
||||
{
|
||||
if (!evm_key_loaded())
|
||||
if (!evm_revalidate_status(NULL))
|
||||
return;
|
||||
|
||||
evm_reset_status(dentry->d_inode);
|
||||
|
||||
if (!(evm_initialized & EVM_INIT_HMAC))
|
||||
return;
|
||||
|
||||
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
|
||||
@ -521,7 +836,7 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
|
||||
}
|
||||
|
||||
/*
|
||||
* evm_inode_init_security - initializes security.evm
|
||||
* evm_inode_init_security - initializes security.evm HMAC value
|
||||
*/
|
||||
int evm_inode_init_security(struct inode *inode,
|
||||
const struct xattr *lsm_xattr,
|
||||
@ -530,7 +845,8 @@ int evm_inode_init_security(struct inode *inode,
|
||||
struct evm_xattr *xattr_data;
|
||||
int rc;
|
||||
|
||||
if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
|
||||
if (!(evm_initialized & EVM_INIT_HMAC) ||
|
||||
!evm_protected_xattr(lsm_xattr->name))
|
||||
return 0;
|
||||
|
||||
xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
|
||||
|
@ -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 @@ out:
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user