Skip to content
Permalink
Browse files
ima: Move policy related variables into ima_namespace
Move variables related to the IMA policy into the ima_namespace. This way
the IMA policy of an IMA namespace can be set and displayed using a
front-end like SecurityFS.

Implement ima_free_policy_rules() that frees the policy rules on
ima_namespace deletion.

Implement ima_ns_from_file() to get the IMA namespace via the user
namespace of the SecurityFS superblock that a file belongs to.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
  • Loading branch information
stefanberger authored and intel-lab-lkp committed Dec 16, 2021
1 parent ad76788 commit 4927ddb1c276a9aa164fced45c2614ec93b5b425
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 142 deletions.
@@ -20,6 +20,7 @@
#include <linux/hash.h>
#include <linux/tpm.h>
#include <linux/audit.h>
#include <linux/user_namespace.h>
#include <crypto/hash_info.h>

#include "../integrity.h"
@@ -43,9 +44,6 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };

#define NR_BANKS(chip) ((chip != NULL) ? chip->nr_allocated_banks : 0)

/* current content of the policy */
extern int ima_policy_flag;

/* bitset of digests algorithms allowed in the setxattr hook */
extern atomic_t ima_setxattr_allowed_hash_algorithms;

@@ -125,6 +123,15 @@ struct ima_namespace {
struct rb_root ns_status_tree;
rwlock_t ns_status_lock;
struct kmem_cache *ns_status_cache;

struct list_head ima_default_rules;
/* ns's policy rules */
struct list_head ima_policy_rules;
struct list_head ima_temp_rules;
/* Pointer to ns's current policy */
struct list_head __rcu *ima_rules;
/* current content of the policy */
int ima_policy_flag;
} __randomize_layout;

extern const int read_idmap[];
@@ -259,7 +266,7 @@ void ima_init_key_queue(void);
bool ima_should_queue_key(void);
bool ima_queue_key(struct key *keyring, const void *payload,
size_t payload_len);
void ima_process_queued_keys(void);
void ima_process_queued_keys(struct ima_namespace *ns);
#else
static inline void ima_init_key_queue(void) {}
static inline bool ima_should_queue_key(void) { return false; }
@@ -270,7 +277,8 @@ static inline void ima_process_queued_keys(void) {}
#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */

/* LIM API function definitions */
int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
int ima_get_action(struct ima_namespace *ns,
struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
@@ -284,7 +292,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig, int pcr,
struct ima_template_desc *template_desc);
int process_buffer_measurement(struct user_namespace *mnt_userns,
int process_buffer_measurement(struct ima_namespace *ns,
struct user_namespace *mnt_userns,
struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *func_data,
@@ -302,17 +311,19 @@ void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);

/* IMA policy related functions */
int ima_match_policy(struct user_namespace *mnt_userns, struct inode *inode,
int ima_match_policy(struct ima_namespace *ns,
struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, enum ima_hooks func,
int mask, int flags, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flags(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
int ima_check_policy(void);
void ima_init_policy(struct ima_namespace *ns);
void ima_update_policy(struct ima_namespace *ns);
void ima_update_policy_flags(struct ima_namespace *ns);
ssize_t ima_parse_add_rule(struct ima_namespace *ns, char *rule);
void ima_delete_rules(struct ima_namespace *ns);
int ima_check_policy(struct ima_namespace *ns);
void ima_free_policy_rules(struct ima_namespace *ns);
void *ima_policy_start(struct seq_file *m, loff_t *pos);
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
@@ -328,14 +339,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_namespace *ns,
struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr);
int ima_appraise_measurement(enum ima_hooks func,
struct integrity_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 user_namespace *mnt_userns, struct inode *inode,
int ima_must_appraise(struct ima_namespace *ns,
struct user_namespace *mnt_userns, 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,
@@ -346,7 +359,8 @@ int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);

#else
static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
static inline int ima_check_blacklist(struct ima_namespace *ns,
struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr)
{
return 0;
@@ -363,7 +377,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
return INTEGRITY_UNKNOWN;
}

static inline int ima_must_appraise(struct user_namespace *mnt_userns,
static inline int ima_must_appraise(struct ima_namespace *ns,
struct user_namespace *mnt_userns,
struct inode *inode, int mask,
enum ima_hooks func)
{
@@ -507,4 +522,15 @@ static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op,
#define POLICY_FILE_FLAGS S_IWUSR
#endif /* CONFIG_IMA_READ_POLICY */

static inline
struct user_namespace *ima_user_ns_from_file(const struct file *filp)
{
return file_inode(filp)->i_sb->s_user_ns;
}

static inline struct ima_namespace *ima_ns_from_file(const struct file *filp)
{
return ima_user_ns_from_file(filp)->ima_ns;
}

#endif /* __LINUX_IMA_H */
@@ -162,6 +162,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,

/**
* ima_get_action - appraise & measure decision based on policy.
* @ns: IMA namespace that has the policy
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: pointer to the inode associated with the object being validated
* @cred: pointer to credentials structure to validate
@@ -185,17 +186,18 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
int ima_get_action(struct user_namespace *mnt_userns, struct inode *inode,
int ima_get_action(struct ima_namespace *ns,
struct user_namespace *mnt_userns, struct inode *inode,
const struct cred *cred, u32 secid, int mask,
enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc,
const char *func_data, unsigned int *allowed_algos)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;

flags &= ima_policy_flag;
flags &= ns->ima_policy_flag;

return ima_match_policy(mnt_userns, inode, cred, secid, func, mask,
return ima_match_policy(ns, mnt_userns, inode, cred, secid, func, mask,
flags, pcr, template_desc, func_data,
allowed_algos);
}
@@ -68,7 +68,8 @@ bool is_ima_appraise_enabled(void)
*
* Return 1 to appraise or hash
*/
int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
int ima_must_appraise(struct ima_namespace *ns,
struct user_namespace *mnt_userns, struct inode *inode,
int mask, enum ima_hooks func)
{
u32 secid;
@@ -77,7 +78,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
return 0;

security_task_getsecid_subj(current, &secid);
return ima_match_policy(mnt_userns, inode, current_cred(), secid,
return ima_match_policy(ns, mnt_userns, inode, current_cred(), secid,
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
NULL, NULL, NULL);
}
@@ -341,7 +342,8 @@ 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_namespace *ns,
struct integrity_iint_cache *iint,
const struct modsig *modsig, int pcr)
{
enum hash_algo hash_algo;
@@ -357,7 +359,8 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,

rc = is_binary_blacklisted(digest, digestsize);
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(&init_user_ns, NULL, digest, digestsize,
process_buffer_measurement(ns, &init_user_ns, NULL,
digest, digestsize,
"blacklisted-hash", NONE,
pcr, NULL, false, NULL, 0);
}
@@ -527,14 +530,16 @@ void ima_inode_post_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
struct ima_namespace *ns = &init_ima_ns;
struct integrity_iint_cache *iint;
int action;

if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !(inode->i_opflags & IOP_XATTR))
return;

action = ima_must_appraise(mnt_userns, inode, MAY_ACCESS, POST_SETATTR);
action = ima_must_appraise(ns, mnt_userns, inode, MAY_ACCESS,
POST_SETATTR);
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
@@ -559,11 +564,12 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
return 0;
}

static void ima_reset_appraise_flags(struct inode *inode, int digsig)
static void ima_reset_appraise_flags(struct ima_namespace *ns,
struct inode *inode, int digsig)
{
struct integrity_iint_cache *iint;

if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
if (!(ns->ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
return;

iint = integrity_iint_find(inode);
@@ -641,6 +647,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
const struct evm_ima_xattr_data *xvalue = xattr_value;
struct ima_namespace *ns = &init_ima_ns;
int digsig = 0;
int result;

@@ -658,18 +665,19 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
if (result)
return result;

ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
ima_reset_appraise_flags(ns, d_backing_inode(dentry), digsig);
}
return result;
}

int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
struct ima_namespace *ns = &init_ima_ns;
int result;

result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1 || evm_revalidate_status(xattr_name)) {
ima_reset_appraise_flags(d_backing_inode(dentry), 0);
ima_reset_appraise_flags(ns, d_backing_inode(dentry), 0);
if (result == 1)
result = 0;
}
@@ -30,6 +30,7 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
const void *payload, size_t payload_len,
unsigned long flags, bool create)
{
struct ima_namespace *ns = get_current_ns();
bool queued = false;

/* Only asymmetric keys are handled by this hook. */
@@ -60,7 +61,8 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
* if the IMA policy is configured to measure a key linked
* to the given keyring.
*/
process_buffer_measurement(&init_user_ns, NULL, payload, payload_len,
process_buffer_measurement(ns, &init_user_ns, NULL,
payload, payload_len,
keyring->description, KEY_CHECK, 0,
keyring->description, false, NULL, 0);
}
@@ -271,7 +271,7 @@ static const struct file_operations ima_ascii_measurements_ops = {
.release = seq_release,
};

static ssize_t ima_read_policy(char *path)
static ssize_t ima_read_policy(struct ima_namespace *ns, char *path)
{
void *data = NULL;
char *datap;
@@ -296,7 +296,7 @@ static ssize_t ima_read_policy(char *path)
datap = data;
while (size > 0 && (p = strsep(&datap, "\n"))) {
pr_debug("rule: %s\n", p);
rc = ima_parse_add_rule(p);
rc = ima_parse_add_rule(ns, p);
if (rc < 0)
break;
size -= rc;
@@ -314,6 +314,7 @@ static ssize_t ima_read_policy(char *path)
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
struct ima_namespace *ns = ima_ns_from_file(file);
char *data;
ssize_t result;

@@ -336,15 +337,15 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
goto out_free;

if (data[0] == '/') {
result = ima_read_policy(data);
result = ima_read_policy(ns, data);
} else if (ima_appraise & IMA_APPRAISE_POLICY) {
pr_err("signed policy file (specified as an absolute pathname) required\n");
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
"policy_update", "signed policy required",
1, 0);
result = -EACCES;
} else {
result = ima_parse_add_rule(data);
result = ima_parse_add_rule(ns, data);
}
mutex_unlock(&ima_write_mutex);
out_free:
@@ -410,11 +411,12 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
static int ima_release_policy(struct inode *inode, struct file *file)
{
const char *cause = valid_policy ? "completed" : "failed";
struct ima_namespace *ns = ima_ns_from_file(file);

if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);

if (valid_policy && ima_check_policy() < 0) {
if (valid_policy && ima_check_policy(ns) < 0) {
cause = "failed";
valid_policy = 0;
}
@@ -424,13 +426,13 @@ static int ima_release_policy(struct inode *inode, struct file *file)
"policy_update", cause, !valid_policy, 0);

if (!valid_policy) {
ima_delete_rules();
ima_delete_rules(ns);
valid_policy = 1;
clear_bit(IMA_FS_BUSY, &ima_fs_flags);
return 0;
}

ima_update_policy();
ima_update_policy(ns);
#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
securityfs_remove(ima_policy);
ima_policy = NULL;
@@ -104,15 +104,15 @@ static int __init ima_add_boot_aggregate(void)
#ifdef CONFIG_IMA_LOAD_X509
void __init ima_load_x509(void)
{
int unset_flags = ima_policy_flag & IMA_APPRAISE;
int unset_flags = init_ima_ns.ima_policy_flag & IMA_APPRAISE;

ima_policy_flag &= ~unset_flags;
init_ima_ns.ima_policy_flag &= ~unset_flags;
integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);

/* load also EVM key to avoid appraisal */
evm_load_x509();

ima_policy_flag |= unset_flags;
init_ima_ns.ima_policy_flag |= unset_flags;
}
#endif

@@ -149,7 +149,7 @@ int __init ima_init(void)
if (rc != 0)
return rc;

ima_init_policy();
ima_init_policy(&init_ima_ns);

rc = ima_fs_init();
if (rc != 0)

0 comments on commit 4927ddb

Please sign in to comment.