Skip to content

Commit e3ccfe1

Browse files
robertosassumimizohar
authored andcommitted
evm: Introduce evm_revalidate_status()
When EVM_ALLOW_METADATA_WRITES is set, EVM allows any operation on metadata. Its main purpose is to allow users to freely set metadata when it is protected by a portable signature, until an HMAC key is loaded. However, callers of evm_verifyxattr() are not notified about metadata changes and continue to rely on the last status returned by the function. For example IMA, since it caches the appraisal result, will not call again evm_verifyxattr() until the appraisal flags are cleared, and will grant access to the file even if there was a metadata operation that made the portable signature invalid. This patch introduces evm_revalidate_status(), which callers of evm_verifyxattr() can use in their xattr hooks to determine whether re-validation is necessary and to do the proper actions. IMA calls it in its xattr hooks to reset the appraisal flags, so that the EVM status is re-evaluated after a metadata operation. Lastly, this patch also adds a call to evm_reset_status() in evm_inode_post_setattr() to invalidate the cached EVM status after a setattr operation. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
1 parent 9acc89d commit e3ccfe1

3 files changed

Lines changed: 52 additions & 9 deletions

File tree

include/linux/evm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extern void evm_inode_post_removexattr(struct dentry *dentry,
3535
extern int evm_inode_init_security(struct inode *inode,
3636
const struct xattr *xattr_array,
3737
struct xattr *evm);
38+
extern bool evm_revalidate_status(const char *xattr_name);
3839
#ifdef CONFIG_FS_POSIX_ACL
3940
extern int posix_xattr_acl(const char *xattrname);
4041
#else
@@ -104,5 +105,10 @@ static inline int evm_inode_init_security(struct inode *inode,
104105
return 0;
105106
}
106107

108+
static inline bool evm_revalidate_status(const char *xattr_name)
109+
{
110+
return false;
111+
}
112+
107113
#endif /* CONFIG_EVM */
108114
#endif /* LINUX_EVM_H */

security/integrity/evm/evm_main.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,31 @@ static void evm_reset_status(struct inode *inode)
425425
iint->evm_status = INTEGRITY_UNKNOWN;
426426
}
427427

428+
/**
429+
* evm_revalidate_status - report whether EVM status re-validation is necessary
430+
* @xattr_name: pointer to the affected extended attribute name
431+
*
432+
* Report whether callers of evm_verifyxattr() should re-validate the
433+
* EVM status.
434+
*
435+
* Return true if re-validation is necessary, false otherwise.
436+
*/
437+
bool evm_revalidate_status(const char *xattr_name)
438+
{
439+
if (!evm_key_loaded())
440+
return false;
441+
442+
/* evm_inode_post_setattr() passes NULL */
443+
if (!xattr_name)
444+
return true;
445+
446+
if (!evm_protected_xattr(xattr_name) && !posix_xattr_acl(xattr_name) &&
447+
strcmp(xattr_name, XATTR_NAME_EVM))
448+
return false;
449+
450+
return true;
451+
}
452+
428453
/**
429454
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
430455
* @dentry: pointer to the affected dentry
@@ -441,12 +466,14 @@ static void evm_reset_status(struct inode *inode)
441466
void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
442467
const void *xattr_value, size_t xattr_value_len)
443468
{
444-
if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name)
445-
&& !posix_xattr_acl(xattr_name)))
469+
if (!evm_revalidate_status(xattr_name))
446470
return;
447471

448472
evm_reset_status(dentry->d_inode);
449473

474+
if (!strcmp(xattr_name, XATTR_NAME_EVM))
475+
return;
476+
450477
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
451478
}
452479

@@ -462,11 +489,14 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
462489
*/
463490
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
464491
{
465-
if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))
492+
if (!evm_revalidate_status(xattr_name))
466493
return;
467494

468495
evm_reset_status(dentry->d_inode);
469496

497+
if (!strcmp(xattr_name, XATTR_NAME_EVM))
498+
return;
499+
470500
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
471501
}
472502

@@ -513,9 +543,11 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
513543
*/
514544
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
515545
{
516-
if (!evm_key_loaded())
546+
if (!evm_revalidate_status(NULL))
517547
return;
518548

549+
evm_reset_status(dentry->d_inode);
550+
519551
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
520552
evm_update_evmxattr(dentry, NULL, NULL, 0);
521553
}

security/integrity/ima/ima_appraise.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,16 +570,20 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
570570
const void *xattr_value, size_t xattr_value_len)
571571
{
572572
const struct evm_ima_xattr_data *xvalue = xattr_value;
573+
int digsig = 0;
573574
int result;
574575

575576
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
576577
xattr_value_len);
577578
if (result == 1) {
578579
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
579580
return -EINVAL;
580-
ima_reset_appraise_flags(d_backing_inode(dentry),
581-
xvalue->type == EVM_IMA_XATTR_DIGSIG);
582-
result = 0;
581+
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
582+
}
583+
if (result == 1 || evm_revalidate_status(xattr_name)) {
584+
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
585+
if (result == 1)
586+
result = 0;
583587
}
584588
return result;
585589
}
@@ -589,9 +593,10 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
589593
int result;
590594

591595
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
592-
if (result == 1) {
596+
if (result == 1 || evm_revalidate_status(xattr_name)) {
593597
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
594-
result = 0;
598+
if (result == 1)
599+
result = 0;
595600
}
596601
return result;
597602
}

0 commit comments

Comments
 (0)