Commit 19453ce0 authored by Matthew Garrett's avatar Matthew Garrett Committed by Mimi Zohar

IMA: support for per policy rule template formats

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: default avatarRoberto Sassu <roberto.sassu@huawei.com>
Signed-off-by: default avatarMatthew Garrett <mjg59@google.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent 8c655784
...@@ -24,8 +24,7 @@ Description: ...@@ -24,8 +24,7 @@ Description:
[euid=] [fowner=] [fsname=]] [euid=] [fowner=] [fsname=]]
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=]] [permit_directio] option: [[appraise_type=]] [template=] [permit_directio]
base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK] base: 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]
...@@ -38,6 +37,8 @@ Description: ...@@ -38,6 +37,8 @@ Description:
fowner:= decimal value fowner:= decimal value
lsm: are LSM specific lsm: are LSM specific
option: appraise_type:= [imasig] option: appraise_type:= [imasig]
template:= name of a defined IMA template type
(eg, ima-ng). Only valid when action is "measure".
pcr:= decimal value pcr:= decimal value
default policy: default policy:
......
...@@ -146,7 +146,11 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -146,7 +146,11 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
int ima_init_crypto(void); int ima_init_crypto(void);
void ima_putc(struct seq_file *m, void *data, int datalen); void ima_putc(struct seq_file *m, void *data, int datalen);
void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); 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 *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_entry(struct ima_template_entry *entry);
int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_restore_measurement_list(loff_t bufsize, void *buf);
int ima_measurements_show(struct seq_file *m, void *v); int ima_measurements_show(struct seq_file *m, void *v);
...@@ -195,7 +199,8 @@ enum ima_hooks { ...@@ -195,7 +199,8 @@ enum ima_hooks {
/* LIM API function definitions */ /* LIM API function definitions */
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, 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_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,
...@@ -203,11 +208,13 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -203,11 +208,13 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value, 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, 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,
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, int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode, struct inode *inode,
const unsigned char *filename, int pcr); const unsigned char *filename, int pcr);
...@@ -216,7 +223,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); ...@@ -216,7 +223,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
/* IMA policy related functions */ /* IMA policy related functions */
int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, 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_init_policy(void);
void ima_update_policy(void); void ima_update_policy(void);
void ima_update_policy_flag(void); void ima_update_policy_flag(void);
......
...@@ -38,11 +38,17 @@ void ima_free_template_entry(struct ima_template_entry *entry) ...@@ -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 * ima_alloc_init_template - create and initialize a new template entry
*/ */
int ima_alloc_init_template(struct ima_event_data *event_data, 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; int i, result = 0;
if (desc)
template_desc = desc;
else
template_desc = ima_template_desc_current();
*entry = kzalloc(sizeof(**entry) + template_desc->num_fields * *entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
sizeof(struct ima_field_data), GFP_NOFS); sizeof(struct ima_field_data), GFP_NOFS);
if (!*entry) if (!*entry)
...@@ -143,7 +149,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -143,7 +149,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
/* can overflow, only indicator */ /* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations); 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) { if (result < 0) {
result = -ENOMEM; result = -ENOMEM;
goto err_out; goto err_out;
...@@ -166,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -166,6 +172,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* MAY_APPEND) * MAY_APPEND)
* @func: caller identifier * @func: caller identifier
* @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=
* *
* 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=
...@@ -178,13 +185,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -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 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; int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
flags &= ima_policy_flag; 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);
} }
/* /*
...@@ -279,7 +288,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -279,7 +288,8 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
void ima_store_measurement(struct integrity_iint_cache *iint, void ima_store_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename, struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value, 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 op[] = "add_template_measure";
static const char audit_cause[] = "ENOMEM"; static const char audit_cause[] = "ENOMEM";
...@@ -296,7 +306,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, ...@@ -296,7 +306,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
if (iint->measured_pcrs & (0x1 << pcr)) if (iint->measured_pcrs & (0x1 << pcr))
return; return;
result = ima_alloc_init_template(&event_data, &entry); result = ima_alloc_init_template(&event_data, &entry, template_desc);
if (result < 0) { if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0); op, audit_cause, result, 0);
......
...@@ -57,7 +57,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) ...@@ -57,7 +57,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
security_task_getsecid(current, &secid); security_task_getsecid(current, &secid);
return ima_match_policy(inode, current_cred(), secid, func, mask, 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, static int ima_fix_xattr(struct dentry *dentry,
......
...@@ -72,7 +72,7 @@ static int __init ima_add_boot_aggregate(void) ...@@ -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) { if (result < 0) {
audit_cause = "alloc_entry"; audit_cause = "alloc_entry";
goto err_out; goto err_out;
......
...@@ -199,7 +199,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -199,7 +199,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL; struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc; struct ima_template_desc *template_desc = NULL;
char *pathbuf = NULL; char *pathbuf = NULL;
char filename[NAME_MAX]; char filename[NAME_MAX];
const char *pathname = NULL; const char *pathname = NULL;
...@@ -217,7 +217,8 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -217,7 +217,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
* bitmask based on the appraise/audit/measurement policy. * bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask. * 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) && 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)
...@@ -304,7 +305,6 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -304,7 +305,6 @@ static int process_measurement(struct file *file, const struct cred *cred,
goto out_locked; goto out_locked;
} }
template_desc = ima_template_desc_current();
if ((action & IMA_APPRAISE_SUBMASK) || if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
/* read 'security.ima' */ /* read 'security.ima' */
...@@ -321,7 +321,8 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -321,7 +321,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (action & IMA_MEASURE) if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname, ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr); xattr_value, xattr_len, pcr,
template_desc);
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
inode_lock(inode); inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file, pathname, rc = ima_appraise_measurement(func, iint, file, pathname,
......
...@@ -80,6 +80,7 @@ struct ima_rule_entry { ...@@ -80,6 +80,7 @@ struct ima_rule_entry {
int type; /* audit type */ int type; /* audit type */
} lsm[MAX_LSM_RULES]; } lsm[MAX_LSM_RULES];
char *fsname; char *fsname;
struct ima_template_desc *template;
}; };
/* /*
...@@ -473,6 +474,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) ...@@ -473,6 +474,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @func: IMA hook identifier * @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @pcr: set the pcr to extend * @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) * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions. * conditions.
...@@ -482,7 +484,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) ...@@ -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. * than writes so ima_match_policy() is classical RCU candidate.
*/ */
int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, 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; struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1); int action = 0, actmask = flags | (flags << 1);
...@@ -514,6 +517,11 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, ...@@ -514,6 +517,11 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
if ((pcr) && (entry->flags & IMA_PCR)) if ((pcr) && (entry->flags & IMA_PCR))
*pcr = entry->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) if (!actmask)
break; break;
} }
...@@ -752,7 +760,7 @@ enum { ...@@ -752,7 +760,7 @@ enum {
Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt,
Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt,
Opt_appraise_type, Opt_permit_directio, Opt_appraise_type, Opt_permit_directio,
Opt_pcr, Opt_err Opt_pcr, Opt_template, Opt_err
}; };
static const match_table_t policy_tokens = { static const match_table_t policy_tokens = {
...@@ -786,6 +794,7 @@ static const match_table_t policy_tokens = { ...@@ -786,6 +794,7 @@ static const match_table_t policy_tokens = {
{Opt_appraise_type, "appraise_type=%s"}, {Opt_appraise_type, "appraise_type=%s"},
{Opt_permit_directio, "permit_directio"}, {Opt_permit_directio, "permit_directio"},
{Opt_pcr, "pcr=%s"}, {Opt_pcr, "pcr=%s"},
{Opt_template, "template=%s"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -839,6 +848,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) ...@@ -839,6 +848,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
char *from; char *from;
char *p; char *p;
bool uid_token; bool uid_token;
struct ima_template_desc *template_desc;
int result = 0; int result = 0;
ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, ab = integrity_audit_log_start(audit_context(), GFP_KERNEL,
...@@ -1134,6 +1144,28 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) ...@@ -1134,6 +1144,28 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
else else
entry->flags |= IMA_PCR; 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; break;
case Opt_err: case Opt_err:
ima_log_string(ab, "UNKNOWN", p); ima_log_string(ab, "UNKNOWN", p);
...@@ -1410,6 +1442,8 @@ int ima_policy_show(struct seq_file *m, void *v) ...@@ -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) if (entry->flags & IMA_DIGSIG_REQUIRED)
seq_puts(m, "appraise_type=imasig "); seq_puts(m, "appraise_type=imasig ");
if (entry->flags & IMA_PERMIT_DIRECTIO) if (entry->flags & IMA_PERMIT_DIRECTIO)
......
...@@ -47,10 +47,6 @@ static const struct ima_template_field supported_fields[] = { ...@@ -47,10 +47,6 @@ static const struct ima_template_field supported_fields[] = {
#define MAX_TEMPLATE_NAME_LEN 15 #define MAX_TEMPLATE_NAME_LEN 15
static struct ima_template_desc *ima_template; 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) static int __init ima_template_setup(char *str)
{ {
...@@ -108,7 +104,7 @@ static int __init ima_template_fmt_setup(char *str) ...@@ -108,7 +104,7 @@ static int __init ima_template_fmt_setup(char *str)
} }
__setup("ima_template_fmt=", ima_template_fmt_setup); __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; struct ima_template_desc *template_desc;
int found = 0; int found = 0;
...@@ -153,9 +149,9 @@ static int template_fmt_size(const char *template_fmt) ...@@ -153,9 +149,9 @@ static int template_fmt_size(const char *template_fmt)
return j + 1; return j + 1;
} }
static int template_desc_init_fields(const char *template_fmt, int template_desc_init_fields(const char *template_fmt,
const struct ima_template_field ***fields, const struct ima_template_field ***fields,
int *num_fields) int *num_fields)
{ {
const char *template_fmt_ptr; const char *template_fmt_ptr;
const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
......
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