Skip to content

Commit

Permalink
Merge branch 'serge-next-2' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/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
  • Loading branch information
torvalds committed Jun 13, 2014
2 parents 6d87c22 + 0430e49 commit aa569fa
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 28 deletions.
42 changes: 34 additions & 8 deletions security/integrity/evm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
if EVM

menu "EVM options"

config EVM_ATTR_FSUUID
bool "FSUUID (version 2)"
default y
depends on EVM
default 2
help
This options adds EVM HMAC version support.
1 - original version
2 - add per filesystem unique identifier (UUID) (default)
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
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
5 changes: 4 additions & 1 deletion security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 26 additions & 3 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ 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
XATTR_NAME_SELINUX,
#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,
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");
Expand Down
10 changes: 7 additions & 3 deletions security/integrity/ima/ima_appraise.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand Down
32 changes: 31 additions & 1 deletion security/integrity/ima/ima_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
22 changes: 11 additions & 11 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down

0 comments on commit aa569fa

Please sign in to comment.