Commit ac60ab4b authored by James Morris's avatar James Morris

Merge branch 'next' of...

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity into next
parents a0cfd75f a2d61ed5
......@@ -3058,7 +3058,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = open_check_o_direct(file);
if (error)
goto exit_fput;
error = ima_file_check(file, op->acc_mode);
error = ima_file_check(file, op->acc_mode, *opened);
if (error)
goto exit_fput;
......
......@@ -709,7 +709,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
host_err = PTR_ERR(*filp);
*filp = NULL;
} else {
host_err = ima_file_check(*filp, may_flags);
host_err = ima_file_check(*filp, may_flags, 0);
if (may_flags & NFSD_MAY_64BIT_COOKIE)
(*filp)->f_mode |= FMODE_64BITHASH;
......
......@@ -15,7 +15,7 @@ struct linux_binprm;
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask);
extern int ima_file_check(struct file *file, int mask, int opened);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
extern int ima_module_check(struct file *file);
......@@ -27,7 +27,7 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
return 0;
}
static inline int ima_file_check(struct file *file, int mask)
static inline int ima_file_check(struct file *file, int mask, int opened)
{
return 0;
}
......
#
config INTEGRITY
def_bool y
depends on IMA || EVM
bool "Integrity subsystem"
depends on SECURITY
default y
help
This option enables the integrity subsystem, which is comprised
of a number of different components including the Integrity
Measurement Architecture (IMA), Extended Verification Module
(EVM), IMA-appraisal extension, digital signature verification
extension and audit measurement log support.
Each of these components can be enabled/disabled separately.
Refer to the individual components for additional details.
if INTEGRITY
config INTEGRITY_SIGNATURE
boolean "Digital signature verification using multiple keyrings"
depends on INTEGRITY && KEYS
depends on KEYS
default n
select SIGNATURE
help
......@@ -17,9 +29,21 @@ config INTEGRITY_SIGNATURE
This is useful for evm and module keyrings, when keys are
usually only added from initramfs.
config INTEGRITY_ASYMMETRIC_KEYS
boolean "Enable asymmetric keys support"
depends on INTEGRITY_SIGNATURE
default n
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select PUBLIC_KEY_ALGO_RSA
select X509_CERTIFICATE_PARSER
help
This option enables digital signature verification using
asymmetric keys.
config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
depends on INTEGRITY && AUDIT
depends on AUDIT
default y
help
In addition to enabling integrity auditing support, this
......@@ -32,17 +56,7 @@ config INTEGRITY_AUDIT
be enabled by specifying 'integrity_audit=1' on the kernel
command line.
config INTEGRITY_ASYMMETRIC_KEYS
boolean "Enable asymmetric keys support"
depends on INTEGRITY_SIGNATURE
default n
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select PUBLIC_KEY_ALGO_RSA
select X509_CERTIFICATE_PARSER
help
This option enables digital signature verification using
asymmetric keys.
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
endif # if INTEGRITY
......@@ -3,11 +3,11 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
integrity-y := iint.o
integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
subdir-$(CONFIG_IMA) += ima
obj-$(CONFIG_IMA) += ima/
......
......@@ -13,6 +13,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/ratelimit.h>
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
......@@ -45,8 +46,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
}
if (IS_ERR(key)) {
pr_warn("Request for unknown key '%s' err %ld\n",
name, PTR_ERR(key));
pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
name, PTR_ERR(key));
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
......
config EVM
boolean "EVM support"
depends on SECURITY
select KEYS
select ENCRYPTED_KEYS
select CRYPTO_HMAC
......@@ -12,10 +11,6 @@ config EVM
If you are unsure how to answer this question, answer N.
if EVM
menu "EVM options"
config EVM_ATTR_FSUUID
bool "FSUUID (version 2)"
default y
......@@ -47,6 +42,3 @@ config EVM_EXTRA_SMACK_XATTRS
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.
endmenu
endif
......@@ -126,14 +126,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
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) {
evm_status = INTEGRITY_FAIL;
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 */
} else if (rc == -EOPNOTSUPP) {
evm_status = INTEGRITY_UNKNOWN;
}
goto out;
}
......@@ -284,6 +285,13 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
goto out;
}
evm_status = evm_verify_current_integrity(dentry);
if (evm_status == INTEGRITY_NOXATTRS) {
struct integrity_iint_cache *iint;
iint = integrity_iint_find(dentry->d_inode);
if (iint && (iint->flags & IMA_NEW_FILE))
return 0;
}
out:
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
......@@ -352,7 +360,6 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
return;
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
return;
}
/**
......@@ -372,7 +379,6 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
mutex_lock(&inode->i_mutex);
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
mutex_unlock(&inode->i_mutex);
return;
}
/**
......@@ -414,7 +420,6 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
return;
}
/*
......
......@@ -2,8 +2,6 @@
#
config IMA
bool "Integrity Measurement Architecture(IMA)"
depends on SECURITY
select INTEGRITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
......
......@@ -90,10 +90,7 @@ extern struct list_head ima_measurements; /* list of all measurements */
/* Internal IMA function definitions */
int ima_init(void);
void ima_cleanup(void);
int ima_fs_init(void);
void ima_fs_cleanup(void);
int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode,
const unsigned char *filename);
......@@ -110,8 +107,6 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size);
struct ima_template_desc *ima_template_desc_current(void);
int ima_init_template(void);
int ima_init_template(void);
/*
* used to protect h_table and sha_table
*/
......@@ -151,12 +146,6 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(struct path *path, char **pathbuf);
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
......@@ -177,7 +166,7 @@ void ima_delete_rules(void);
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int xattr_len, int opened);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
......@@ -193,7 +182,7 @@ static inline int ima_appraise_measurement(int func,
struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
int xattr_len, int opened)
{
return INTEGRITY_UNKNOWN;
}
......
......@@ -330,10 +330,9 @@ const char *ima_d_path(struct path *path, char **pathbuf)
{
char *pathname = NULL;
/* We will allow 11 spaces for ' (deleted)' to be appended */
*pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
*pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (*pathbuf) {
pathname = d_path(path, *pathbuf, PATH_MAX + 11);
pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
if (IS_ERR(pathname)) {
kfree(*pathbuf);
*pathbuf = NULL;
......
......@@ -183,7 +183,7 @@ int ima_read_xattr(struct dentry *dentry,
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
int xattr_len, int opened)
{
static const char op[] = "appraise_data";
char *cause = "unknown";
......@@ -192,8 +192,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
if (!ima_appraise)
return 0;
if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN;
......@@ -202,8 +200,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
goto out;
cause = "missing-hash";
status =
(inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
status = INTEGRITY_NOLABEL;
if (opened & FILE_CREATED) {
iint->flags |= IMA_NEW_FILE;
status = INTEGRITY_PASS;
}
goto out;
}
......
......@@ -80,24 +80,24 @@ static int ima_kernel_read(struct file *file, loff_t offset,
{
mm_segment_t old_fs;
char __user *buf = addr;
ssize_t ret;
ssize_t ret = -EINVAL;
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
else if (file->f_op->aio_read)
ret = do_sync_read(file, buf, count, &offset);
else if (file->f_op->read_iter)
ret = new_sync_read(file, buf, count, &offset);
set_fs(old_fs);
return ret;
}
int ima_init_crypto(void)
int __init ima_init_crypto(void)
{
long rc;
......@@ -116,7 +116,10 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
struct crypto_shash *tfm = ima_shash_tfm;
int rc;
if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
if (algo < 0 || algo >= HASH_ALGO__LAST)
algo = ima_hash_algo;
if (algo != ima_hash_algo) {
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
......@@ -200,7 +203,10 @@ static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
struct crypto_ahash *tfm = ima_ahash_tfm;
int rc;
if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
if (algo < 0 || algo >= HASH_ALGO__LAST)
algo = ima_hash_algo;
if (algo != ima_hash_algo || !tfm) {
tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
if (!IS_ERR(tfm)) {
if (algo == ima_hash_algo)
......
......@@ -124,11 +124,13 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
return;
mutex_lock(&inode->i_mutex);
if (atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version) {
iint->flags &= ~IMA_DONE_MASK;
if (iint->flags & IMA_APPRAISE)
ima_update_xattr(iint, file);
if (atomic_read(&inode->i_writecount) == 1) {
if ((iint->version != inode->i_version) ||
(iint->flags & IMA_NEW_FILE)) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
if (iint->flags & IMA_APPRAISE)
ima_update_xattr(iint, file);
}
}
mutex_unlock(&inode->i_mutex);
}
......@@ -154,15 +156,15 @@ void ima_file_free(struct file *file)
ima_check_last_writer(iint, inode, file);
}
static int process_measurement(struct file *file, const char *filename,
int mask, int function)
static int process_measurement(struct file *file, int mask, int function,
int opened)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint;
struct ima_template_desc *template_desc;
char *pathbuf = NULL;
const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise, _func;
int rc = -ENOMEM, action, must_appraise;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0;
......@@ -180,7 +182,8 @@ static int process_measurement(struct file *file, const char *filename,
must_appraise = action & IMA_APPRAISE;
/* Is the appraise rule hook specific? */
_func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
if (action & IMA_FILE_APPRAISE)
function = FILE_CHECK;
mutex_lock(&inode->i_mutex);
......@@ -199,15 +202,13 @@ static int process_measurement(struct file *file, const char *filename,
/* Nothing to do, just return existing appraised status */
if (!action) {
if (must_appraise)
rc = ima_get_cache_status(iint, _func);
rc = ima_get_cache_status(iint, function);
goto out_digsig;
}
template_desc = ima_template_desc_current();
if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
if (action & IMA_APPRAISE_SUBMASK)
xattr_ptr = &xattr_value;
} else
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
xattr_ptr = &xattr_value;
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
......@@ -217,14 +218,14 @@ static int process_measurement(struct file *file, const char *filename,
goto out_digsig;
}
pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
pathname = ima_d_path(&file->f_path, &pathbuf);
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len);
if (action & IMA_APPRAISE_SUBMASK)
rc = ima_appraise_measurement(_func, iint, file, pathname,
xattr_value, xattr_len);
rc = ima_appraise_measurement(function, iint, file, pathname,
xattr_value, xattr_len, opened);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
kfree(pathbuf);
......@@ -253,7 +254,7 @@ static int process_measurement(struct file *file, const char *filename,
int ima_file_mmap(struct file *file, unsigned long prot)
{
if (file && (prot & PROT_EXEC))
return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
......@@ -272,10 +273,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
*/
int ima_bprm_check(struct linux_binprm *bprm)
{
return process_measurement(bprm->file,
(strcmp(bprm->filename, bprm->interp) == 0) ?
bprm->filename : bprm->interp,
MAY_EXEC, BPRM_CHECK);
return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
}
/**
......@@ -288,12 +286,12 @@ int ima_bprm_check(struct linux_binprm *bprm)
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
int ima_file_check(struct file *file, int mask)
int ima_file_check(struct file *file, int mask, int opened)
{
ima_rdwr_violation_check(file);
return process_measurement(file, NULL,
return process_measurement(file,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK);
FILE_CHECK, opened);
}
EXPORT_SYMBOL_GPL(ima_file_check);
......@@ -316,7 +314,7 @@ int ima_module_check(struct file *file)
#endif
return 0; /* We rely on module signature checking */
}
return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
}
int ima_fw_from_file(struct file *file, char *buf, size_t size)
......@@ -327,7 +325,7 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size)
return -EACCES; /* INTEGRITY_UNKNOWN */
return 0;
}
return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
}
static int __init init_ima(void)
......
......@@ -152,24 +152,6 @@ static int template_desc_init_fields(const char *template_fmt,
return result;
}
static int init_defined_templates(void)
{
int i = 0;
int result = 0;
/* Init defined templates. */
for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
struct ima_template_desc *template = &defined_templates[i];
result = template_desc_init_fields(template->fmt,
&(template->fields),
&(template->num_fields));
if (result < 0)
return result;
}
return result;
}
struct ima_template_desc *ima_template_desc_current(void)
{
if (!ima_template)
......@@ -178,13 +160,11 @@ struct ima_template_desc *ima_template_desc_current(void)
return ima_template;
}
int ima_init_template(void)
int __init ima_init_template(void)
{
int result;
result = init_defined_templates();
if (result < 0)
return result;
struct ima_template_desc *template = ima_template_desc_current();
return 0;
return template_desc_init_fields(template->fmt,
&(template->fields),
&(template->num_fields));
}
......@@ -31,6 +31,7 @@
#define IMA_DIGSIG 0x01000000
#define IMA_DIGSIG_REQUIRED 0x02000000
#define IMA_PERMIT_DIRECTIO 0x04000000
#define IMA_NEW_FILE 0x08000000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
IMA_APPRAISE_SUBMASK)
......@@ -116,7 +117,6 @@ struct integrity_iint_cache {
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment