mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
ima: Make it independent from 'integrity' LSM
Make the 'ima' LSM independent from the 'integrity' LSM by introducing IMA own integrity metadata (ima_iint_cache structure, with IMA-specific fields from the integrity_iint_cache structure), and by managing it directly from the 'ima' LSM. Create ima_iint.c and introduce the same integrity metadata management functions found in iint.c (renamed with ima_). However, instead of putting metadata in an rbtree, reserve space from IMA in the inode security blob for a pointer, and introduce the ima_inode_set_iint()/ima_inode_get_iint() primitives to store/retrieve that pointer. This improves search time from logarithmic to constant. Consequently, don't include the inode pointer as field in the ima_iint_cache structure, since the association with the inode is clear. Since the inode field is missing in ima_iint_cache, pass the extra inode parameter to ima_get_verity_digest(). Prefer storing the pointer instead of the entire ima_iint_cache structure, to avoid too much memory pressure. Use the same mechanism as before, a cache named ima_iint_cache (renamed from iint_cache), to quickly allocate a new ima_iint_cache structure when requested by the IMA policy. Create the new ima_iint_cache in ima_iintcache_init(), called by init_ima_lsm(), during the initialization of the 'ima' LSM. And, register ima_inode_free_security() to free the ima_iint_cache structure, if exists. Replace integrity_iint_cache with ima_iint_cache in various places of the IMA code. Also, replace integrity_inode_get() and integrity_iint_find(), respectively with ima_inode_get() and ima_iint_find(). Finally, move the remaining IMA-specific flags to security/integrity/ima/ima.h, since they are now unnecessary in the common integrity layer. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
parent
75a323e604
commit
4de2f084fb
@ -4,7 +4,7 @@
|
||||
# Measurement Architecture(IMA).
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IMA) += ima.o
|
||||
obj-$(CONFIG_IMA) += ima.o ima_iint.o
|
||||
|
||||
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
|
||||
ima_policy.o ima_template.o ima_template_lib.o
|
||||
|
@ -60,7 +60,7 @@ extern const char boot_aggregate_name[];
|
||||
|
||||
/* IMA event related data */
|
||||
struct ima_event_data {
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
struct file *file;
|
||||
const unsigned char *filename;
|
||||
struct evm_ima_xattr_data *xattr_value;
|
||||
@ -119,6 +119,107 @@ struct ima_kexec_hdr {
|
||||
u64 count;
|
||||
};
|
||||
|
||||
/* IMA iint action cache flags */
|
||||
#define IMA_MEASURE 0x00000001
|
||||
#define IMA_MEASURED 0x00000002
|
||||
#define IMA_APPRAISE 0x00000004
|
||||
#define IMA_APPRAISED 0x00000008
|
||||
/*#define IMA_COLLECT 0x00000010 do not use this flag */
|
||||
#define IMA_COLLECTED 0x00000020
|
||||
#define IMA_AUDIT 0x00000040
|
||||
#define IMA_AUDITED 0x00000080
|
||||
#define IMA_HASH 0x00000100
|
||||
#define IMA_HASHED 0x00000200
|
||||
|
||||
/* IMA iint policy rule cache flags */
|
||||
#define IMA_NONACTION_FLAGS 0xff000000
|
||||
#define IMA_DIGSIG_REQUIRED 0x01000000
|
||||
#define IMA_PERMIT_DIRECTIO 0x02000000
|
||||
#define IMA_NEW_FILE 0x04000000
|
||||
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
|
||||
#define IMA_MODSIG_ALLOWED 0x20000000
|
||||
#define IMA_CHECK_BLACKLIST 0x40000000
|
||||
#define IMA_VERITY_REQUIRED 0x80000000
|
||||
|
||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
||||
IMA_HASHED | IMA_COLLECTED | \
|
||||
IMA_APPRAISED_SUBMASK)
|
||||
|
||||
/* IMA iint subaction appraise cache flags */
|
||||
#define IMA_FILE_APPRAISE 0x00001000
|
||||
#define IMA_FILE_APPRAISED 0x00002000
|
||||
#define IMA_MMAP_APPRAISE 0x00004000
|
||||
#define IMA_MMAP_APPRAISED 0x00008000
|
||||
#define IMA_BPRM_APPRAISE 0x00010000
|
||||
#define IMA_BPRM_APPRAISED 0x00020000
|
||||
#define IMA_READ_APPRAISE 0x00040000
|
||||
#define IMA_READ_APPRAISED 0x00080000
|
||||
#define IMA_CREDS_APPRAISE 0x00100000
|
||||
#define IMA_CREDS_APPRAISED 0x00200000
|
||||
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
|
||||
IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \
|
||||
IMA_CREDS_APPRAISE)
|
||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
|
||||
IMA_CREDS_APPRAISED)
|
||||
|
||||
/* IMA iint cache atomic_flags */
|
||||
#define IMA_CHANGE_XATTR 0
|
||||
#define IMA_UPDATE_XATTR 1
|
||||
#define IMA_CHANGE_ATTR 2
|
||||
#define IMA_DIGSIG 3
|
||||
#define IMA_MUST_MEASURE 4
|
||||
|
||||
/* IMA integrity metadata associated with an inode */
|
||||
struct ima_iint_cache {
|
||||
struct mutex mutex; /* protects: version, flags, digest */
|
||||
u64 version; /* track inode changes */
|
||||
unsigned long flags;
|
||||
unsigned long measured_pcrs;
|
||||
unsigned long atomic_flags;
|
||||
unsigned long real_ino;
|
||||
dev_t real_dev;
|
||||
enum integrity_status ima_file_status:4;
|
||||
enum integrity_status ima_mmap_status:4;
|
||||
enum integrity_status ima_bprm_status:4;
|
||||
enum integrity_status ima_read_status:4;
|
||||
enum integrity_status ima_creds_status:4;
|
||||
struct ima_digest_data *ima_hash;
|
||||
};
|
||||
|
||||
extern struct lsm_blob_sizes ima_blob_sizes;
|
||||
|
||||
static inline struct ima_iint_cache *
|
||||
ima_inode_get_iint(const struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache **iint_sec;
|
||||
|
||||
if (unlikely(!inode->i_security))
|
||||
return NULL;
|
||||
|
||||
iint_sec = inode->i_security + ima_blob_sizes.lbs_inode;
|
||||
return *iint_sec;
|
||||
}
|
||||
|
||||
static inline void ima_inode_set_iint(const struct inode *inode,
|
||||
struct ima_iint_cache *iint)
|
||||
{
|
||||
struct ima_iint_cache **iint_sec;
|
||||
|
||||
if (unlikely(!inode->i_security))
|
||||
return;
|
||||
|
||||
iint_sec = inode->i_security + ima_blob_sizes.lbs_inode;
|
||||
*iint_sec = iint;
|
||||
}
|
||||
|
||||
struct ima_iint_cache *ima_iint_find(struct inode *inode);
|
||||
struct ima_iint_cache *ima_inode_get(struct inode *inode);
|
||||
void ima_inode_free(struct inode *inode);
|
||||
void __init ima_iintcache_init(void);
|
||||
|
||||
extern const int read_idmap[];
|
||||
|
||||
#ifdef CONFIG_HAVE_IMA_KEXEC
|
||||
@ -152,8 +253,8 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
|
||||
struct ima_template_entry *entry);
|
||||
int ima_calc_boot_aggregate(struct ima_digest_data *hash);
|
||||
void ima_add_violation(struct file *file, const unsigned char *filename,
|
||||
struct integrity_iint_cache *iint,
|
||||
const char *op, const char *cause);
|
||||
struct ima_iint_cache *iint, const char *op,
|
||||
const char *cause);
|
||||
int ima_init_crypto(void);
|
||||
void ima_putc(struct seq_file *m, void *data, int datalen);
|
||||
void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
|
||||
@ -267,10 +368,10 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct ima_template_desc **template_desc,
|
||||
const char *func_data, unsigned int *allowed_algos);
|
||||
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
|
||||
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, void *buf, loff_t size,
|
||||
enum hash_algo algo, struct modsig *modsig);
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
|
||||
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
void *buf, loff_t size, enum hash_algo algo,
|
||||
struct modsig *modsig);
|
||||
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
@ -280,7 +381,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
const char *eventname, enum ima_hooks func,
|
||||
int pcr, const char *func_data,
|
||||
bool buf_hash, u8 *digest, size_t digest_len);
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
void ima_audit_measurement(struct ima_iint_cache *iint,
|
||||
const unsigned char *filename);
|
||||
int ima_alloc_init_template(struct ima_event_data *event_data,
|
||||
struct ima_template_entry **entry,
|
||||
@ -318,17 +419,16 @@ int ima_policy_show(struct seq_file *m, void *v);
|
||||
#define IMA_APPRAISE_KEXEC 0x40
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE
|
||||
int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr);
|
||||
int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig);
|
||||
int ima_must_appraise(struct mnt_idmap *idmap, 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,
|
||||
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file);
|
||||
enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func);
|
||||
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len);
|
||||
@ -337,14 +437,14 @@ int ima_read_xattr(struct dentry *dentry,
|
||||
void __init init_ima_appraise_lsm(const struct lsm_id *lsmid);
|
||||
|
||||
#else
|
||||
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
static inline int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
struct ima_iint_cache *iint,
|
||||
struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
@ -361,14 +461,13 @@ static inline int ima_must_appraise(struct mnt_idmap *idmap,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ima_update_xattr(struct integrity_iint_cache *iint,
|
||||
static inline void ima_update_xattr(struct ima_iint_cache *iint,
|
||||
struct file *file)
|
||||
{
|
||||
}
|
||||
|
||||
static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache
|
||||
*iint,
|
||||
enum ima_hooks func)
|
||||
static inline enum integrity_status
|
||||
ima_get_cache_status(struct ima_iint_cache *iint, enum ima_hooks func)
|
||||
{
|
||||
return INTEGRITY_UNKNOWN;
|
||||
}
|
||||
|
@ -131,8 +131,8 @@ int ima_store_template(struct ima_template_entry *entry,
|
||||
* value is invalidated.
|
||||
*/
|
||||
void ima_add_violation(struct file *file, const unsigned char *filename,
|
||||
struct integrity_iint_cache *iint,
|
||||
const char *op, const char *cause)
|
||||
struct ima_iint_cache *iint, const char *op,
|
||||
const char *cause)
|
||||
{
|
||||
struct ima_template_entry *entry;
|
||||
struct inode *inode = file_inode(file);
|
||||
@ -201,7 +201,8 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
|
||||
allowed_algos);
|
||||
}
|
||||
|
||||
static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
static bool ima_get_verity_digest(struct ima_iint_cache *iint,
|
||||
struct inode *inode,
|
||||
struct ima_max_digest_data *hash)
|
||||
{
|
||||
enum hash_algo alg;
|
||||
@ -211,7 +212,7 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
* On failure, 'measure' policy rules will result in a file data
|
||||
* hash containing 0's.
|
||||
*/
|
||||
digest_len = fsverity_get_digest(iint->inode, hash->digest, NULL, &alg);
|
||||
digest_len = fsverity_get_digest(inode, hash->digest, NULL, &alg);
|
||||
if (digest_len == 0)
|
||||
return false;
|
||||
|
||||
@ -237,9 +238,9 @@ static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Return 0 on success, error code otherwise
|
||||
*/
|
||||
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, void *buf, loff_t size,
|
||||
enum hash_algo algo, struct modsig *modsig)
|
||||
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
void *buf, loff_t size, enum hash_algo algo,
|
||||
struct modsig *modsig)
|
||||
{
|
||||
const char *audit_cause = "failed";
|
||||
struct inode *inode = file_inode(file);
|
||||
@ -280,7 +281,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
memset(&hash.digest, 0, sizeof(hash.digest));
|
||||
|
||||
if (iint->flags & IMA_VERITY_REQUIRED) {
|
||||
if (!ima_get_verity_digest(iint, &hash)) {
|
||||
if (!ima_get_verity_digest(iint, inode, &hash)) {
|
||||
audit_cause = "no-verity-digest";
|
||||
result = -ENODATA;
|
||||
}
|
||||
@ -338,8 +339,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Must be called with iint->mutex held.
|
||||
*/
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc)
|
||||
@ -382,7 +383,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
ima_free_template_entry(entry);
|
||||
}
|
||||
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
void ima_audit_measurement(struct ima_iint_cache *iint,
|
||||
const unsigned char *filename)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
@ -84,8 +84,7 @@ int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int ima_fix_xattr(struct dentry *dentry,
|
||||
struct integrity_iint_cache *iint)
|
||||
static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint)
|
||||
{
|
||||
int rc, offset;
|
||||
u8 algo = iint->ima_hash->algo;
|
||||
@ -106,7 +105,7 @@ static int ima_fix_xattr(struct dentry *dentry,
|
||||
}
|
||||
|
||||
/* Return specific func appraised cached result */
|
||||
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func)
|
||||
{
|
||||
switch (func) {
|
||||
@ -126,7 +125,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
}
|
||||
}
|
||||
|
||||
static void ima_set_cache_status(struct integrity_iint_cache *iint,
|
||||
static void ima_set_cache_status(struct ima_iint_cache *iint,
|
||||
enum ima_hooks func,
|
||||
enum integrity_status status)
|
||||
{
|
||||
@ -152,8 +151,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
|
||||
}
|
||||
}
|
||||
|
||||
static void ima_cache_flags(struct integrity_iint_cache *iint,
|
||||
enum ima_hooks func)
|
||||
static void ima_cache_flags(struct ima_iint_cache *iint, enum ima_hooks func)
|
||||
{
|
||||
switch (func) {
|
||||
case MMAP_CHECK:
|
||||
@ -276,7 +274,7 @@ static int calc_file_id_hash(enum evm_ima_xattr_type type,
|
||||
*
|
||||
* Return 0 on success, error code otherwise.
|
||||
*/
|
||||
static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
|
||||
static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct evm_ima_xattr_data *xattr_value, int xattr_len,
|
||||
enum integrity_status *status, const char **cause)
|
||||
{
|
||||
@ -443,7 +441,7 @@ static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
|
||||
*
|
||||
* Returns -EPERM if the hash is blacklisted.
|
||||
*/
|
||||
int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
int ima_check_blacklist(struct ima_iint_cache *iint,
|
||||
const struct modsig *modsig, int pcr)
|
||||
{
|
||||
enum hash_algo hash_algo;
|
||||
@ -477,8 +475,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
|
||||
*
|
||||
* Return 0 on success, error code otherwise
|
||||
*/
|
||||
int ima_appraise_measurement(enum ima_hooks func,
|
||||
struct integrity_iint_cache *iint,
|
||||
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, const struct modsig *modsig)
|
||||
@ -603,7 +600,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
||||
/*
|
||||
* ima_update_xattr - update 'security.ima' hash value
|
||||
*/
|
||||
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
||||
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
int rc = 0;
|
||||
@ -640,7 +637,7 @@ static void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, int ia_valid)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
int action;
|
||||
|
||||
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|
||||
@ -648,7 +645,7 @@ static void ima_inode_post_setattr(struct mnt_idmap *idmap,
|
||||
return;
|
||||
|
||||
action = ima_must_appraise(idmap, inode, MAY_ACCESS, POST_SETATTR);
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint) {
|
||||
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
|
||||
if (!action)
|
||||
@ -674,12 +671,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
||||
|
||||
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
iint->measured_pcrs = 0;
|
||||
|
142
security/integrity/ima/ima_iint.c
Normal file
142
security/integrity/ima/ima_iint.c
Normal file
@ -0,0 +1,142 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2008 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Mimi Zohar <zohar@us.ibm.com>
|
||||
*
|
||||
* File: ima_iint.c
|
||||
* - implements the IMA hook: ima_inode_free
|
||||
* - cache integrity information in the inode security blob
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "ima.h"
|
||||
|
||||
static struct kmem_cache *ima_iint_cache __ro_after_init;
|
||||
|
||||
/**
|
||||
* ima_iint_find - Return the iint associated with an inode
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Return the IMA integrity information (iint) associated with an inode, if the
|
||||
* inode was processed by IMA.
|
||||
*
|
||||
* Return: Found iint or NULL.
|
||||
*/
|
||||
struct ima_iint_cache *ima_iint_find(struct inode *inode)
|
||||
{
|
||||
if (!IS_IMA(inode))
|
||||
return NULL;
|
||||
|
||||
return ima_inode_get_iint(inode);
|
||||
}
|
||||
|
||||
#define IMA_MAX_NESTING (FILESYSTEM_MAX_STACK_DEPTH + 1)
|
||||
|
||||
/*
|
||||
* It is not clear that IMA should be nested at all, but as long is it measures
|
||||
* files both on overlayfs and on underlying fs, we need to annotate the iint
|
||||
* mutex to avoid lockdep false positives related to IMA + overlayfs.
|
||||
* See ovl_lockdep_annotate_inode_mutex_key() for more details.
|
||||
*/
|
||||
static inline void ima_iint_lockdep_annotate(struct ima_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lock_class_key ima_iint_mutex_key[IMA_MAX_NESTING];
|
||||
|
||||
int depth = inode->i_sb->s_stack_depth;
|
||||
|
||||
if (WARN_ON_ONCE(depth < 0 || depth >= IMA_MAX_NESTING))
|
||||
depth = 0;
|
||||
|
||||
lockdep_set_class(&iint->mutex, &ima_iint_mutex_key[depth]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ima_iint_init_always(struct ima_iint_cache *iint,
|
||||
struct inode *inode)
|
||||
{
|
||||
iint->ima_hash = NULL;
|
||||
iint->version = 0;
|
||||
iint->flags = 0UL;
|
||||
iint->atomic_flags = 0UL;
|
||||
iint->ima_file_status = INTEGRITY_UNKNOWN;
|
||||
iint->ima_mmap_status = INTEGRITY_UNKNOWN;
|
||||
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
|
||||
iint->ima_read_status = INTEGRITY_UNKNOWN;
|
||||
iint->ima_creds_status = INTEGRITY_UNKNOWN;
|
||||
iint->measured_pcrs = 0;
|
||||
mutex_init(&iint->mutex);
|
||||
ima_iint_lockdep_annotate(iint, inode);
|
||||
}
|
||||
|
||||
static void ima_iint_free(struct ima_iint_cache *iint)
|
||||
{
|
||||
kfree(iint->ima_hash);
|
||||
mutex_destroy(&iint->mutex);
|
||||
kmem_cache_free(ima_iint_cache, iint);
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_inode_get - Find or allocate an iint associated with an inode
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Find an iint associated with an inode, and allocate a new one if not found.
|
||||
* Caller must lock i_mutex.
|
||||
*
|
||||
* Return: An iint on success, NULL on error.
|
||||
*/
|
||||
struct ima_iint_cache *ima_inode_get(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint)
|
||||
return iint;
|
||||
|
||||
iint = kmem_cache_alloc(ima_iint_cache, GFP_NOFS);
|
||||
if (!iint)
|
||||
return NULL;
|
||||
|
||||
ima_iint_init_always(iint, inode);
|
||||
|
||||
inode->i_flags |= S_IMA;
|
||||
ima_inode_set_iint(inode, iint);
|
||||
|
||||
return iint;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_inode_free - Called on inode free
|
||||
* @inode: Pointer to the inode
|
||||
*
|
||||
* Free the iint associated with an inode.
|
||||
*/
|
||||
void ima_inode_free(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!IS_IMA(inode))
|
||||
return;
|
||||
|
||||
iint = ima_iint_find(inode);
|
||||
ima_inode_set_iint(inode, NULL);
|
||||
|
||||
ima_iint_free(iint);
|
||||
}
|
||||
|
||||
static void ima_iint_init_once(void *foo)
|
||||
{
|
||||
struct ima_iint_cache *iint = (struct ima_iint_cache *)foo;
|
||||
|
||||
memset(iint, 0, sizeof(*iint));
|
||||
}
|
||||
|
||||
void __init ima_iintcache_init(void)
|
||||
{
|
||||
ima_iint_cache =
|
||||
kmem_cache_create("ima_iint_cache", sizeof(struct ima_iint_cache),
|
||||
0, SLAB_PANIC, ima_iint_init_once);
|
||||
}
|
@ -44,7 +44,7 @@ static int __init ima_add_boot_aggregate(void)
|
||||
static const char op[] = "add_boot_aggregate";
|
||||
const char *audit_cause = "ENOMEM";
|
||||
struct ima_template_entry *entry;
|
||||
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
|
||||
struct ima_iint_cache tmp_iint, *iint = &tmp_iint;
|
||||
struct ima_event_data event_data = { .iint = iint,
|
||||
.filename = boot_aggregate_name };
|
||||
struct ima_max_digest_data hash;
|
||||
|
@ -114,7 +114,7 @@ static int mmap_violation_check(enum ima_hooks func, struct file *file,
|
||||
*
|
||||
*/
|
||||
static void ima_rdwr_violation_check(struct file *file,
|
||||
struct integrity_iint_cache *iint,
|
||||
struct ima_iint_cache *iint,
|
||||
int must_measure,
|
||||
char **pathbuf,
|
||||
const char **pathname,
|
||||
@ -127,7 +127,7 @@ static void ima_rdwr_violation_check(struct file *file,
|
||||
if (mode & FMODE_WRITE) {
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
|
||||
if (!iint)
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
/* IMA_MEASURE is set from reader side */
|
||||
if (iint && test_bit(IMA_MUST_MEASURE,
|
||||
&iint->atomic_flags))
|
||||
@ -153,7 +153,7 @@ static void ima_rdwr_violation_check(struct file *file,
|
||||
"invalid_pcr", "open_writers");
|
||||
}
|
||||
|
||||
static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
||||
static void ima_check_last_writer(struct ima_iint_cache *iint,
|
||||
struct inode *inode, struct file *file)
|
||||
{
|
||||
fmode_t mode = file->f_mode;
|
||||
@ -192,12 +192,12 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
||||
static void ima_file_free(struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
||||
return;
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -209,7 +209,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
||||
enum ima_hooks func)
|
||||
{
|
||||
struct inode *backing_inode, *inode = file_inode(file);
|
||||
struct integrity_iint_cache *iint = NULL;
|
||||
struct ima_iint_cache *iint = NULL;
|
||||
struct ima_template_desc *template_desc = NULL;
|
||||
char *pathbuf = NULL;
|
||||
char filename[NAME_MAX];
|
||||
@ -248,7 +248,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
||||
inode_lock(inode);
|
||||
|
||||
if (action) {
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
@ -564,11 +564,11 @@ static int ima_file_check(struct file *file, int mask)
|
||||
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct integrity_iint_cache *iint = NULL, tmp_iint;
|
||||
struct ima_iint_cache *iint = NULL, tmp_iint;
|
||||
int rc, hash_algo;
|
||||
|
||||
if (ima_policy_flag) {
|
||||
iint = integrity_iint_find(inode);
|
||||
iint = ima_iint_find(inode);
|
||||
if (iint)
|
||||
mutex_lock(&iint->mutex);
|
||||
}
|
||||
@ -578,7 +578,6 @@ static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
memset(&tmp_iint, 0, sizeof(tmp_iint));
|
||||
tmp_iint.inode = inode;
|
||||
mutex_init(&tmp_iint.mutex);
|
||||
|
||||
rc = ima_collect_measurement(&tmp_iint, file, NULL, 0,
|
||||
@ -688,7 +687,7 @@ static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
struct inode *inode)
|
||||
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
int must_appraise;
|
||||
|
||||
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
|
||||
@ -700,7 +699,7 @@ static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
return;
|
||||
|
||||
/* Nothing to do if we can't allocate memory */
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -719,7 +718,7 @@ static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
|
||||
*/
|
||||
static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_iint_cache *iint;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int must_appraise;
|
||||
|
||||
@ -732,7 +731,7 @@ static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
return;
|
||||
|
||||
/* Nothing to do if we can't allocate memory */
|
||||
iint = integrity_inode_get(inode);
|
||||
iint = ima_inode_get(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
@ -935,7 +934,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap,
|
||||
int ret = 0;
|
||||
const char *audit_cause = "ENOMEM";
|
||||
struct ima_template_entry *entry = NULL;
|
||||
struct integrity_iint_cache iint = {};
|
||||
struct ima_iint_cache iint = {};
|
||||
struct ima_event_data event_data = {.iint = &iint,
|
||||
.filename = eventname,
|
||||
.buf = buf,
|
||||
@ -1172,6 +1171,7 @@ static struct security_hook_list ima_hooks[] __ro_after_init = {
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
LSM_HOOK_INIT(kernel_module_request, ima_kernel_module_request),
|
||||
#endif
|
||||
LSM_HOOK_INIT(inode_free_security, ima_inode_free),
|
||||
};
|
||||
|
||||
static const struct lsm_id ima_lsmid = {
|
||||
@ -1181,15 +1181,21 @@ static const struct lsm_id ima_lsmid = {
|
||||
|
||||
static int __init init_ima_lsm(void)
|
||||
{
|
||||
ima_iintcache_init();
|
||||
security_add_hooks(ima_hooks, ARRAY_SIZE(ima_hooks), &ima_lsmid);
|
||||
init_ima_appraise_lsm(&ima_lsmid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
|
||||
.lbs_inode = sizeof(struct ima_iint_cache *),
|
||||
};
|
||||
|
||||
DEFINE_LSM(ima) = {
|
||||
.name = "ima",
|
||||
.init = init_ima_lsm,
|
||||
.order = LSM_ORDER_LAST,
|
||||
.blobs = &ima_blob_sizes,
|
||||
};
|
||||
|
||||
late_initcall(init_ima); /* Start IMA after the TPM is available */
|
||||
|
@ -49,7 +49,7 @@
|
||||
#define DONT_HASH 0x0200
|
||||
|
||||
#define INVALID_PCR(a) (((a) < 0) || \
|
||||
(a) >= (sizeof_field(struct integrity_iint_cache, measured_pcrs) * 8))
|
||||
(a) >= (sizeof_field(struct ima_iint_cache, measured_pcrs) * 8))
|
||||
|
||||
int ima_policy_flag;
|
||||
static int temp_ima_appraise;
|
||||
|
@ -20,59 +20,6 @@
|
||||
#include <linux/audit.h>
|
||||
#include <linux/lsm_hooks.h>
|
||||
|
||||
/* iint action cache flags */
|
||||
#define IMA_MEASURE 0x00000001
|
||||
#define IMA_MEASURED 0x00000002
|
||||
#define IMA_APPRAISE 0x00000004
|
||||
#define IMA_APPRAISED 0x00000008
|
||||
/*#define IMA_COLLECT 0x00000010 do not use this flag */
|
||||
#define IMA_COLLECTED 0x00000020
|
||||
#define IMA_AUDIT 0x00000040
|
||||
#define IMA_AUDITED 0x00000080
|
||||
#define IMA_HASH 0x00000100
|
||||
#define IMA_HASHED 0x00000200
|
||||
|
||||
/* iint policy rule cache flags */
|
||||
#define IMA_NONACTION_FLAGS 0xff000000
|
||||
#define IMA_DIGSIG_REQUIRED 0x01000000
|
||||
#define IMA_PERMIT_DIRECTIO 0x02000000
|
||||
#define IMA_NEW_FILE 0x04000000
|
||||
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
|
||||
#define IMA_MODSIG_ALLOWED 0x20000000
|
||||
#define IMA_CHECK_BLACKLIST 0x40000000
|
||||
#define IMA_VERITY_REQUIRED 0x80000000
|
||||
|
||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \
|
||||
IMA_HASHED | IMA_COLLECTED | \
|
||||
IMA_APPRAISED_SUBMASK)
|
||||
|
||||
/* iint subaction appraise cache flags */
|
||||
#define IMA_FILE_APPRAISE 0x00001000
|
||||
#define IMA_FILE_APPRAISED 0x00002000
|
||||
#define IMA_MMAP_APPRAISE 0x00004000
|
||||
#define IMA_MMAP_APPRAISED 0x00008000
|
||||
#define IMA_BPRM_APPRAISE 0x00010000
|
||||
#define IMA_BPRM_APPRAISED 0x00020000
|
||||
#define IMA_READ_APPRAISE 0x00040000
|
||||
#define IMA_READ_APPRAISED 0x00080000
|
||||
#define IMA_CREDS_APPRAISE 0x00100000
|
||||
#define IMA_CREDS_APPRAISED 0x00200000
|
||||
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
|
||||
IMA_BPRM_APPRAISE | IMA_READ_APPRAISE | \
|
||||
IMA_CREDS_APPRAISE)
|
||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
|
||||
IMA_CREDS_APPRAISED)
|
||||
|
||||
/* iint cache atomic_flags */
|
||||
#define IMA_CHANGE_XATTR 0
|
||||
#define IMA_UPDATE_XATTR 1
|
||||
#define IMA_CHANGE_ATTR 2
|
||||
#define IMA_DIGSIG 3
|
||||
#define IMA_MUST_MEASURE 4
|
||||
|
||||
enum evm_ima_xattr_type {
|
||||
IMA_XATTR_DIGEST = 0x01,
|
||||
EVM_XATTR_HMAC,
|
||||
|
Loading…
Reference in New Issue
Block a user