Skip to content

Commit

Permalink
IMA: support for per policy rule template formats
Browse files Browse the repository at this point in the history
Admins may wish to log different measurements using different IMA
templates. Add support for overriding the default template on a per-rule
basis.

Inspired-by: Roberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: Matthew Garrett <mjg59@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
  • Loading branch information
Matthew Garrett authored and Mimi Zohar committed Jun 19, 2019
1 parent 8c65578 commit 19453ce
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 29 deletions.
5 changes: 3 additions & 2 deletions Documentation/ABI/testing/ima_policy
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ Description:
[euid=] [fowner=] [fsname=]]
lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]]
option: [[appraise_type=]] [permit_directio]

option: [[appraise_type=]] [template=] [permit_directio]
base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
Expand All @@ -38,6 +37,8 @@ Description:
fowner:= decimal value
lsm: are LSM specific
option: appraise_type:= [imasig]
template:= name of a defined IMA template type
(eg, ima-ng). Only valid when action is "measure".
pcr:= decimal value

default policy:
Expand Down
16 changes: 12 additions & 4 deletions security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
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);
int template_desc_init_fields(const char *template_fmt,
const struct ima_template_field ***fields,
int *num_fields);
struct ima_template_desc *ima_template_desc_current(void);
struct ima_template_desc *lookup_template_desc(const char *name);
int ima_restore_measurement_entry(struct ima_template_entry *entry);
int ima_restore_measurement_list(loff_t bufsize, void *buf);
int ima_measurements_show(struct seq_file *m, void *v);
Expand Down Expand Up @@ -195,19 +199,22 @@ enum ima_hooks {

/* LIM API function definitions */
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
int mask, enum ima_hooks func, int *pcr);
int mask, enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc);
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);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int pcr);
int xattr_len, int pcr,
struct ima_template_desc *template_desc);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_entry **entry);
struct ima_template_entry **entry,
struct ima_template_desc *template_desc);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode,
const unsigned char *filename, int pcr);
Expand All @@ -216,7 +223,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);

/* IMA policy related functions */
int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
enum ima_hooks func, int mask, int flags, int *pcr);
enum ima_hooks func, int mask, int flags, int *pcr,
struct ima_template_desc **template_desc);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flag(void);
Expand Down
24 changes: 17 additions & 7 deletions security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ void ima_free_template_entry(struct ima_template_entry *entry)
* ima_alloc_init_template - create and initialize a new template entry
*/
int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_entry **entry)
struct ima_template_entry **entry,
struct ima_template_desc *desc)
{
struct ima_template_desc *template_desc = ima_template_desc_current();
struct ima_template_desc *template_desc;
int i, result = 0;

if (desc)
template_desc = desc;
else
template_desc = ima_template_desc_current();

*entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
sizeof(struct ima_field_data), GFP_NOFS);
if (!*entry)
Expand Down Expand Up @@ -143,7 +149,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
/* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations);

result = ima_alloc_init_template(&event_data, &entry);
result = ima_alloc_init_template(&event_data, &entry, NULL);
if (result < 0) {
result = -ENOMEM;
goto err_out;
Expand All @@ -166,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* MAY_APPEND)
* @func: caller identifier
* @pcr: pointer filled in if matched measure policy sets pcr=
* @template_desc: pointer filled in if matched measure policy sets template=
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
Expand All @@ -178,13 +185,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
*
*/
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
int mask, enum ima_hooks func, int *pcr)
int mask, enum ima_hooks func, int *pcr,
struct ima_template_desc **template_desc)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;

flags &= ima_policy_flag;

return ima_match_policy(inode, cred, secid, func, mask, flags, pcr);
return ima_match_policy(inode, cred, secid, func, mask, flags, pcr,
template_desc);
}

/*
Expand Down Expand Up @@ -279,7 +288,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
void ima_store_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int pcr)
int xattr_len, int pcr,
struct ima_template_desc *template_desc)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "ENOMEM";
Expand All @@ -296,7 +306,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
if (iint->measured_pcrs & (0x1 << pcr))
return;

result = ima_alloc_init_template(&event_data, &entry);
result = ima_alloc_init_template(&event_data, &entry, template_desc);
if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0);
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_appraise.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)

security_task_getsecid(current, &secid);
return ima_match_policy(inode, current_cred(), secid, func, mask,
IMA_APPRAISE | IMA_HASH, NULL);
IMA_APPRAISE | IMA_HASH, NULL, NULL);
}

static int ima_fix_xattr(struct dentry *dentry,
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ static int __init ima_add_boot_aggregate(void)
}
}

result = ima_alloc_init_template(&event_data, &entry);
result = ima_alloc_init_template(&event_data, &entry, NULL);
if (result < 0) {
audit_cause = "alloc_entry";
goto err_out;
Expand Down
9 changes: 5 additions & 4 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc;
struct ima_template_desc *template_desc = NULL;
char *pathbuf = NULL;
char filename[NAME_MAX];
const char *pathname = NULL;
Expand All @@ -217,7 +217,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
action = ima_get_action(inode, cred, secid, mask, func, &pcr);
action = ima_get_action(inode, cred, secid, mask, func, &pcr,
&template_desc);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
Expand Down Expand Up @@ -304,7 +305,6 @@ static int process_measurement(struct file *file, const struct cred *cred,
goto out_locked;
}

template_desc = ima_template_desc_current();
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
/* read 'security.ima' */
Expand All @@ -321,7 +321,8 @@ static int process_measurement(struct file *file, const struct cred *cred,

if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr);
xattr_value, xattr_len, pcr,
template_desc);
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file, pathname,
Expand Down
38 changes: 36 additions & 2 deletions security/integrity/ima/ima_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct ima_rule_entry {
int type; /* audit type */
} lsm[MAX_LSM_RULES];
char *fsname;
struct ima_template_desc *template;
};

/*
Expand Down Expand Up @@ -473,6 +474,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @pcr: set the pcr to extend
* @template_desc: the template that should be used for this rule
*
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
Expand All @@ -482,7 +484,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* than writes so ima_match_policy() is classical RCU candidate.
*/
int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
enum ima_hooks func, int mask, int flags, int *pcr)
enum ima_hooks func, int mask, int flags, int *pcr,
struct ima_template_desc **template_desc)
{
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
Expand Down Expand Up @@ -514,6 +517,11 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
if ((pcr) && (entry->flags & IMA_PCR))
*pcr = entry->pcr;

if (template_desc && entry->template)
*template_desc = entry->template;
else if (template_desc)
*template_desc = ima_template_desc_current();

if (!actmask)
break;
}
Expand Down Expand Up @@ -752,7 +760,7 @@ enum {
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
Opt_appraise_type, Opt_permit_directio,
Opt_pcr, Opt_err
Opt_pcr, Opt_template, Opt_err
};

static const match_table_t policy_tokens = {
Expand Down Expand Up @@ -786,6 +794,7 @@ static const match_table_t policy_tokens = {
{Opt_appraise_type, "appraise_type=%s"},
{Opt_permit_directio, "permit_directio"},
{Opt_pcr, "pcr=%s"},
{Opt_template, "template=%s"},
{Opt_err, NULL}
};

Expand Down Expand Up @@ -839,6 +848,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
char *from;
char *p;
bool uid_token;
struct ima_template_desc *template_desc;
int result = 0;

ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
Expand Down Expand Up @@ -1134,6 +1144,28 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
else
entry->flags |= IMA_PCR;

break;
case Opt_template:
ima_log_string(ab, "template", args[0].from);
if (entry->action != MEASURE) {
result = -EINVAL;
break;
}
template_desc = lookup_template_desc(args[0].from);
if (!template_desc || entry->template) {
result = -EINVAL;
break;
}

/*
* template_desc_init_fields() does nothing if
* the template is already initialised, so
* it's safe to do this unconditionally
*/
template_desc_init_fields(template_desc->fmt,
&(template_desc->fields),
&(template_desc->num_fields));
entry->template = template_desc;
break;
case Opt_err:
ima_log_string(ab, "UNKNOWN", p);
Expand Down Expand Up @@ -1410,6 +1442,8 @@ int ima_policy_show(struct seq_file *m, void *v)
}
}
}
if (entry->template)
seq_printf(m, "template=%s ", entry->template->name);
if (entry->flags & IMA_DIGSIG_REQUIRED)
seq_puts(m, "appraise_type=imasig ");
if (entry->flags & IMA_PERMIT_DIRECTIO)
Expand Down
12 changes: 4 additions & 8 deletions security/integrity/ima/ima_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ static const struct ima_template_field supported_fields[] = {
#define MAX_TEMPLATE_NAME_LEN 15

static struct ima_template_desc *ima_template;
static struct ima_template_desc *lookup_template_desc(const char *name);
static int template_desc_init_fields(const char *template_fmt,
const struct ima_template_field ***fields,
int *num_fields);

static int __init ima_template_setup(char *str)
{
Expand Down Expand Up @@ -108,7 +104,7 @@ static int __init ima_template_fmt_setup(char *str)
}
__setup("ima_template_fmt=", ima_template_fmt_setup);

static struct ima_template_desc *lookup_template_desc(const char *name)
struct ima_template_desc *lookup_template_desc(const char *name)
{
struct ima_template_desc *template_desc;
int found = 0;
Expand Down Expand Up @@ -153,9 +149,9 @@ static int template_fmt_size(const char *template_fmt)
return j + 1;
}

static int template_desc_init_fields(const char *template_fmt,
const struct ima_template_field ***fields,
int *num_fields)
int template_desc_init_fields(const char *template_fmt,
const struct ima_template_field ***fields,
int *num_fields)
{
const char *template_fmt_ptr;
const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
Expand Down

0 comments on commit 19453ce

Please sign in to comment.