Commit aef4892a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'integrity-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity subsystem updates from Mimi Zohar:

 - Limit the allowed hash algorithms when writing security.ima xattrs or
   verifying them, based on the IMA policy and the configured hash
   algorithms.

 - Return the calculated "critical data" measurement hash and size to
   avoid code duplication. (Preparatory change for a proposed LSM.)

 - and a single patch to address a compiler warning.

* tag 'integrity-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  IMA: reject unknown hash algorithms in ima_get_hash_algo
  IMA: prevent SETXATTR_CHECK policy rules with unavailable algorithms
  IMA: introduce a new policy option func=SETXATTR_CHECK
  IMA: add a policy option to restrict xattr hash algorithms on appraisal
  IMA: add support to restrict the hash algorithms used for file appraisal
  IMA: block writes of the security.ima xattr with unsupported algorithms
  IMA: remove the dependency on CRYPTO_MD5
  ima: Add digest and digest_len params to the functions to measure a buffer
  ima: Return int in the functions to measure a buffer
  ima: Introduce ima_get_current_hash_algo()
  IMA: remove -Wmissing-prototypes warning
parents b55060d7 cb181da1
...@@ -27,12 +27,13 @@ Description: ...@@ -27,12 +27,13 @@ Description:
lsm: [[subj_user=] [subj_role=] [subj_type=] lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]] [obj_user=] [obj_role=] [obj_type=]]
option: [[appraise_type=]] [template=] [permit_directio] option: [[appraise_type=]] [template=] [permit_directio]
[appraise_flag=] [keyrings=] [appraise_flag=] [appraise_algos=] [keyrings=]
base: base:
func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK] [FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK] [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
[KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA] [KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA]
[SETXATTR_CHECK]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND] mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC] [[^]MAY_EXEC]
fsmagic:= hex value fsmagic:= hex value
...@@ -55,6 +56,10 @@ Description: ...@@ -55,6 +56,10 @@ Description:
label:= [selinux]|[kernel_info]|[data_label] label:= [selinux]|[kernel_info]|[data_label]
data_label:= a unique string used for grouping and limiting critical data. data_label:= a unique string used for grouping and limiting critical data.
For example, "selinux" to measure critical data for SELinux. For example, "selinux" to measure critical data for SELinux.
appraise_algos:= comma-separated list of hash algorithms
For example, "sha256,sha512" to only accept to appraise
files where the security.ima xattr was hashed with one
of these two algorithms.
default policy: default policy:
# PROC_SUPER_MAGIC # PROC_SUPER_MAGIC
...@@ -134,3 +139,9 @@ Description: ...@@ -134,3 +139,9 @@ Description:
keys added to .builtin_trusted_keys or .ima keyring: keys added to .builtin_trusted_keys or .ima keyring:
measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima
Example of the special SETXATTR_CHECK appraise rule, that
restricts the hash algorithms allowed when writing to the
security.ima xattr of a file:
appraise func=SETXATTR_CHECK appraise_algos=sha256,sha384,sha512
...@@ -136,7 +136,8 @@ static void dm_ima_measure_data(const char *event_name, const void *buf, size_t ...@@ -136,7 +136,8 @@ static void dm_ima_measure_data(const char *event_name, const void *buf, size_t
if (noio) if (noio)
noio_flag = memalloc_noio_save(); noio_flag = memalloc_noio_save();
ima_measure_critical_data(DM_NAME, event_name, buf, buf_len, false); ima_measure_critical_data(DM_NAME, event_name, buf, buf_len,
false, NULL, 0);
if (noio) if (noio)
memalloc_noio_restore(noio_flag); memalloc_noio_restore(noio_flag);
......
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <crypto/hash_info.h>
struct linux_binprm; struct linux_binprm;
#ifdef CONFIG_IMA #ifdef CONFIG_IMA
extern enum hash_algo ima_get_current_hash_algo(void);
extern int ima_bprm_check(struct linux_binprm *bprm); 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);
extern void ima_post_create_tmpfile(struct user_namespace *mnt_userns, extern void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
...@@ -33,10 +35,10 @@ extern void ima_post_path_mknod(struct user_namespace *mnt_userns, ...@@ -33,10 +35,10 @@ extern void ima_post_path_mknod(struct user_namespace *mnt_userns,
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size); extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size); extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size); extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
extern void ima_measure_critical_data(const char *event_label, extern int ima_measure_critical_data(const char *event_label,
const char *event_name, const char *event_name,
const void *buf, size_t buf_len, const void *buf, size_t buf_len,
bool hash); bool hash, u8 *digest, size_t digest_len);
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
extern void ima_appraise_parse_cmdline(void); extern void ima_appraise_parse_cmdline(void);
...@@ -64,6 +66,11 @@ static inline const char * const *arch_get_ima_policy(void) ...@@ -64,6 +66,11 @@ static inline const char * const *arch_get_ima_policy(void)
#endif #endif
#else #else
static inline enum hash_algo ima_get_current_hash_algo(void)
{
return HASH_ALGO__LAST;
}
static inline int ima_bprm_check(struct linux_binprm *bprm) static inline int ima_bprm_check(struct linux_binprm *bprm)
{ {
return 0; return 0;
...@@ -137,10 +144,14 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size ...@@ -137,10 +144,14 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size
static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {} static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
static inline void ima_measure_critical_data(const char *event_label, static inline int ima_measure_critical_data(const char *event_label,
const char *event_name, const char *event_name,
const void *buf, size_t buf_len, const void *buf, size_t buf_len,
bool hash) {} bool hash, u8 *digest,
size_t digest_len)
{
return -ENOENT;
}
#endif /* CONFIG_IMA */ #endif /* CONFIG_IMA */
......
...@@ -6,7 +6,6 @@ config IMA ...@@ -6,7 +6,6 @@ config IMA
select SECURITYFS select SECURITYFS
select CRYPTO select CRYPTO
select CRYPTO_HMAC select CRYPTO_HMAC
select CRYPTO_MD5
select CRYPTO_SHA1 select CRYPTO_SHA1
select CRYPTO_HASH_INFO select CRYPTO_HASH_INFO
select TCG_TPM if HAS_IOMEM && !UML select TCG_TPM if HAS_IOMEM && !UML
......
...@@ -46,8 +46,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 }; ...@@ -46,8 +46,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
/* current content of the policy */ /* current content of the policy */
extern int ima_policy_flag; extern int ima_policy_flag;
/* bitset of digests algorithms allowed in the setxattr hook */
extern atomic_t ima_setxattr_allowed_hash_algorithms;
/* set during initialization */ /* set during initialization */
extern int ima_hash_algo; extern int ima_hash_algo __ro_after_init;
extern int ima_sha1_idx __ro_after_init; extern int ima_sha1_idx __ro_after_init;
extern int ima_hash_algo_idx __ro_after_init; extern int ima_hash_algo_idx __ro_after_init;
extern int ima_extra_slots __ro_after_init; extern int ima_extra_slots __ro_after_init;
...@@ -198,6 +201,7 @@ static inline unsigned int ima_hash_key(u8 *digest) ...@@ -198,6 +201,7 @@ static inline unsigned int ima_hash_key(u8 *digest)
hook(KEXEC_CMDLINE, kexec_cmdline) \ hook(KEXEC_CMDLINE, kexec_cmdline) \
hook(KEY_CHECK, key) \ hook(KEY_CHECK, key) \
hook(CRITICAL_DATA, critical_data) \ hook(CRITICAL_DATA, critical_data) \
hook(SETXATTR_CHECK, setxattr_check) \
hook(MAX_CHECK, none) hook(MAX_CHECK, none)
#define __ima_hook_enumify(ENUM, str) ENUM, #define __ima_hook_enumify(ENUM, str) ENUM,
...@@ -254,7 +258,7 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -254,7 +258,7 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask, const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr, enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc, struct ima_template_desc **template_desc,
const char *func_data); const char *func_data, unsigned int *allowed_algos);
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint, int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size, struct file *file, void *buf, loff_t size,
...@@ -264,11 +268,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, ...@@ -264,11 +268,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value, struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr, int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc); struct ima_template_desc *template_desc);
void process_buffer_measurement(struct user_namespace *mnt_userns, int process_buffer_measurement(struct user_namespace *mnt_userns,
struct inode *inode, const void *buf, int size, struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func, const char *eventname, enum ima_hooks func,
int pcr, const char *func_data, int pcr, const char *func_data,
bool buf_hash); bool buf_hash, u8 *digest, size_t digest_len);
void ima_audit_measurement(struct integrity_iint_cache *iint, void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename); const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data, int ima_alloc_init_template(struct ima_event_data *event_data,
...@@ -285,10 +289,10 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -285,10 +289,10 @@ int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func, const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr, int mask, int flags, int *pcr,
struct ima_template_desc **template_desc, struct ima_template_desc **template_desc,
const char *func_data); const char *func_data, unsigned int *allowed_algos);
void ima_init_policy(void); void ima_init_policy(void);
void ima_update_policy(void); void ima_update_policy(void);
void ima_update_policy_flag(void); void ima_update_policy_flags(void);
ssize_t ima_parse_add_rule(char *); ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void); void ima_delete_rules(void);
int ima_check_policy(void); int ima_check_policy(void);
...@@ -319,7 +323,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -319,7 +323,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
enum ima_hooks func); enum ima_hooks func);
enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len); int xattr_len);
int ima_read_xattr(struct dentry *dentry, int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value); struct evm_ima_xattr_data **xattr_value);
......
...@@ -172,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -172,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* @pcr: pointer filled in if matched measure policy sets pcr= * @pcr: pointer filled in if matched measure policy sets pcr=
* @template_desc: pointer filled in if matched measure policy sets template= * @template_desc: pointer filled in if matched measure policy sets template=
* @func_data: func specific data, may be NULL * @func_data: func specific data, may be NULL
* @allowed_algos: allowlist of hash algorithms for the IMA xattr
* *
* The policy is defined in terms of keypairs: * The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic= * subj=, obj=, type=, func=, mask=, fsmagic=
...@@ -188,14 +189,15 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -188,14 +189,15 @@ int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask, const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr, enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc, struct ima_template_desc **template_desc,
const char *func_data) const char *func_data, unsigned int *allowed_algos)
{ {
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
flags &= ima_policy_flag; flags &= ima_policy_flag;
return ima_match_policy(mnt_userns, inode, cred, secid, func, mask, return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
flags, pcr, template_desc, func_data); flags, pcr, template_desc, func_data,
allowed_algos);
} }
/* /*
......
...@@ -77,8 +77,9 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -77,8 +77,9 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
return 0; return 0;
security_task_getsecid_subj(current, &secid); security_task_getsecid_subj(current, &secid);
return ima_match_policy(mnt_userns, inode, current_cred(), secid, func, return ima_match_policy(mnt_userns, inode, current_cred(), secid,
mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL); func, mask, IMA_APPRAISE | IMA_HASH, NULL,
NULL, NULL, NULL);
} }
static int ima_fix_xattr(struct dentry *dentry, static int ima_fix_xattr(struct dentry *dentry,
...@@ -171,7 +172,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, ...@@ -171,7 +172,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
} }
} }
enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len) int xattr_len)
{ {
struct signature_v2_hdr *sig; struct signature_v2_hdr *sig;
...@@ -184,7 +185,8 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, ...@@ -184,7 +185,8 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
switch (xattr_value->type) { switch (xattr_value->type) {
case EVM_IMA_XATTR_DIGSIG: case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value; sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof(*sig)) if (sig->version != 2 || xattr_len <= sizeof(*sig)
|| sig->hash_algo >= HASH_ALGO__LAST)
return ima_hash_algo; return ima_hash_algo;
return sig->hash_algo; return sig->hash_algo;
break; break;
...@@ -357,7 +359,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, ...@@ -357,7 +359,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE)) if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(&init_user_ns, NULL, digest, digestsize, process_buffer_measurement(&init_user_ns, NULL, digest, digestsize,
"blacklisted-hash", NONE, "blacklisted-hash", NONE,
pcr, NULL, false); pcr, NULL, false, NULL, 0);
} }
return rc; return rc;
...@@ -575,6 +577,66 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) ...@@ -575,6 +577,66 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
clear_bit(IMA_DIGSIG, &iint->atomic_flags); clear_bit(IMA_DIGSIG, &iint->atomic_flags);
} }
/**
* validate_hash_algo() - Block setxattr with unsupported hash algorithms
* @dentry: object of the setxattr()
* @xattr_value: userland supplied xattr value
* @xattr_value_len: length of xattr_value
*
* The xattr value is mapped to its hash algorithm, and this algorithm
* must be built in the kernel for the setxattr to be allowed.
*
* Emit an audit message when the algorithm is invalid.
*
* Return: 0 on success, else an error.
*/
static int validate_hash_algo(struct dentry *dentry,
const struct evm_ima_xattr_data *xattr_value,
size_t xattr_value_len)
{
char *path = NULL, *pathbuf = NULL;
enum hash_algo xattr_hash_algo;
const char *errmsg = "unavailable-hash-algorithm";
unsigned int allowed_hashes;
xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
if (allowed_hashes) {
/* success if the algorithm is allowed in the ima policy */
if (allowed_hashes & (1U << xattr_hash_algo))
return 0;
/*
* We use a different audit message when the hash algorithm
* is denied by a policy rule, instead of not being built
* in the kernel image
*/
errmsg = "denied-hash-algorithm";
} else {
if (likely(xattr_hash_algo == ima_hash_algo))
return 0;
/* allow any xattr using an algorithm built in the kernel */
if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0, 0))
return 0;
}
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!pathbuf)
return -EACCES;
path = dentry_path(dentry, pathbuf, PATH_MAX);
integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
"set_data", errmsg, -EACCES, 0);
kfree(pathbuf);
return -EACCES;
}
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len) const void *xattr_value, size_t xattr_value_len)
{ {
...@@ -592,9 +654,11 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, ...@@ -592,9 +654,11 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG); digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
} }
if (result == 1 || evm_revalidate_status(xattr_name)) { if (result == 1 || evm_revalidate_status(xattr_name)) {
result = validate_hash_algo(dentry, xvalue, xattr_value_len);
if (result)
return result;
ima_reset_appraise_flags(d_backing_inode(dentry), digsig); ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
if (result == 1)
result = 0;
} }
return result; return result;
} }
......
...@@ -62,5 +62,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, ...@@ -62,5 +62,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
*/ */
process_buffer_measurement(&init_user_ns, NULL, payload, payload_len, process_buffer_measurement(&init_user_ns, NULL, payload, payload_len,
keyring->description, KEY_CHECK, 0, keyring->description, KEY_CHECK, 0,
keyring->description, false); keyring->description, false, NULL, 0);
} }
...@@ -154,7 +154,8 @@ int __init ima_init(void) ...@@ -154,7 +154,8 @@ int __init ima_init(void)
ima_init_key_queue(); ima_init_key_queue();
ima_measure_critical_data("kernel_info", "kernel_version", ima_measure_critical_data("kernel_info", "kernel_version",
UTS_RELEASE, strlen(UTS_RELEASE), false); UTS_RELEASE, strlen(UTS_RELEASE), false,
NULL, 0);
return rc; return rc;
} }
...@@ -35,7 +35,7 @@ int ima_appraise = IMA_APPRAISE_ENFORCE; ...@@ -35,7 +35,7 @@ int ima_appraise = IMA_APPRAISE_ENFORCE;
int ima_appraise; int ima_appraise;
#endif #endif
int ima_hash_algo = HASH_ALGO_SHA1; int __ro_after_init ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done; static int hash_setup_done;
static struct notifier_block ima_lsm_policy_notifier = { static struct notifier_block ima_lsm_policy_notifier = {
...@@ -76,6 +76,11 @@ static int __init hash_setup(char *str) ...@@ -76,6 +76,11 @@ static int __init hash_setup(char *str)
} }
__setup("ima_hash=", hash_setup); __setup("ima_hash=", hash_setup);
enum hash_algo ima_get_current_hash_algo(void)
{
return ima_hash_algo;
}
/* Prevent mmap'ing a file execute that is already mmap'ed write */ /* Prevent mmap'ing a file execute that is already mmap'ed write */
static int mmap_violation_check(enum ima_hooks func, struct file *file, static int mmap_violation_check(enum ima_hooks func, struct file *file,
char **pathbuf, const char **pathname, char **pathbuf, const char **pathname,
...@@ -210,6 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -210,6 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
int xattr_len = 0; int xattr_len = 0;
bool violation_check; bool violation_check;
enum hash_algo hash_algo; enum hash_algo hash_algo;
unsigned int allowed_algos = 0;
if (!ima_policy_flag || !S_ISREG(inode->i_mode)) if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0; return 0;
...@@ -219,7 +225,8 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -219,7 +225,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
* Included is the appraise submask. * Included is the appraise submask.
*/ */
action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid, action = ima_get_action(file_mnt_user_ns(file), inode, cred, secid,
mask, func, &pcr, &template_desc, NULL); mask, func, &pcr, &template_desc, NULL,
&allowed_algos);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE)); (ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check) if (!action && !violation_check)
...@@ -356,6 +363,16 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -356,6 +363,16 @@ static int process_measurement(struct file *file, const struct cred *cred,
if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))
rc = 0; rc = 0;
/* Ensure the digest was generated using an allowed algorithm */
if (rc == 0 && must_appraise && allowed_algos != 0 &&
(allowed_algos & (1U << hash_algo)) == 0) {
rc = -EACCES;
integrity_audit_msg(AUDIT_INTEGRITY_DATA, file_inode(file),
pathname, "collect_data",
"denied-hash-algorithm", rc, 0);
}
out_locked: out_locked:
if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) && if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&
!(iint->flags & IMA_NEW_FILE)) !(iint->flags & IMA_NEW_FILE))
...@@ -433,7 +450,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) ...@@ -433,7 +450,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
inode = file_inode(vma->vm_file); inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode, action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK, current_cred(), secid, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL); &pcr, &template, NULL, NULL);
/* Is the mmap'ed file in policy? */ /* Is the mmap'ed file in policy? */
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK))) if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
...@@ -822,7 +839,7 @@ int ima_post_load_data(char *buf, loff_t size, ...@@ -822,7 +839,7 @@ int ima_post_load_data(char *buf, loff_t size,
return 0; return 0;
} }
/* /**
* process_buffer_measurement - Measure the buffer or the buffer data hash * process_buffer_measurement - Measure the buffer or the buffer data hash
* @mnt_userns: user namespace of the mount the inode was found from * @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode associated with the object being measured (NULL for KEY_CHECK) * @inode: inode associated with the object being measured (NULL for KEY_CHECK)
...@@ -833,14 +850,20 @@ int ima_post_load_data(char *buf, loff_t size, ...@@ -833,14 +850,20 @@ int ima_post_load_data(char *buf, loff_t size,
* @pcr: pcr to extend the measurement * @pcr: pcr to extend the measurement
* @func_data: func specific data, may be NULL * @func_data: func specific data, may be NULL
* @buf_hash: measure buffer data hash * @buf_hash: measure buffer data hash
* @digest: buffer digest will be written to
* @digest_len: buffer length
* *
* Based on policy, either the buffer data or buffer data hash is measured * Based on policy, either the buffer data or buffer data hash is measured
*
* Return: 0 if the buffer has been successfully measured, 1 if the digest
* has been written to the passed location but not added to a measurement entry,
* a negative value otherwise.
*/ */
void process_buffer_measurement(struct user_namespace *mnt_userns, int process_buffer_measurement(struct user_namespace *mnt_userns,
struct inode *inode, const void *buf, int size, struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func, const char *eventname, enum ima_hooks func,
int pcr, const char *func_data, int pcr, const char *func_data,
bool buf_hash) bool buf_hash, u8 *digest, size_t digest_len)
{ {
int ret = 0; int ret = 0;
const char *audit_cause = "ENOMEM"; const char *audit_cause = "ENOMEM";
...@@ -861,8 +884,11 @@ void process_buffer_measurement(struct user_namespace *mnt_userns, ...@@ -861,8 +884,11 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
int action = 0; int action = 0;
u32 secid; u32 secid;
if (!ima_policy_flag) if (digest && digest_len < digest_hash_len)
return; return -EINVAL;
if (!ima_policy_flag && !digest)
return -ENOENT;
template = ima_template_desc_buf(); template = ima_template_desc_buf();
if (!template) { if (!template) {
...@@ -882,9 +908,9 @@ void process_buffer_measurement(struct user_namespace *mnt_userns, ...@@ -882,9 +908,9 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
security_task_getsecid_subj(current, &secid); security_task_getsecid_subj(current, &secid);
action = ima_get_action(mnt_userns, inode, current_cred(), action = ima_get_action(mnt_userns, inode, current_cred(),
secid, 0, func, &pcr, &template, secid, 0, func, &pcr, &template,
func_data); func_data, NULL);
if (!(action & IMA_MEASURE)) if (!(action & IMA_MEASURE) && !digest)
return; return -ENOENT;
} }
if (!pcr) if (!pcr)
...@@ -914,6 +940,12 @@ void process_buffer_measurement(struct user_namespace *mnt_userns, ...@@ -914,6 +940,12 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
event_data.buf_len = digest_hash_len; event_data.buf_len = digest_hash_len;
} }
if (digest)
memcpy(digest, iint.ima_hash->digest, digest_hash_len);
if (!ima_policy_flag || (func && !(action & IMA_MEASURE)))
return 1;
ret = ima_alloc_init_template(&event_data, &entry, template); ret = ima_alloc_init_template(&event_data, &entry, template);
if (ret < 0) { if (ret < 0) {
audit_cause = "alloc_entry"; audit_cause = "alloc_entry";
...@@ -932,7 +964,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns, ...@@ -932,7 +964,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
func_measure_str(func), func_measure_str(func),
audit_cause, ret, 0, ret); audit_cause, ret, 0, ret);
return; return ret;
} }
/** /**
...@@ -956,7 +988,7 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) ...@@ -956,7 +988,7 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file), process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file),
buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0, buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0,
NULL, false); NULL, false, NULL, 0);
fdput(f); fdput(f);
} }
...@@ -967,23 +999,30 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) ...@@ -967,23 +999,30 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
* @buf: pointer to buffer data * @buf: pointer to buffer data
* @buf_len: length of buffer data (in bytes) * @buf_len: length of buffer data (in bytes)
* @hash: measure buffer data hash * @hash: measure buffer data hash
* @digest: buffer digest will be written to
* @digest_len: buffer length
* *
* Measure data critical to the integrity of the kernel into the IMA log * Measure data critical to the integrity of the kernel into the IMA log
* and extend the pcr. Examples of critical data could be various data * and extend the pcr. Examples of critical data could be various data
* structures, policies, and states stored in kernel memory that can * structures, policies, and states stored in kernel memory that can
* impact the integrity of the system. * impact the integrity of the system.
*
* Return: 0 if the buffer has been successfully measured, 1 if the digest
* has been written to the passed location but not added to a measurement entry,
* a negative value otherwise.
*/ */
void ima_measure_critical_data(const char *event_label, int ima_measure_critical_data(const char *event_label,
const char *event_name, const char *event_name,
const void *buf, size_t buf_len, const void *buf, size_t buf_len,
bool hash) bool hash, u8 *digest, size_t digest_len)
{ {
if (!event_name || !event_label || !buf || !buf_len) if (!event_name || !event_label || !buf || !buf_len)
return; return -ENOPARAM;
process_buffer_measurement(&init_user_ns, NULL, buf, buf_len, event_name, return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len,
CRITICAL_DATA, 0, event_label, event_name, CRITICAL_DATA, 0,
hash); event_label, hash, digest,
digest_len);
} }
EXPORT_SYMBOL_GPL(ima_measure_critical_data); EXPORT_SYMBOL_GPL(ima_measure_critical_data);
...@@ -1013,7 +1052,7 @@ static int __init init_ima(void) ...@@ -1013,7 +1052,7 @@ static int __init init_ima(void)
pr_warn("Couldn't register LSM notifier, error %d\n", error); pr_warn("Couldn't register LSM notifier, error %d\n", error);
if (!error) if (!error)
ima_update_policy_flag(); ima_update_policy_flags();
return error; return error;
} }
......
...@@ -21,7 +21,7 @@ struct key *ima_blacklist_keyring; ...@@ -21,7 +21,7 @@ struct key *ima_blacklist_keyring;
/* /*
* Allocate the IMA blacklist keyring * Allocate the IMA blacklist keyring
*/ */
__init int ima_mok_init(void) static __init int ima_mok_init(void)
{ {
struct key_restriction *restriction; struct key_restriction *restriction;
......
This diff is collapsed.
...@@ -165,7 +165,7 @@ void ima_process_queued_keys(void) ...@@ -165,7 +165,7 @@ void ima_process_queued_keys(void)
entry->keyring_name, entry->keyring_name,
KEY_CHECK, 0, KEY_CHECK, 0,
entry->keyring_name, entry->keyring_name,
false); false, NULL, 0);
list_del(&entry->list); list_del(&entry->list);
ima_free_key_entry(entry); ima_free_key_entry(entry);
} }
......
...@@ -86,7 +86,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state) ...@@ -86,7 +86,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
} }
ima_measure_critical_data("selinux", "selinux-state", ima_measure_critical_data("selinux", "selinux-state",
state_str, strlen(state_str), false); state_str, strlen(state_str), false,
NULL, 0);
kfree(state_str); kfree(state_str);
...@@ -103,7 +104,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state) ...@@ -103,7 +104,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
} }
ima_measure_critical_data("selinux", "selinux-policy-hash", ima_measure_critical_data("selinux", "selinux-policy-hash",
policy, policy_len, true); policy, policy_len, true,
NULL, 0);
vfree(policy); vfree(policy);
} }
......
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