Commit b33e3cc5 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-integrity' of...

Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem integrity updates from James Morris:
 "There is a mixture of bug fixes, code cleanup, preparatory code for
  new functionality and new functionality.

  Commit 26ddabfe ("evm: enable EVM when X509 certificate is
  loaded") enabled EVM without loading a symmetric key, but was limited
  to defining the x509 certificate pathname at build. Included in this
  set of patches is the ability of enabling EVM, without loading the EVM
  symmetric key, from userspace. New is the ability to prevent the
  loading of an EVM symmetric key."

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  ima: Remove redundant conditional operator
  ima: Fix bool initialization/comparison
  ima: check signature enforcement against cmdline param instead of CONFIG
  module: export module signature enforcement status
  ima: fix hash algorithm initialization
  EVM: Only complain about a missing HMAC key once
  EVM: Allow userspace to signal an RSA key has been loaded
  EVM: Include security.apparmor in EVM measurements
  ima: call ima_file_free() prior to calling fasync
  integrity: use kernel_read_file_from_path() to read x509 certs
  ima: always measure and audit files in policy
  ima: don't remove the securityfs policy file
  vfs: fix mounting a filesystem with i_version
parents 55b3a0cb e5729f86
...@@ -7,17 +7,37 @@ Description: ...@@ -7,17 +7,37 @@ Description:
HMAC-sha1 value across the extended attributes, storing the HMAC-sha1 value across the extended attributes, storing the
value as the extended attribute 'security.evm'. value as the extended attribute 'security.evm'.
EVM depends on the Kernel Key Retention System to provide it EVM supports two classes of security.evm. The first is
with a trusted/encrypted key for the HMAC-sha1 operation. an HMAC-sha1 generated locally with a
The key is loaded onto the root's keyring using keyctl. Until trusted/encrypted key stored in the Kernel Key
EVM receives notification that the key has been successfully Retention System. The second is a digital signature
loaded onto the keyring (echo 1 > <securityfs>/evm), EVM generated either locally or remotely using an
can not create or validate the 'security.evm' xattr, but asymmetric key. These keys are loaded onto root's
returns INTEGRITY_UNKNOWN. Loading the key and signaling EVM keyring using keyctl, and EVM is then enabled by
should be done as early as possible. Normally this is done echoing a value to <securityfs>/evm:
in the initramfs, which has already been measured as part
of the trusted boot. For more information on creating and 1: enable HMAC validation and creation
loading existing trusted/encrypted keys, refer to: 2: enable digital signature validation
Documentation/security/keys/trusted-encrypted.rst. (A sample 3: enable HMAC and digital signature validation and HMAC
dracut patch, which loads the trusted/encrypted key and enables creation
EVM, is available from http://linux-ima.sourceforge.net/#EVM.)
Further writes will be blocked if HMAC support is enabled or
if bit 32 is set:
echo 0x80000002 ><securityfs>/evm
will enable digital signature validation and block
further writes to <securityfs>/evm.
Until this is done, EVM can not create or validate the
'security.evm' xattr, but returns INTEGRITY_UNKNOWN.
Loading keys 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/security/keys/trusted-encrypted.rst. Both dracut
(via 97masterkey and 98integrity) and systemd (via
core/ima-setup) have support for loading keys at boot
time.
...@@ -201,11 +201,11 @@ static void __fput(struct file *file) ...@@ -201,11 +201,11 @@ static void __fput(struct file *file)
eventpoll_release(file); eventpoll_release(file);
locks_remove_file(file); locks_remove_file(file);
ima_file_free(file);
if (unlikely(file->f_flags & FASYNC)) { if (unlikely(file->f_flags & FASYNC)) {
if (file->f_op->fasync) if (file->f_op->fasync)
file->f_op->fasync(-1, file, 0); file->f_op->fasync(-1, file, 0);
} }
ima_file_free(file);
if (file->f_op->release) if (file->f_op->release)
file->f_op->release(inode, file); file->f_op->release(inode, file);
security_file_free(file); security_file_free(file);
......
...@@ -2793,6 +2793,7 @@ extern int do_pipe_flags(int *, int); ...@@ -2793,6 +2793,7 @@ extern int do_pipe_flags(int *, int);
id(KEXEC_IMAGE, kexec-image) \ id(KEXEC_IMAGE, kexec-image) \
id(KEXEC_INITRAMFS, kexec-initramfs) \ id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \ id(POLICY, security-policy) \
id(X509_CERTIFICATE, x509-certificate) \
id(MAX_ID, ) id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM, #define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
......
...@@ -639,6 +639,8 @@ static inline bool is_livepatch_module(struct module *mod) ...@@ -639,6 +639,8 @@ static inline bool is_livepatch_module(struct module *mod)
} }
#endif /* CONFIG_LIVEPATCH */ #endif /* CONFIG_LIVEPATCH */
bool is_module_sig_enforced(void);
#else /* !CONFIG_MODULES... */ #else /* !CONFIG_MODULES... */
static inline struct module *__module_address(unsigned long addr) static inline struct module *__module_address(unsigned long addr)
...@@ -753,6 +755,11 @@ static inline bool module_requested_async_probing(struct module *module) ...@@ -753,6 +755,11 @@ static inline bool module_requested_async_probing(struct module *module)
return false; return false;
} }
static inline bool is_module_sig_enforced(void)
{
return false;
}
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
......
...@@ -66,6 +66,9 @@ ...@@ -66,6 +66,9 @@
#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE #define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE
#define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP #define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP
#define XATTR_APPARMOR_SUFFIX "apparmor"
#define XATTR_NAME_APPARMOR XATTR_SECURITY_PREFIX XATTR_APPARMOR_SUFFIX
#define XATTR_CAPS_SUFFIX "capability" #define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
......
...@@ -278,6 +278,16 @@ static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE); ...@@ -278,6 +278,16 @@ static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
module_param(sig_enforce, bool_enable_only, 0644); module_param(sig_enforce, bool_enable_only, 0644);
#endif /* !CONFIG_MODULE_SIG_FORCE */ #endif /* !CONFIG_MODULE_SIG_FORCE */
/*
* Export sig_enforce kernel cmdline parameter to allow other subsystems rely
* on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
*/
bool is_module_sig_enforced(void)
{
return sig_enforce;
}
EXPORT_SYMBOL(is_module_sig_enforced);
/* Block module loading/unloading? */ /* Block module loading/unloading? */
int modules_disabled = 0; int modules_disabled = 0;
core_param(nomodule, modules_disabled, bint, 0); core_param(nomodule, modules_disabled, bint, 0);
......
...@@ -112,21 +112,25 @@ int __init integrity_init_keyring(const unsigned int id) ...@@ -112,21 +112,25 @@ int __init integrity_init_keyring(const unsigned int id)
int __init integrity_load_x509(const unsigned int id, const char *path) int __init integrity_load_x509(const unsigned int id, const char *path)
{ {
key_ref_t key; key_ref_t key;
char *data; void *data;
loff_t size;
int rc; int rc;
if (!keyring[id]) if (!keyring[id])
return -EINVAL; return -EINVAL;
rc = integrity_read_file(path, &data); rc = kernel_read_file_from_path(path, &data, &size, 0,
if (rc < 0) READING_X509_CERTIFICATE);
if (rc < 0) {
pr_err("Unable to open file: %s (%d)", path, rc);
return rc; return rc;
}
key = key_create_or_update(make_key_ref(keyring[id], 1), key = key_create_or_update(make_key_ref(keyring[id], 1),
"asymmetric", "asymmetric",
NULL, NULL,
data, data,
rc, size,
((KEY_POS_ALL & ~KEY_POS_SETATTR) | ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ), KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA); KEY_ALLOC_NOT_IN_QUOTA);
...@@ -139,6 +143,6 @@ int __init integrity_load_x509(const unsigned int id, const char *path) ...@@ -139,6 +143,6 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
key_ref_to_ptr(key)->description, path); key_ref_to_ptr(key)->description, path);
key_ref_put(key); key_ref_put(key);
} }
kfree(data); vfree(data);
return 0; return 0;
} }
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#define EVM_INIT_HMAC 0x0001 #define EVM_INIT_HMAC 0x0001
#define EVM_INIT_X509 0x0002 #define EVM_INIT_X509 0x0002
#define EVM_SETUP 0x80000000 /* userland has signaled key load */
#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP)
extern int evm_initialized; extern int evm_initialized;
extern char *evm_hmac; extern char *evm_hmac;
......
...@@ -80,7 +80,7 @@ static struct shash_desc *init_desc(char type) ...@@ -80,7 +80,7 @@ static struct shash_desc *init_desc(char type)
if (type == EVM_XATTR_HMAC) { if (type == EVM_XATTR_HMAC) {
if (!(evm_initialized & EVM_INIT_HMAC)) { if (!(evm_initialized & EVM_INIT_HMAC)) {
pr_err("HMAC key is not set\n"); pr_err_once("HMAC key is not set\n");
return ERR_PTR(-ENOKEY); return ERR_PTR(-ENOKEY);
} }
tfm = &hmac_tfm; tfm = &hmac_tfm;
......
...@@ -49,6 +49,9 @@ char *evm_config_xattrnames[] = { ...@@ -49,6 +49,9 @@ char *evm_config_xattrnames[] = {
XATTR_NAME_SMACKMMAP, XATTR_NAME_SMACKMMAP,
#endif #endif
#endif #endif
#ifdef CONFIG_SECURITY_APPARMOR
XATTR_NAME_APPARMOR,
#endif
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
XATTR_NAME_IMA, XATTR_NAME_IMA,
#endif #endif
......
...@@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf, ...@@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
if (*ppos != 0) if (*ppos != 0)
return 0; return 0;
sprintf(temp, "%d", evm_initialized); sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP));
rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
return rc; return rc;
...@@ -61,24 +61,29 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf, ...@@ -61,24 +61,29 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
static ssize_t evm_write_key(struct file *file, const char __user *buf, static ssize_t evm_write_key(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char temp[80]; int i, ret;
int i;
if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC)) if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP))
return -EPERM; return -EPERM;
if (count >= sizeof(temp) || count == 0) ret = kstrtoint_from_user(buf, count, 0, &i);
return -EINVAL;
if (copy_from_user(temp, buf, count) != 0)
return -EFAULT;
temp[count] = '\0'; if (ret)
return ret;
if ((sscanf(temp, "%d", &i) != 1) || (i != 1)) /* Reject invalid values */
if (!i || (i & ~EVM_INIT_MASK) != 0)
return -EINVAL; return -EINVAL;
evm_init_key(); if (i & EVM_INIT_HMAC) {
ret = evm_init_key();
if (ret != 0)
return ret;
/* Forbid further writes after the symmetric key is loaded */
i |= EVM_SETUP;
}
evm_initialized |= i;
return count; return count;
} }
......
...@@ -199,55 +199,6 @@ int integrity_kernel_read(struct file *file, loff_t offset, ...@@ -199,55 +199,6 @@ int integrity_kernel_read(struct file *file, loff_t offset,
return ret; return ret;
} }
/*
* integrity_read_file - read entire file content into the buffer
*
* This is function opens a file, allocates the buffer of required
* size, read entire file content to the buffer and closes the file
*
* It is used only by init code.
*
*/
int __init integrity_read_file(const char *path, char **data)
{
struct file *file;
loff_t size;
char *buf;
int rc = -EINVAL;
if (!path || !*path)
return -EINVAL;
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
pr_err("Unable to open file: %s (%d)", path, rc);
return rc;
}
size = i_size_read(file_inode(file));
if (size <= 0)
goto out;
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto out;
}
rc = integrity_kernel_read(file, 0, buf, size);
if (rc == size) {
*data = buf;
} else {
kfree(buf);
if (rc >= 0)
rc = -EIO;
}
out:
fput(file);
return rc;
}
/* /*
* integrity_load_keys - load integrity keys hook * integrity_load_keys - load integrity keys hook
* *
......
...@@ -199,42 +199,59 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -199,42 +199,59 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
const char *filename = file->f_path.dentry->d_name.name; const char *filename = file->f_path.dentry->d_name.name;
int result = 0; int result = 0;
int length;
void *tmpbuf;
u64 i_version;
struct { struct {
struct ima_digest_data hdr; struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE]; char digest[IMA_MAX_DIGEST_SIZE];
} hash; } hash;
if (!(iint->flags & IMA_COLLECTED)) { if (iint->flags & IMA_COLLECTED)
u64 i_version = file_inode(file)->i_version;
if (file->f_flags & O_DIRECT) {
audit_cause = "failed(directio)";
result = -EACCES;
goto out; goto out;
}
/*
* Dectecting file change is based on i_version. On filesystems
* which do not support i_version, support is limited to an initial
* measurement/appraisal/audit.
*/
i_version = file_inode(file)->i_version;
hash.hdr.algo = algo; hash.hdr.algo = algo;
result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : /* Initialize hash digest to 0's in case of failure */
ima_calc_buffer_hash(buf, size, &hash.hdr); memset(&hash.digest, 0, sizeof(hash.digest));
if (!result) {
int length = sizeof(hash.hdr) + hash.hdr.length; if (buf)
void *tmpbuf = krealloc(iint->ima_hash, length, result = ima_calc_buffer_hash(buf, size, &hash.hdr);
GFP_NOFS); else
if (tmpbuf) { result = ima_calc_file_hash(file, &hash.hdr);
if (result && result != -EBADF && result != -EINVAL)
goto out;
length = sizeof(hash.hdr) + hash.hdr.length;
tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
if (!tmpbuf) {
result = -ENOMEM;
goto out;
}
iint->ima_hash = tmpbuf; iint->ima_hash = tmpbuf;
memcpy(iint->ima_hash, &hash, length); memcpy(iint->ima_hash, &hash, length);
iint->version = i_version; iint->version = i_version;
/* Possibly temporary failure due to type of read (eg. O_DIRECT) */
if (!result)
iint->flags |= IMA_COLLECTED; iint->flags |= IMA_COLLECTED;
} else
result = -ENOMEM;
}
}
out: out:
if (result) if (result) {
if (file->f_flags & O_DIRECT)
audit_cause = "failed(directio)";
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
filename, "collect_data", audit_cause, filename, "collect_data", audit_cause,
result, 0); result, 0);
}
return result; return result;
} }
...@@ -278,7 +295,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, ...@@ -278,7 +295,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
} }
result = ima_store_template(entry, violation, inode, filename, pcr); result = ima_store_template(entry, violation, inode, filename, pcr);
if (!result || result == -EEXIST) { if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
iint->flags |= IMA_MEASURED; iint->flags |= IMA_MEASURED;
iint->measured_pcrs |= (0x1 << pcr); iint->measured_pcrs |= (0x1 << pcr);
} }
......
...@@ -40,7 +40,7 @@ __setup("ima_appraise=", default_appraise_setup); ...@@ -40,7 +40,7 @@ __setup("ima_appraise=", default_appraise_setup);
*/ */
bool is_ima_appraise_enabled(void) bool is_ima_appraise_enabled(void)
{ {
return (ima_appraise & IMA_APPRAISE_ENFORCE) ? 1 : 0; return ima_appraise & IMA_APPRAISE_ENFORCE;
} }
/* /*
...@@ -405,7 +405,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, ...@@ -405,7 +405,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL; return -EINVAL;
ima_reset_appraise_flags(d_backing_inode(dentry), ima_reset_appraise_flags(d_backing_inode(dentry),
(xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); xvalue->type == EVM_IMA_XATTR_DIGSIG);
result = 0; result = 0;
} }
return result; return result;
......
...@@ -441,6 +441,16 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) ...@@ -441,6 +441,16 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
loff_t i_size; loff_t i_size;
int rc; int rc;
/*
* For consistency, fail file's opened with the O_DIRECT flag on
* filesystems mounted with/without DAX option.
*/
if (file->f_flags & O_DIRECT) {
hash->length = hash_digest_size[ima_hash_algo];
hash->algo = ima_hash_algo;
return -EINVAL;
}
i_size = i_size_read(file_inode(file)); i_size = i_size_read(file_inode(file));
if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
......
...@@ -32,7 +32,7 @@ bool ima_canonical_fmt; ...@@ -32,7 +32,7 @@ bool ima_canonical_fmt;
static int __init default_canonical_fmt_setup(char *str) static int __init default_canonical_fmt_setup(char *str)
{ {
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
ima_canonical_fmt = 1; ima_canonical_fmt = true;
#endif #endif
return 1; return 1;
} }
...@@ -429,10 +429,10 @@ static int ima_release_policy(struct inode *inode, struct file *file) ...@@ -429,10 +429,10 @@ static int ima_release_policy(struct inode *inode, struct file *file)
} }
ima_update_policy(); ima_update_policy();
#ifndef CONFIG_IMA_WRITE_POLICY #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
securityfs_remove(ima_policy); securityfs_remove(ima_policy);
ima_policy = NULL; ima_policy = NULL;
#else #elif defined(CONFIG_IMA_WRITE_POLICY)
clear_bit(IMA_FS_BUSY, &ima_fs_flags); clear_bit(IMA_FS_BUSY, &ima_fs_flags);
#endif #endif
return 0; return 0;
......
...@@ -51,6 +51,8 @@ static int __init hash_setup(char *str) ...@@ -51,6 +51,8 @@ static int __init hash_setup(char *str)
ima_hash_algo = HASH_ALGO_SHA1; ima_hash_algo = HASH_ALGO_SHA1;
else if (strncmp(str, "md5", 3) == 0) else if (strncmp(str, "md5", 3) == 0)
ima_hash_algo = HASH_ALGO_MD5; ima_hash_algo = HASH_ALGO_MD5;
else
return 1;
goto out; goto out;
} }
...@@ -60,6 +62,8 @@ static int __init hash_setup(char *str) ...@@ -60,6 +62,8 @@ static int __init hash_setup(char *str)
break; break;
} }
} }
if (i == HASH_ALGO__LAST)
return 1;
out: out:
hash_setup_done = 1; hash_setup_done = 1;
return 1; return 1;
...@@ -235,11 +239,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size, ...@@ -235,11 +239,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
hash_algo = ima_get_hash_algo(xattr_value, xattr_len); hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
rc = ima_collect_measurement(iint, file, buf, size, hash_algo); rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
if (rc != 0) { if (rc != 0 && rc != -EBADF && rc != -EINVAL)
if (file->f_flags & O_DIRECT)
rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
goto out_digsig; goto out_digsig;
}
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename); pathname = ima_d_path(&file->f_path, &pathbuf, filename);
...@@ -247,12 +248,14 @@ static int process_measurement(struct file *file, char *buf, loff_t size, ...@@ -247,12 +248,14 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
if (action & IMA_MEASURE) if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname, ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr); xattr_value, xattr_len, pcr);
if (action & IMA_APPRAISE_SUBMASK) if (rc == 0 && (action & IMA_APPRAISE_SUBMASK))
rc = ima_appraise_measurement(func, iint, file, pathname, rc = ima_appraise_measurement(func, iint, file, pathname,
xattr_value, xattr_len, opened); xattr_value, xattr_len, opened);
if (action & IMA_AUDIT) if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname); ima_audit_measurement(iint, pathname);
if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
rc = 0;
out_digsig: out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
!(iint->flags & IMA_NEW_FILE)) !(iint->flags & IMA_NEW_FILE))
...@@ -359,12 +362,12 @@ void ima_post_path_mknod(struct dentry *dentry) ...@@ -359,12 +362,12 @@ void ima_post_path_mknod(struct dentry *dentry)
*/ */
int ima_read_file(struct file *file, enum kernel_read_file_id read_id) int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
{ {
bool sig_enforce = is_module_sig_enforced();
if (!file && read_id == READING_MODULE) { if (!file && read_id == READING_MODULE) {
#ifndef CONFIG_MODULE_SIG_FORCE if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) &&
if ((ima_appraise & IMA_APPRAISE_MODULES) &&
(ima_appraise & IMA_APPRAISE_ENFORCE)) (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES; /* INTEGRITY_UNKNOWN */ return -EACCES; /* INTEGRITY_UNKNOWN */
#endif
return 0; /* We rely on module signature checking */ return 0; /* We rely on module signature checking */
} }
return 0; return 0;
...@@ -406,6 +409,10 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, ...@@ -406,6 +409,10 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */ if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */
return 0; return 0;
/* permit signed certs */
if (!file && read_id == READING_X509_CERTIFICATE)
return 0;
if (!file || !buf || size == 0) { /* should never happen */ if (!file || !buf || size == 0) { /* should never happen */
if (ima_appraise & IMA_APPRAISE_ENFORCE) if (ima_appraise & IMA_APPRAISE_ENFORCE)
return -EACCES; return -EACCES;
......
...@@ -196,9 +196,9 @@ static int __init policy_setup(char *str) ...@@ -196,9 +196,9 @@ static int __init policy_setup(char *str)
if ((strcmp(p, "tcb") == 0) && !ima_policy) if ((strcmp(p, "tcb") == 0) && !ima_policy)
ima_policy = DEFAULT_TCB; ima_policy = DEFAULT_TCB;
else if (strcmp(p, "appraise_tcb") == 0) else if (strcmp(p, "appraise_tcb") == 0)
ima_use_appraise_tcb = 1; ima_use_appraise_tcb = true;
else if (strcmp(p, "secure_boot") == 0) else if (strcmp(p, "secure_boot") == 0)
ima_use_secure_boot = 1; ima_use_secure_boot = true;
} }
return 1; return 1;
...@@ -207,7 +207,7 @@ __setup("ima_policy=", policy_setup); ...@@ -207,7 +207,7 @@ __setup("ima_policy=", policy_setup);
static int __init default_appraise_policy_setup(char *str) static int __init default_appraise_policy_setup(char *str)
{ {
ima_use_appraise_tcb = 1; ima_use_appraise_tcb = true;
return 1; return 1;
} }
__setup("ima_appraise_tcb", default_appraise_policy_setup); __setup("ima_appraise_tcb", default_appraise_policy_setup);
......
...@@ -120,8 +120,6 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); ...@@ -120,8 +120,6 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
int integrity_kernel_read(struct file *file, loff_t offset, int integrity_kernel_read(struct file *file, loff_t offset,
void *addr, unsigned long count); void *addr, unsigned long count);
int __init integrity_read_file(const char *path, char **data);
#define INTEGRITY_KEYRING_EVM 0 #define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_IMA 1 #define INTEGRITY_KEYRING_IMA 1
#define INTEGRITY_KEYRING_MODULE 2 #define INTEGRITY_KEYRING_MODULE 2
......
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