Skip to content

Commit 88b4cbc

Browse files
coibymimizohar
authored andcommitted
ima: don't clear IMA_DIGSIG flag when setting or removing non-IMA xattr
Currently when both IMA and EVM are in fix mode, the IMA signature will be reset to IMA hash if a program first stores IMA signature in security.ima and then writes/removes some other security xattr for the file. For example, on Fedora, after booting the kernel with "ima_appraise=fix evm=fix ima_policy=appraise_tcb" and installing rpm-plugin-ima, installing/reinstalling a package will not make good reference IMA signature generated. Instead IMA hash is generated, # getfattr -m - -d -e hex /usr/bin/bash # file: usr/bin/bash security.ima=0x0404... This happens because when setting security.selinux, the IMA_DIGSIG flag that had been set early was cleared. As a result, IMA hash is generated when the file is closed. Similarly, IMA signature can be cleared on file close after removing security xattr like security.evm or setting/removing ACL. Prevent replacing the IMA file signature with a file hash, by preventing the IMA_DIGSIG flag from being reset. Here's a minimal C reproducer which sets security.selinux as the last step which can also replaced by removing security.evm or setting ACL, #include <stdio.h> #include <sys/xattr.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdlib.h> int main() { const char* file_path = "/usr/sbin/test_binary"; const char* hex_string = "030204d33204490066306402304"; int length = strlen(hex_string); char* ima_attr_value; int fd; fd = open(file_path, O_WRONLY|O_CREAT|O_EXCL, 0644); if (fd == -1) { perror("Error opening file"); return 1; } ima_attr_value = (char*)malloc(length / 2 ); for (int i = 0, j = 0; i < length; i += 2, j++) { sscanf(hex_string + i, "%2hhx", &ima_attr_value[j]); } if (fsetxattr(fd, "security.ima", ima_attr_value, length/2, 0) == -1) { perror("Error setting extended attribute"); close(fd); return 1; } const char* selinux_value= "system_u:object_r:bin_t:s0"; if (fsetxattr(fd, "security.selinux", selinux_value, strlen(selinux_value), 0) == -1) { perror("Error setting extended attribute"); close(fd); return 1; } close(fd); return 0; } Signed-off-by: Coiby Xu <[email protected]> Signed-off-by: Mimi Zohar <[email protected]>
1 parent 191cac3 commit 88b4cbc

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

security/integrity/ima/ima_appraise.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,15 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
694694
return 0;
695695
}
696696

697+
/*
698+
* ima_reset_appraise_flags - reset ima_iint_cache flags
699+
*
700+
* @digsig: whether to clear/set IMA_DIGSIG flag, tristate values
701+
* 0: clear IMA_DIGSIG
702+
* 1: set IMA_DIGSIG
703+
* -1: don't change IMA_DIGSIG
704+
*
705+
*/
697706
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
698707
{
699708
struct ima_iint_cache *iint;
@@ -706,9 +715,9 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
706715
return;
707716
iint->measured_pcrs = 0;
708717
set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
709-
if (digsig)
718+
if (digsig == 1)
710719
set_bit(IMA_DIGSIG, &iint->atomic_flags);
711-
else
720+
else if (digsig == 0)
712721
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
713722
}
714723

@@ -794,6 +803,8 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
794803
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
795804
} else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
796805
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
806+
} else {
807+
digsig = -1;
797808
}
798809
if (result == 1 || evm_revalidate_status(xattr_name)) {
799810
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
@@ -807,19 +818,21 @@ static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
807818
const char *acl_name, struct posix_acl *kacl)
808819
{
809820
if (evm_revalidate_status(acl_name))
810-
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
821+
ima_reset_appraise_flags(d_backing_inode(dentry), -1);
811822

812823
return 0;
813824
}
814825

815826
static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
816827
const char *xattr_name)
817828
{
818-
int result;
829+
int result, digsig = -1;
819830

820831
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
821832
if (result == 1 || evm_revalidate_status(xattr_name)) {
822-
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
833+
if (!strcmp(xattr_name, XATTR_NAME_IMA))
834+
digsig = 0;
835+
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
823836
if (result == 1)
824837
result = 0;
825838
}

0 commit comments

Comments
 (0)