Skip to content

Commit

Permalink
Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/jmorris/linux-security

Pull integrity updates from James Morris:
 "This adds support for EVM signatures based on larger digests, contains
  a new audit record AUDIT_INTEGRITY_POLICY_RULE to differentiate the
  IMA policy rules from the IMA-audit messages, addresses two deadlocks
  due to either loading or searching for crypto algorithms, and cleans
  up the audit messages"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  EVM: fix return value check in evm_write_xattrs()
  integrity: prevent deadlock during digsig verification.
  evm: Allow non-SHA1 digital signatures
  evm: Don't deadlock if a crypto algorithm is unavailable
  integrity: silence warning when CONFIG_SECURITYFS is not enabled
  ima: Differentiate auditing policy rules from "audit" actions
  ima: Do not audit if CONFIG_INTEGRITY_AUDIT is not set
  ima: Use audit_log_format() rather than audit_log_string()
  ima: Call audit_log_string() rather than logging it untrusted
  • Loading branch information
torvalds committed Aug 16, 2018
2 parents c715ebe + 3dd0f18 commit f91e654
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 47 deletions.
2 changes: 1 addition & 1 deletion crypto/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static struct crypto_alg *crypto_larval_lookup(const char *name, u32 type,
mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);

alg = crypto_alg_lookup(name, type, mask);
if (!alg) {
if (!alg && !(mask & CRYPTO_NOLOAD)) {
request_module("crypto-%s", name);

if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
Expand Down
5 changes: 5 additions & 0 deletions include/linux/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@
*/
#define CRYPTO_ALG_OPTIONAL_KEY 0x00004000

/*
* Don't trigger module loading
*/
#define CRYPTO_NOLOAD 0x00008000

/*
* Transform masks and values (for crt_flags).
*/
Expand Down
13 changes: 13 additions & 0 deletions include/linux/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,17 @@ static inline void integrity_load_keys(void)
}
#endif /* CONFIG_INTEGRITY */

#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS

extern int integrity_kernel_module_request(char *kmod_name);

#else

static inline int integrity_kernel_module_request(char *kmod_name)
{
return 0;
}

#endif /* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */

#endif /* _LINUX_INTEGRITY_H */
1 change: 1 addition & 0 deletions include/uapi/linux/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */
#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */
#define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */
#define AUDIT_INTEGRITY_POLICY_RULE 1807 /* IMA policy rules */

#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */

Expand Down
23 changes: 23 additions & 0 deletions security/integrity/digsig_asymmetric.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,26 @@ int asymmetric_verify(struct key *keyring, const char *sig,
pr_debug("%s() = %d\n", __func__, ret);
return ret;
}

/**
* integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
* @kmod_name: kernel module name
*
* We have situation, when public_key_verify_signature() in case of RSA
* algorithm use alg_name to store internal information in order to
* construct an algorithm on the fly, but crypto_larval_lookup() will try
* to use alg_name in order to load kernel module with same name.
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
* we are safe to fail such module request from crypto_larval_lookup().
*
* In this way we prevent modprobe execution during digsig verification
* and avoid possible deadlock if modprobe and/or it's dependencies
* also signed with digsig.
*/
int integrity_kernel_module_request(char *kmod_name)
{
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
return -EINVAL;

return 0;
}
1 change: 1 addition & 0 deletions security/integrity/evm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config EVM
select ENCRYPTED_KEYS
select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_HASH_INFO
default n
help
EVM protects a file's security extended attributes against
Expand Down
10 changes: 8 additions & 2 deletions security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,23 @@ extern struct crypto_shash *hash_tfm;
/* List of EVM protected security xattrs */
extern struct list_head evm_config_xattrnames;

struct evm_digest {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} __packed;

int evm_init_key(void);
int evm_update_evmxattr(struct dentry *dentry,
const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len);
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);
size_t req_xattr_value_len, struct evm_digest *data);
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char type, char *digest);
size_t req_xattr_value_len, char type,
struct evm_digest *data);
int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
char *hmac_val);
int evm_init_secfs(void);
Expand Down
50 changes: 27 additions & 23 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/evm.h>
#include <keys/encrypted-type.h>
#include <crypto/hash.h>
#include <crypto/hash_info.h>
#include "evm.h"

#define EVMKEY "evm-key"
Expand All @@ -29,7 +30,7 @@ static unsigned char evmkey[MAX_KEY_SIZE];
static int evmkey_len = MAX_KEY_SIZE;

struct crypto_shash *hmac_tfm;
struct crypto_shash *hash_tfm;
static struct crypto_shash *evm_tfm[HASH_ALGO__LAST];

static DEFINE_MUTEX(mutex);

Expand All @@ -38,7 +39,6 @@ static DEFINE_MUTEX(mutex);
static unsigned long evm_set_key_flags;

static char * const evm_hmac = "hmac(sha1)";
static char * const evm_hash = "sha1";

/**
* evm_set_key() - set EVM HMAC key from the kernel
Expand Down Expand Up @@ -74,10 +74,10 @@ int evm_set_key(void *key, size_t keylen)
}
EXPORT_SYMBOL_GPL(evm_set_key);

static struct shash_desc *init_desc(char type)
static struct shash_desc *init_desc(char type, uint8_t hash_algo)
{
long rc;
char *algo;
const char *algo;
struct crypto_shash **tfm;
struct shash_desc *desc;

Expand All @@ -89,15 +89,16 @@ static struct shash_desc *init_desc(char type)
tfm = &hmac_tfm;
algo = evm_hmac;
} else {
tfm = &hash_tfm;
algo = evm_hash;
tfm = &evm_tfm[hash_algo];
algo = hash_algo_name[hash_algo];
}

if (*tfm == NULL) {
mutex_lock(&mutex);
if (*tfm)
goto out;
*tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
*tfm = crypto_alloc_shash(algo, 0,
CRYPTO_ALG_ASYNC | CRYPTO_NOLOAD);
if (IS_ERR(*tfm)) {
rc = PTR_ERR(*tfm);
pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
Expand Down Expand Up @@ -186,10 +187,10 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
* each xattr, but attempt to re-use the previously allocated memory.
*/
static int evm_calc_hmac_or_hash(struct dentry *dentry,
const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len,
char type, char *digest)
const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len,
uint8_t type, struct evm_digest *data)
{
struct inode *inode = d_backing_inode(dentry);
struct xattr_list *xattr;
Expand All @@ -204,10 +205,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
inode->i_sb->s_user_ns != &init_user_ns)
return -EOPNOTSUPP;

desc = init_desc(type);
desc = init_desc(type, data->hdr.algo);
if (IS_ERR(desc))
return PTR_ERR(desc);

data->hdr.length = crypto_shash_digestsize(desc->tfm);

error = -ENODATA;
list_for_each_entry_rcu(xattr, &evm_config_xattrnames, list) {
bool is_ima = false;
Expand Down Expand Up @@ -239,7 +242,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (is_ima)
ima_present = true;
}
hmac_add_misc(desc, inode, type, digest);
hmac_add_misc(desc, inode, type, data->digest);

/* Portable EVM signatures must include an IMA hash */
if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present)
Expand All @@ -252,18 +255,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,

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 evm_digest *data)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, EVM_XATTR_HMAC, digest);
req_xattr_value_len, EVM_XATTR_HMAC, data);
}

int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
char type, char *digest)
char type, struct evm_digest *data)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, type, digest);
req_xattr_value_len, type, data);
}

static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
Expand Down Expand Up @@ -303,7 +306,7 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
struct inode *inode = d_backing_inode(dentry);
struct evm_ima_xattr_data xattr_data;
struct evm_digest data;
int rc = 0;

/*
Expand All @@ -316,13 +319,14 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
if (rc)
return -EPERM;

data.hdr.algo = HASH_ALGO_SHA1;
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, xattr_data.digest);
xattr_value_len, &data);
if (rc == 0) {
xattr_data.type = EVM_XATTR_HMAC;
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
&xattr_data,
sizeof(xattr_data), 0);
&data.hdr.xattr.data[1],
SHA1_DIGEST_SIZE + 1, 0);
} else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
}
Expand All @@ -334,7 +338,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
{
struct shash_desc *desc;

desc = init_desc(EVM_XATTR_HMAC);
desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
if (IS_ERR(desc)) {
pr_info("init_desc failed\n");
return PTR_ERR(desc);
Expand Down
19 changes: 12 additions & 7 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/magic.h>

#include <crypto/hash.h>
#include <crypto/hash_info.h>
#include <crypto/algapi.h>
#include "evm.h"

Expand Down Expand Up @@ -134,8 +135,9 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
struct integrity_iint_cache *iint)
{
struct evm_ima_xattr_data *xattr_data = NULL;
struct evm_ima_xattr_data calc;
struct signature_v2_hdr *hdr;
enum integrity_status evm_status = INTEGRITY_PASS;
struct evm_digest digest;
struct inode *inode;
int rc, xattr_len;

Expand Down Expand Up @@ -171,25 +173,28 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = INTEGRITY_FAIL;
goto out;
}

digest.hdr.algo = HASH_ALGO_SHA1;
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, calc.digest);
xattr_value_len, &digest);
if (rc)
break;
rc = crypto_memneq(xattr_data->digest, calc.digest,
sizeof(calc.digest));
rc = crypto_memneq(xattr_data->digest, digest.digest,
SHA1_DIGEST_SIZE);
if (rc)
rc = -EINVAL;
break;
case EVM_IMA_XATTR_DIGSIG:
case EVM_XATTR_PORTABLE_DIGSIG:
hdr = (struct signature_v2_hdr *)xattr_data;
digest.hdr.algo = hdr->hash_algo;
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
xattr_value_len, xattr_data->type,
calc.digest);
xattr_value_len, xattr_data->type, &digest);
if (rc)
break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
(const char *)xattr_data, xattr_len,
calc.digest, sizeof(calc.digest));
digest.digest, digest.hdr.length);
if (!rc) {
inode = d_backing_inode(dentry);

Expand Down
4 changes: 2 additions & 2 deletions security/integrity/evm/evm_secfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
return -E2BIG;

ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_EVM_XATTR);
if (IS_ERR(ab))
return PTR_ERR(ab);
if (!ab)
return -ENOMEM;

xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
if (!xattr) {
Expand Down
9 changes: 6 additions & 3 deletions security/integrity/iint.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,13 @@ static int __init integrity_fs_init(void)
{
integrity_dir = securityfs_create_dir("integrity", NULL);
if (IS_ERR(integrity_dir)) {
pr_err("Unable to create integrity sysfs dir: %ld\n",
PTR_ERR(integrity_dir));
int ret = PTR_ERR(integrity_dir);

if (ret != -ENODEV)
pr_err("Unable to create integrity sysfs dir: %d\n",
ret);
integrity_dir = NULL;
return PTR_ERR(integrity_dir);
return ret;
}

return 0;
Expand Down
1 change: 1 addition & 0 deletions security/integrity/ima/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ config IMA
select TCG_TIS if TCG_TPM && X86
select TCG_CRB if TCG_TPM && ACPI
select TCG_IBMVTPM if TCG_TPM && PPC_PSERIES
select INTEGRITY_AUDIT if AUDIT
help
The Trusted Computing Group(TCG) runtime Integrity
Measurement Architecture(IMA) maintains a list of hash
Expand Down
9 changes: 6 additions & 3 deletions security/integrity/ima/ima_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,14 +657,16 @@ static int ima_lsm_rule_init(struct ima_rule_entry *entry,
static void ima_log_string_op(struct audit_buffer *ab, char *key, char *value,
bool (*rule_operator)(kuid_t, kuid_t))
{
if (!ab)
return;

if (rule_operator == &uid_gt)
audit_log_format(ab, "%s>", key);
else if (rule_operator == &uid_lt)
audit_log_format(ab, "%s<", key);
else
audit_log_format(ab, "%s=", key);
audit_log_untrustedstring(ab, value);
audit_log_format(ab, " ");
audit_log_format(ab, "%s ", value);
}
static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
{
Expand All @@ -679,7 +681,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
bool uid_token;
int result = 0;

ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE);
ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_INTEGRITY_POLICY_RULE);

entry->uid = INVALID_UID;
entry->fowner = INVALID_UID;
Expand Down
Loading

0 comments on commit f91e654

Please sign in to comment.