Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 264480
b: refs/heads/master
c: 66dbc32
h: refs/heads/master
v: v3
  • Loading branch information
Mimi Zohar committed Jul 18, 2011
1 parent db9f3de commit 7192e12
Show file tree
Hide file tree
Showing 14 changed files with 666 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1601fbad2b14e0b8d4dbb55e749bfe31e972818a
refs/heads/master: 66dbc325afcef909043c30e90930a36823fc734c
23 changes: 23 additions & 0 deletions trunk/Documentation/ABI/testing/evm
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
What: security/evm
Date: March 2011
Contact: Mimi Zohar <zohar@us.ibm.com>
Description:
EVM protects a file's security extended attributes(xattrs)
against integrity attacks. The initial method maintains an
HMAC-sha1 value across the extended attributes, storing the
value as the extended attribute 'security.evm'.

EVM depends on the Kernel Key Retention System to provide it
with a trusted/encrypted key for the HMAC-sha1 operation.
The key is loaded onto the root's keyring using keyctl. Until
EVM receives notification that the key has been successfully
loaded onto the keyring (echo 1 > <securityfs>/evm), EVM
can not create or validate the 'security.evm' xattr, but
returns INTEGRITY_UNKNOWN. Loading the key and signaling EVM
should be done as early as possible. Normally this is done
in the initramfs, which has already been measured as part
of the trusted boot. For more information on creating and
loading existing trusted/encrypted keys, refer to:
Documentation/keys-trusted-encrypted.txt. (A sample dracut
patch, which loads the trusted/encrypted key and enables
EVM, is available from http://linux-ima.sourceforge.net/#EVM.)
7 changes: 7 additions & 0 deletions trunk/include/linux/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

#include <linux/fs.h>

enum integrity_status {
INTEGRITY_PASS = 0,
INTEGRITY_FAIL,
INTEGRITY_NOLABEL,
INTEGRITY_UNKNOWN,
};

#ifdef CONFIG_INTEGRITY
extern int integrity_inode_alloc(struct inode *inode);
extern void integrity_inode_free(struct inode *inode);
Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)

/* Security namespace */
#define XATTR_EVM_SUFFIX "evm"
#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX

#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX

Expand Down
3 changes: 2 additions & 1 deletion trunk/security/integrity/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#
config INTEGRITY
def_bool y
depends on IMA
depends on IMA || EVM

source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
2 changes: 2 additions & 0 deletions trunk/security/integrity/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ integrity-y := iint.o

subdir-$(CONFIG_IMA) += ima
obj-$(CONFIG_IMA) += ima/built-in.o
subdir-$(CONFIG_EVM) += evm
obj-$(CONFIG_EVM) += evm/built-in.o
12 changes: 12 additions & 0 deletions trunk/security/integrity/evm/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
config EVM
boolean "EVM support"
depends on SECURITY && KEYS && ENCRYPTED_KEYS
select CRYPTO_HMAC
select CRYPTO_MD5
select CRYPTO_SHA1
default n
help
EVM protects a file's security extended attributes against
integrity attacks.

If you are unsure how to answer this question, answer N.
6 changes: 6 additions & 0 deletions trunk/security/integrity/evm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# Makefile for building the Extended Verification Module(EVM)
#
obj-$(CONFIG_EVM) += evm.o

evm-y := evm_main.o evm_crypto.o evm_secfs.o
33 changes: 33 additions & 0 deletions trunk/security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2005-2010 IBM Corporation
*
* Authors:
* Mimi Zohar <zohar@us.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* File: evm.h
*
*/
#include <linux/security.h>
#include "../integrity.h"

extern int evm_initialized;
extern char *evm_hmac;

/* List of EVM protected security xattrs */
extern char *evm_config_xattrnames[];

extern int evm_init_key(void);
extern int evm_update_evmxattr(struct dentry *dentry,
const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len);
extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char *digest);
extern int evm_init_secfs(void);
extern void evm_cleanup_secfs(void);
183 changes: 183 additions & 0 deletions trunk/security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (C) 2005-2010 IBM Corporation
*
* Authors:
* Mimi Zohar <zohar@us.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* File: evm_crypto.c
* Using root's kernel master key (kmk), calculate the HMAC
*/

#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/xattr.h>
#include <linux/scatterlist.h>
#include <keys/encrypted-type.h>
#include "evm.h"

#define EVMKEY "evm-key"
#define MAX_KEY_SIZE 128
static unsigned char evmkey[MAX_KEY_SIZE];
static int evmkey_len = MAX_KEY_SIZE;

static int init_desc(struct hash_desc *desc)
{
int rc;

desc->tfm = crypto_alloc_hash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(desc->tfm)) {
pr_info("Can not allocate %s (reason: %ld)\n",
evm_hmac, PTR_ERR(desc->tfm));
rc = PTR_ERR(desc->tfm);
return rc;
}
desc->flags = 0;
rc = crypto_hash_setkey(desc->tfm, evmkey, evmkey_len);
if (rc)
goto out;
rc = crypto_hash_init(desc);
out:
if (rc)
crypto_free_hash(desc->tfm);
return rc;
}

/* Protect against 'cutting & pasting' security.evm xattr, include inode
* specific info.
*
* (Additional directory/file metadata needs to be added for more complete
* protection.)
*/
static void hmac_add_misc(struct hash_desc *desc, struct inode *inode,
char *digest)
{
struct h_misc {
unsigned long ino;
__u32 generation;
uid_t uid;
gid_t gid;
umode_t mode;
} hmac_misc;
struct scatterlist sg[1];

memset(&hmac_misc, 0, sizeof hmac_misc);
hmac_misc.ino = inode->i_ino;
hmac_misc.generation = inode->i_generation;
hmac_misc.uid = inode->i_uid;
hmac_misc.gid = inode->i_gid;
hmac_misc.mode = inode->i_mode;
sg_init_one(sg, &hmac_misc, sizeof hmac_misc);
crypto_hash_update(desc, sg, sizeof hmac_misc);
crypto_hash_final(desc, digest);
}

/*
* Calculate the HMAC value across the set of protected security xattrs.
*
* Instead of retrieving the requested xattr, for performance, calculate
* the hmac using the requested xattr value. Don't alloc/free memory for
* each xattr, but attempt to re-use the previously allocated memory.
*/
int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
char *digest)
{
struct inode *inode = dentry->d_inode;
struct hash_desc desc;
struct scatterlist sg[1];
char **xattrname;
size_t xattr_size = 0;
char *xattr_value = NULL;
int error;
int size;

if (!inode->i_op || !inode->i_op->getxattr)
return -EOPNOTSUPP;
error = init_desc(&desc);
if (error)
return error;

error = -ENODATA;
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
if ((req_xattr_name && req_xattr_value)
&& !strcmp(*xattrname, req_xattr_name)) {
error = 0;
sg_init_one(sg, req_xattr_value, req_xattr_value_len);
crypto_hash_update(&desc, sg, req_xattr_value_len);
continue;
}
size = vfs_getxattr_alloc(dentry, *xattrname,
&xattr_value, xattr_size, GFP_NOFS);
if (size == -ENOMEM) {
error = -ENOMEM;
goto out;
}
if (size < 0)
continue;

error = 0;
xattr_size = size;
sg_init_one(sg, xattr_value, xattr_size);
crypto_hash_update(&desc, sg, xattr_size);
}
hmac_add_misc(&desc, inode, digest);
kfree(xattr_value);
out:
crypto_free_hash(desc.tfm);
return error;
}

/*
* Calculate the hmac and update security.evm xattr
*
* Expects to be called with i_mutex locked.
*/
int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
struct inode *inode = dentry->d_inode;
u8 hmac[SHA1_DIGEST_SIZE];
int rc = 0;

rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, hmac);
if (rc == 0)
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
hmac, SHA1_DIGEST_SIZE, 0);
else if (rc == -ENODATA)
rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
return rc;
}

/*
* Get the key from the TPM for the SHA1-HMAC
*/
int evm_init_key(void)
{
struct key *evm_key;
struct encrypted_key_payload *ekp;
int rc = 0;

evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
if (IS_ERR(evm_key))
return -ENOENT;

down_read(&evm_key->sem);
ekp = evm_key->payload.data;
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
rc = -EINVAL;
goto out;
}
memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
out:
/* burn the original key contents */
memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
up_read(&evm_key->sem);
key_put(evm_key);
return rc;
}
Loading

0 comments on commit 7192e12

Please sign in to comment.