Merge branch 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security
Pull more security layer updates from Serge Hallyn: "A few more commits had previously failed to make it through security-next into linux-next but this week made it into linux-next. At least commit "ima: introduce ima_kernel_read()" was deemed critical by Mimi to make this merge window. This is a temporary tree just for this request. Mimi has pointed me to some previous threads about keeping maintainer trees at the previous release, which I'll certainly do for anything long-term, after talking with James" * 'serge-next-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sergeh/linux-security: ima: introduce ima_kernel_read() evm: prohibit userspace writing 'security.evm' HMAC value ima: check inode integrity cache in violation check ima: prevent unnecessary policy checking evm: provide option to protect additional SMACK xattrs evm: replace HMAC version with attribute mask ima: prevent new digsig xattr from being replaced
This commit is contained in:
commit
aa569fa0ea
7 changed files with 116 additions and 30 deletions
|
@ -12,15 +12,41 @@ config EVM
|
|||
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
config EVM_HMAC_VERSION
|
||||
int "EVM HMAC version"
|
||||
depends on EVM
|
||||
default 2
|
||||
help
|
||||
This options adds EVM HMAC version support.
|
||||
1 - original version
|
||||
2 - add per filesystem unique identifier (UUID) (default)
|
||||
if EVM
|
||||
|
||||
WARNING: changing the HMAC calculation method or adding
|
||||
menu "EVM options"
|
||||
|
||||
config EVM_ATTR_FSUUID
|
||||
bool "FSUUID (version 2)"
|
||||
default y
|
||||
depends on EVM
|
||||
help
|
||||
Include filesystem UUID for HMAC calculation.
|
||||
|
||||
Default value is 'selected', which is former version 2.
|
||||
if 'not selected', it is former version 1
|
||||
|
||||
WARNING: changing the HMAC calculation method or adding
|
||||
additional info to the calculation, requires existing EVM
|
||||
labeled file systems to be relabeled.
|
||||
labeled file systems to be relabeled.
|
||||
|
||||
config EVM_EXTRA_SMACK_XATTRS
|
||||
bool "Additional SMACK xattrs"
|
||||
depends on EVM && SECURITY_SMACK
|
||||
default n
|
||||
help
|
||||
Include additional SMACK xattrs for HMAC calculation.
|
||||
|
||||
In addition to the original security xattrs (eg. security.selinux,
|
||||
security.SMACK64, security.capability, and security.ima) included
|
||||
in the HMAC calculation, enabling this option includes newly defined
|
||||
Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and
|
||||
security.SMACK64MMAP.
|
||||
|
||||
WARNING: changing the HMAC calculation method or adding
|
||||
additional info to the calculation, requires existing EVM
|
||||
labeled file systems to be relabeled.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
extern int evm_initialized;
|
||||
extern char *evm_hmac;
|
||||
extern char *evm_hash;
|
||||
extern int evm_hmac_version;
|
||||
|
||||
#define EVM_ATTR_FSUUID 0x0001
|
||||
|
||||
extern int evm_hmac_attrs;
|
||||
|
||||
extern struct crypto_shash *hmac_tfm;
|
||||
extern struct crypto_shash *hash_tfm;
|
||||
|
|
|
@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
|
|||
hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
|
||||
hmac_misc.mode = inode->i_mode;
|
||||
crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
|
||||
if (evm_hmac_version > 1)
|
||||
if (evm_hmac_attrs & EVM_ATTR_FSUUID)
|
||||
crypto_shash_update(desc, inode->i_sb->s_uuid,
|
||||
sizeof(inode->i_sb->s_uuid));
|
||||
crypto_shash_final(desc, digest);
|
||||
|
|
|
@ -32,7 +32,7 @@ static char *integrity_status_msg[] = {
|
|||
};
|
||||
char *evm_hmac = "hmac(sha1)";
|
||||
char *evm_hash = "sha1";
|
||||
int evm_hmac_version = CONFIG_EVM_HMAC_VERSION;
|
||||
int evm_hmac_attrs;
|
||||
|
||||
char *evm_config_xattrnames[] = {
|
||||
#ifdef CONFIG_SECURITY_SELINUX
|
||||
|
@ -40,6 +40,11 @@ char *evm_config_xattrnames[] = {
|
|||
#endif
|
||||
#ifdef CONFIG_SECURITY_SMACK
|
||||
XATTR_NAME_SMACK,
|
||||
#ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS
|
||||
XATTR_NAME_SMACKEXEC,
|
||||
XATTR_NAME_SMACKTRANSMUTE,
|
||||
XATTR_NAME_SMACKMMAP,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_IMA_APPRAISE
|
||||
XATTR_NAME_IMA,
|
||||
|
@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str)
|
|||
}
|
||||
__setup("evm=", evm_set_fixmode);
|
||||
|
||||
static void __init evm_init_config(void)
|
||||
{
|
||||
#ifdef CONFIG_EVM_ATTR_FSUUID
|
||||
evm_hmac_attrs |= EVM_ATTR_FSUUID;
|
||||
#endif
|
||||
pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
|
||||
}
|
||||
|
||||
static int evm_find_protected_xattrs(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
@ -287,12 +300,20 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
|||
* @xattr_value: pointer to the new extended attribute value
|
||||
* @xattr_value_len: pointer to the new extended attribute value length
|
||||
*
|
||||
* Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
|
||||
* the current value is valid.
|
||||
* Before allowing the 'security.evm' protected xattr to be updated,
|
||||
* verify the existing value is valid. As only the kernel should have
|
||||
* access to the EVM encrypted key needed to calculate the HMAC, prevent
|
||||
* 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)
|
||||
{
|
||||
const struct evm_ima_xattr_data *xattr_data = xattr_value;
|
||||
|
||||
if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
|
||||
&& (xattr_data->type == EVM_XATTR_HMAC))
|
||||
return -EPERM;
|
||||
return evm_protect_xattr(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len);
|
||||
}
|
||||
|
@ -432,6 +453,8 @@ static int __init init_evm(void)
|
|||
{
|
||||
int error;
|
||||
|
||||
evm_init_config();
|
||||
|
||||
error = evm_init_secfs();
|
||||
if (error < 0) {
|
||||
pr_info("Error registering secfs\n");
|
||||
|
|
|
@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ima_reset_appraise_flags(struct inode *inode)
|
||||
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
|
||||
|
@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode)
|
|||
return;
|
||||
|
||||
iint->flags &= ~IMA_DONE_MASK;
|
||||
if (digsig)
|
||||
iint->flags |= IMA_DIGSIG;
|
||||
return;
|
||||
}
|
||||
|
||||
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 result;
|
||||
|
||||
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
|
||||
xattr_value_len);
|
||||
if (result == 1) {
|
||||
ima_reset_appraise_flags(dentry->d_inode);
|
||||
ima_reset_appraise_flags(dentry->d_inode,
|
||||
(xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
|
@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
|
|||
|
||||
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
|
||||
if (result == 1) {
|
||||
ima_reset_appraise_flags(dentry->d_inode);
|
||||
ima_reset_appraise_flags(dentry->d_inode, 0);
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -27,6 +27,36 @@
|
|||
|
||||
static struct crypto_shash *ima_shash_tfm;
|
||||
|
||||
/**
|
||||
* ima_kernel_read - read file content
|
||||
*
|
||||
* This is a function for reading file content instead of kernel_read().
|
||||
* It does not perform locking checks to ensure it cannot be blocked.
|
||||
* It does not perform security checks because it is irrelevant for IMA.
|
||||
*
|
||||
*/
|
||||
static int ima_kernel_read(struct file *file, loff_t offset,
|
||||
char *addr, unsigned long count)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
char __user *buf = addr;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
if (!file->f_op->read && !file->f_op->aio_read)
|
||||
return -EINVAL;
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
if (file->f_op->read)
|
||||
ret = file->f_op->read(file, buf, count, &offset);
|
||||
else
|
||||
ret = do_sync_read(file, buf, count, &offset);
|
||||
set_fs(old_fs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ima_init_crypto(void)
|
||||
{
|
||||
long rc;
|
||||
|
@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
|
|||
while (offset < i_size) {
|
||||
int rbuf_len;
|
||||
|
||||
rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
|
||||
rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
|
||||
if (rbuf_len < 0) {
|
||||
rc = rbuf_len;
|
||||
break;
|
||||
|
|
|
@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file)
|
|||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
fmode_t mode = file->f_mode;
|
||||
int must_measure;
|
||||
bool send_tomtou = false, send_writers = false;
|
||||
char *pathbuf = NULL;
|
||||
const char *pathname;
|
||||
|
@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file)
|
|||
mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */
|
||||
|
||||
if (mode & FMODE_WRITE) {
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
|
||||
send_tomtou = true;
|
||||
goto out;
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
|
||||
struct integrity_iint_cache *iint;
|
||||
iint = integrity_iint_find(inode);
|
||||
/* IMA_MEASURE is set from reader side */
|
||||
if (iint && (iint->flags & IMA_MEASURE))
|
||||
send_tomtou = true;
|
||||
}
|
||||
} else {
|
||||
if ((atomic_read(&inode->i_writecount) > 0) &&
|
||||
ima_must_measure(inode, MAY_READ, FILE_CHECK))
|
||||
send_writers = true;
|
||||
}
|
||||
|
||||
must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK);
|
||||
if (!must_measure)
|
||||
goto out;
|
||||
|
||||
if (atomic_read(&inode->i_writecount) > 0)
|
||||
send_writers = true;
|
||||
out:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
if (!send_tomtou && !send_writers)
|
||||
|
|
Loading…
Reference in a new issue