Merge branch 'for-linus' of git://selinuxproject.org/~jmorris/linux-security

* 'for-linus' of git://selinuxproject.org/~jmorris/linux-security: (32 commits)
  ima: fix invalid memory reference
  ima: free duplicate measurement memory
  security: update security_file_mmap() docs
  selinux: Casting (void *) value returned by kmalloc is useless
  apparmor: fix module parameter handling
  Security: tomoyo: add .gitignore file
  tomoyo: add missing rcu_dereference()
  apparmor: add missing rcu_dereference()
  evm: prevent racing during tfm allocation
  evm: key must be set once during initialization
  mpi/mpi-mpow: NULL dereference on allocation failure
  digsig: build dependency fix
  KEYS: Give key types their own lockdep class for key->sem
  TPM: fix transmit_cmd error logic
  TPM: NSC and TIS drivers X86 dependency fix
  TPM: Export wait_for_stat for other vendor specific drivers
  TPM: Use vendor specific function for status probe
  tpm_tis: add delay after aborting command
  tpm_tis: Check return code from getting timeouts/durations
  tpm: Introduce function to poll for result of self test
  ...

Fix up trivial conflict in lib/Makefile due to addition of CONFIG_MPI
and SIGSIG next to CONFIG_DQL addition.
This commit is contained in:
Linus Torvalds 2012-01-10 21:51:23 -08:00
commit e7691a1ce3
59 changed files with 7026 additions and 143 deletions

View file

@ -133,7 +133,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
struct aa_profile *profile = sa->aad.profile;
pid_t pid;
rcu_read_lock();
pid = tsk->real_parent->pid;
pid = rcu_dereference(tsk->real_parent)->pid;
rcu_read_unlock();
audit_log_format(ab, " parent=%d", pid);
if (profile->ns != root_ns) {

View file

@ -670,7 +670,7 @@ static struct security_operations apparmor_ops = {
static int param_set_aabool(const char *val, const struct kernel_param *kp);
static int param_get_aabool(char *buffer, const struct kernel_param *kp);
#define param_check_aabool(name, p) __param_check(name, p, int)
#define param_check_aabool param_check_bool
static struct kernel_param_ops param_ops_aabool = {
.set = param_set_aabool,
.get = param_get_aabool
@ -678,7 +678,7 @@ static struct kernel_param_ops param_ops_aabool = {
static int param_set_aauint(const char *val, const struct kernel_param *kp);
static int param_get_aauint(char *buffer, const struct kernel_param *kp);
#define param_check_aauint(name, p) __param_check(name, p, int)
#define param_check_aauint param_check_uint
static struct kernel_param_ops param_ops_aauint = {
.set = param_set_aauint,
.get = param_get_aauint
@ -686,7 +686,7 @@ static struct kernel_param_ops param_ops_aauint = {
static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
#define param_check_aalockpolicy param_check_bool
static struct kernel_param_ops param_ops_aalockpolicy = {
.set = param_set_aalockpolicy,
.get = param_get_aalockpolicy

View file

@ -3,5 +3,19 @@ config INTEGRITY
def_bool y
depends on IMA || EVM
config INTEGRITY_DIGSIG
boolean "Digital signature verification using multiple keyrings"
depends on INTEGRITY && KEYS
default n
select DIGSIG
help
This option enables digital signature verification support
using multiple keyrings. It defines separate keyrings for each
of the different use cases - evm, ima, and modules.
Different keyrings improves search performance, but also allow
to "lock" certain keyring to prevent adding new keys.
This is useful for evm and module keyrings, when keys are
usually only added from initramfs.
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig

View file

@ -3,6 +3,7 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o
integrity-y := iint.o

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2011 Intel Corporation
*
* Author:
* Dmitry Kasatkin <dmitry.kasatkin@intel.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.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/rbtree.h>
#include <linux/key-type.h>
#include <linux/digsig.h>
#include "integrity.h"
static struct key *keyring[INTEGRITY_KEYRING_MAX];
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
"_evm",
"_module",
"_ima",
};
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen)
{
if (id >= INTEGRITY_KEYRING_MAX)
return -EINVAL;
if (!keyring[id]) {
keyring[id] =
request_key(&key_type_keyring, keyring_name[id], NULL);
if (IS_ERR(keyring[id])) {
int err = PTR_ERR(keyring[id]);
pr_err("no %s keyring: %d\n", keyring_name[id], err);
keyring[id] = NULL;
return err;
}
}
return digsig_verify(keyring[id], sig, siglen, digest, digestlen);
}

View file

@ -12,14 +12,21 @@
* File: evm.h
*
*/
#ifndef __INTEGRITY_EVM_H
#define __INTEGRITY_EVM_H
#include <linux/xattr.h>
#include <linux/security.h>
#include "../integrity.h"
extern int evm_initialized;
extern char *evm_hmac;
extern char *evm_hash;
extern struct crypto_shash *hmac_tfm;
extern struct crypto_shash *hash_tfm;
/* List of EVM protected security xattrs */
extern char *evm_config_xattrnames[];
@ -32,7 +39,12 @@ extern int evm_update_evmxattr(struct dentry *dentry,
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_calc_hash(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_hmac(struct inode *inode, const struct xattr *xattr,
char *hmac_val);
extern int evm_init_secfs(void);
extern void evm_cleanup_secfs(void);
#endif

View file

@ -26,44 +26,56 @@ 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 DEFINE_MUTEX(mutex);
static struct shash_desc *init_desc(void)
static struct shash_desc *init_desc(char type)
{
int rc;
long rc;
char *algo;
struct crypto_shash **tfm;
struct shash_desc *desc;
if (hmac_tfm == NULL) {
if (type == EVM_XATTR_HMAC) {
tfm = &hmac_tfm;
algo = evm_hmac;
} else {
tfm = &hash_tfm;
algo = evm_hash;
}
if (*tfm == NULL) {
mutex_lock(&mutex);
if (hmac_tfm)
if (*tfm)
goto out;
hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hmac_tfm)) {
pr_err("Can not allocate %s (reason: %ld)\n",
evm_hmac, PTR_ERR(hmac_tfm));
rc = PTR_ERR(hmac_tfm);
hmac_tfm = NULL;
*tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(*tfm)) {
rc = PTR_ERR(*tfm);
pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
*tfm = NULL;
mutex_unlock(&mutex);
return ERR_PTR(rc);
}
rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
if (rc) {
crypto_free_shash(hmac_tfm);
hmac_tfm = NULL;
mutex_unlock(&mutex);
return ERR_PTR(rc);
if (type == EVM_XATTR_HMAC) {
rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
if (rc) {
crypto_free_shash(*tfm);
*tfm = NULL;
mutex_unlock(&mutex);
return ERR_PTR(rc);
}
}
out:
mutex_unlock(&mutex);
}
desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
desc->tfm = hmac_tfm;
desc->tfm = *tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
rc = crypto_shash_init(desc);
@ -108,9 +120,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
* 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)
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)
{
struct inode *inode = dentry->d_inode;
struct shash_desc *desc;
@ -122,7 +136,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
if (!inode->i_op || !inode->i_op->getxattr)
return -EOPNOTSUPP;
desc = init_desc();
desc = init_desc(type);
if (IS_ERR(desc))
return PTR_ERR(desc);
@ -156,6 +170,22 @@ out:
return error;
}
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)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, EVM_XATTR_HMAC, digest);
}
int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value, size_t req_xattr_value_len,
char *digest)
{
return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
req_xattr_value_len, IMA_XATTR_DIGEST, digest);
}
/*
* Calculate the hmac and update security.evm xattr
*
@ -186,7 +216,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
{
struct shash_desc *desc;
desc = init_desc();
desc = init_desc(EVM_XATTR_HMAC);
if (IS_ERR(desc)) {
printk(KERN_INFO "init_desc failed\n");
return PTR_ERR(desc);

View file

@ -25,6 +25,7 @@
int evm_initialized;
char *evm_hmac = "hmac(sha1)";
char *evm_hash = "sha1";
char *evm_config_xattrnames[] = {
#ifdef CONFIG_SECURITY_SELINUX
@ -46,6 +47,29 @@ static int __init evm_set_fixmode(char *str)
}
__setup("evm=", evm_set_fixmode);
static int evm_find_protected_xattrs(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
char **xattr;
int error;
int count = 0;
if (!inode->i_op || !inode->i_op->getxattr)
return -EOPNOTSUPP;
for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
error = inode->i_op->getxattr(dentry, *xattr, NULL, 0);
if (error < 0) {
if (error == -ENODATA)
continue;
return error;
}
count++;
}
return count;
}
/*
* evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
*
@ -65,32 +89,72 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
size_t xattr_value_len,
struct integrity_iint_cache *iint)
{
struct evm_ima_xattr_data xattr_data;
struct evm_ima_xattr_data *xattr_data = NULL;
struct evm_ima_xattr_data calc;
enum integrity_status evm_status = INTEGRITY_PASS;
int rc;
int rc, xattr_len;
if (iint && iint->evm_status == INTEGRITY_PASS)
return iint->evm_status;
/* if status is not PASS, try to check again - against -ENOMEM */
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, xattr_data.digest);
if (rc < 0) {
evm_status = (rc == -ENODATA)
? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
/* first need to know the sig type */
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
if (rc <= 0) {
if (rc == 0)
evm_status = INTEGRITY_FAIL; /* empty */
else if (rc == -ENODATA) {
rc = evm_find_protected_xattrs(dentry);
if (rc > 0)
evm_status = INTEGRITY_NOLABEL;
else if (rc == 0)
evm_status = INTEGRITY_NOXATTRS; /* new file */
}
goto out;
}
xattr_data.type = EVM_XATTR_HMAC;
rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
sizeof xattr_data, GFP_NOFS);
if (rc < 0)
evm_status = (rc == -ENODATA)
? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
xattr_len = rc - 1;
/* check value type */
switch (xattr_data->type) {
case EVM_XATTR_HMAC:
rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
xattr_value_len, calc.digest);
if (rc)
break;
rc = memcmp(xattr_data->digest, calc.digest,
sizeof(calc.digest));
if (rc)
rc = -EINVAL;
break;
case EVM_IMA_XATTR_DIGSIG:
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
xattr_value_len, calc.digest);
if (rc)
break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
xattr_data->digest, xattr_len,
calc.digest, sizeof(calc.digest));
if (!rc) {
/* we probably want to replace rsa with hmac here */
evm_update_evmxattr(dentry, xattr_name, xattr_value,
xattr_value_len);
}
break;
default:
rc = -EINVAL;
break;
}
if (rc)
evm_status = (rc == -ENODATA) ?
INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
out:
if (iint)
iint->evm_status = evm_status;
kfree(xattr_data);
return evm_status;
}
@ -354,6 +418,8 @@ static int __init init_evm(void)
printk(KERN_INFO "EVM: Error registering secfs\n");
goto err;
}
return 0;
err:
return error;
}
@ -363,6 +429,8 @@ static void __exit cleanup_evm(void)
evm_cleanup_secfs();
if (hmac_tfm)
crypto_free_shash(hmac_tfm);
if (hash_tfm)
crypto_free_shash(hash_tfm);
}
/*

View file

@ -178,8 +178,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
result = ima_store_template(entry, violation, inode);
if (!result)
if (!result || result == -EEXIST)
iint->flags |= IMA_MEASURED;
else
if (result < 0)
kfree(entry);
}

View file

@ -23,6 +23,8 @@
#include <linux/slab.h>
#include "ima.h"
#define AUDIT_CAUSE_LEN_MAX 32
LIST_HEAD(ima_measurements); /* list of all measurements */
/* key: inode (before secure-hashing a file) */
@ -94,7 +96,8 @@ static int ima_pcr_extend(const u8 *hash)
result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
if (result != 0)
pr_err("IMA: Error Communicating to TPM chip\n");
pr_err("IMA: Error Communicating to TPM chip, result: %d\n",
result);
return result;
}
@ -106,14 +109,16 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
{
u8 digest[IMA_DIGEST_SIZE];
const char *audit_cause = "hash_added";
char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
int audit_info = 1;
int result = 0;
int result = 0, tpmresult = 0;
mutex_lock(&ima_extend_list_mutex);
if (!violation) {
memcpy(digest, entry->digest, sizeof digest);
if (ima_lookup_digest_entry(digest)) {
audit_cause = "hash_exists";
result = -EEXIST;
goto out;
}
}
@ -128,9 +133,11 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
if (violation) /* invalidate pcr */
memset(digest, 0xff, sizeof digest);
result = ima_pcr_extend(digest);
if (result != 0) {
audit_cause = "TPM error";
tpmresult = ima_pcr_extend(digest);
if (tpmresult != 0) {
snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
tpmresult);
audit_cause = tpm_audit_cause;
audit_info = 0;
}
out:

View file

@ -46,5 +46,26 @@ struct integrity_iint_cache {
struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_MODULE 1
#define INTEGRITY_KEYRING_IMA 2
#define INTEGRITY_KEYRING_MAX 3
#ifdef CONFIG_INTEGRITY_DIGSIG
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen);
#else
static inline int integrity_digsig_verify(const unsigned int id,
const char *sig, int siglen,
const char *digest, int digestlen)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_INTEGRITY_DIGSIG */
/* set during initialization */
extern int iint_initialized;

View file

@ -291,6 +291,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
atomic_set(&key->usage, 1);
init_rwsem(&key->sem);
lockdep_set_class(&key->sem, &type->lock_class);
key->type = type;
key->user = user;
key->quotalen = quotalen;
@ -946,6 +947,8 @@ int register_key_type(struct key_type *ktype)
struct key_type *p;
int ret;
memset(&ktype->lock_class, 0, sizeof(ktype->lock_class));
ret = -EEXIST;
down_write(&key_types_sem);

View file

@ -749,14 +749,6 @@ out:
return length;
}
static inline int hexcode_to_int(int code) {
if (code == '\0' || !isxdigit(code))
return -1;
if (isdigit(code))
return code - '0';
return tolower(code) - 'a' + 10;
}
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
char *scon = NULL, *tcon = NULL;
@ -808,9 +800,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (c1 == '+')
c1 = ' ';
else if (c1 == '%') {
if ((c1 = hexcode_to_int(*r++)) < 0)
c1 = hex_to_bin(*r++);
if (c1 < 0)
goto out;
if ((c2 = hexcode_to_int(*r++)) < 0)
c2 = hex_to_bin(*r++);
if (c2 < 0)
goto out;
c1 = (c1 << 4) | c2;
}

View file

@ -175,7 +175,7 @@ void cond_policydb_destroy(struct policydb *p)
int cond_init_bool_indexes(struct policydb *p)
{
kfree(p->bool_val_to_struct);
p->bool_val_to_struct = (struct cond_bool_datum **)
p->bool_val_to_struct =
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
if (!p->bool_val_to_struct)
return -ENOMEM;

2
security/tomoyo/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
builtin-policy.h
policy/

View file

@ -1122,7 +1122,7 @@ static inline pid_t tomoyo_sys_getppid(void)
{
pid_t pid;
rcu_read_lock();
pid = task_tgid_vnr(current->real_parent);
pid = task_tgid_vnr(rcu_dereference(current->real_parent));
rcu_read_unlock();
return pid;
}