Commit e9085e0a authored by Lakshmi Ramasubramanian's avatar Lakshmi Ramasubramanian Committed by Mimi Zohar

IMA: Add support to limit measuring keys

Limit measuring keys to those keys being loaded onto a given set of
keyrings only and when the user id (uid) matches if uid is specified
in the policy.

This patch defines a new IMA policy option namely "keyrings=" that
can be used to specify a set of keyrings. If this option is specified
in the policy for "measure func=KEY_CHECK" then only the keys
loaded onto a keyring given in the "keyrings=" option are measured.

If uid is specified in the policy then the key is measured only if
the current user id matches the one specified in the policy.

Added a new parameter namely "keyring" (name of the keyring) to
process_buffer_measurement(). The keyring name is passed to
ima_get_action() to determine the required action.
ima_match_rules() is updated to check keyring in the policy, if
specified, for KEY_CHECK function.
Signed-off-by: default avatarLakshmi Ramasubramanian <nramas@linux.microsoft.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent cb1aa382
...@@ -25,7 +25,7 @@ Description: ...@@ -25,7 +25,7 @@ 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=] [appraise_flag=] [keyrings=]
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]
...@@ -42,6 +42,9 @@ Description: ...@@ -42,6 +42,9 @@ Description:
appraise_flag:= [check_blacklist] appraise_flag:= [check_blacklist]
Currently, blacklist check is only for files signed with appended Currently, blacklist check is only for files signed with appended
signature. signature.
keyrings:= list of keyrings
(eg, .builtin_trusted_keys|.ima). Only valid
when action is "measure" and func is KEY_CHECK.
template:= name of a defined IMA template type template:= name of a defined IMA template type
(eg, ima-ng). Only valid when action is "measure". (eg, ima-ng). Only valid when action is "measure".
pcr:= decimal value pcr:= decimal value
...@@ -117,3 +120,8 @@ Description: ...@@ -117,3 +120,8 @@ Description:
Example of measure rule using KEY_CHECK to measure all keys: Example of measure rule using KEY_CHECK to measure all keys:
measure func=KEY_CHECK measure func=KEY_CHECK
Example of measure rule using KEY_CHECK to only measure
keys added to .builtin_trusted_keys or .ima keyring:
measure func=KEY_CHECK keyrings=.builtin_trusted_keys|.ima
...@@ -208,7 +208,8 @@ struct modsig; ...@@ -208,7 +208,8 @@ struct modsig;
/* 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); struct ima_template_desc **template_desc,
const char *keyring);
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,
...@@ -220,7 +221,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, ...@@ -220,7 +221,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct ima_template_desc *template_desc); struct ima_template_desc *template_desc);
void process_buffer_measurement(const void *buf, int size, void process_buffer_measurement(const void *buf, int size,
const char *eventname, enum ima_hooks func, const char *eventname, enum ima_hooks func,
int pcr); int pcr, const char *keyring);
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,
...@@ -235,7 +236,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); ...@@ -235,7 +236,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); struct ima_template_desc **template_desc,
const char *keyring);
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);
......
...@@ -169,12 +169,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -169,12 +169,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* @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= * @template_desc: pointer filled in if matched measure policy sets template=
* @keyring: keyring name used to determine the action
* *
* 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=
* subj,obj, and type: are LSM specific. * subj,obj, and type: are LSM specific.
* func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
* | KEXEC_CMDLINE * | KEXEC_CMDLINE | KEY_CHECK
* mask: contains the permission mask * mask: contains the permission mask
* fsmagic: hex value * fsmagic: hex value
* *
...@@ -183,14 +184,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename, ...@@ -183,14 +184,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) struct ima_template_desc **template_desc,
const char *keyring)
{ {
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); template_desc, keyring);
} }
/* /*
......
...@@ -55,7 +55,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) ...@@ -55,7 +55,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, NULL); IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
} }
static int ima_fix_xattr(struct dentry *dentry, static int ima_fix_xattr(struct dentry *dentry,
...@@ -330,7 +330,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, ...@@ -330,7 +330,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(digest, digestsize, process_buffer_measurement(digest, digestsize,
"blacklisted-hash", NONE, "blacklisted-hash", NONE,
pcr); pcr, NULL);
} }
return rc; return rc;
......
...@@ -46,7 +46,13 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key, ...@@ -46,7 +46,13 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
* parameter to process_buffer_measurement() and is set * parameter to process_buffer_measurement() and is set
* in the "eventname" field in ima_event_data for * in the "eventname" field in ima_event_data for
* the key measurement IMA event. * the key measurement IMA event.
*
* The name of the keyring is also passed in the "keyring"
* parameter to process_buffer_measurement() to check
* if the IMA policy is configured to measure a key linked
* to the given keyring.
*/ */
process_buffer_measurement(payload, payload_len, process_buffer_measurement(payload, payload_len,
keyring->description, KEY_CHECK, 0); keyring->description, KEY_CHECK, 0,
keyring->description);
} }
...@@ -215,7 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred, ...@@ -215,7 +215,7 @@ 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(inode, cred, secid, mask, func, &pcr, action = ima_get_action(inode, cred, secid, mask, func, &pcr,
&template_desc); &template_desc, NULL);
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)
...@@ -632,12 +632,13 @@ int ima_load_data(enum kernel_load_data_id id) ...@@ -632,12 +632,13 @@ int ima_load_data(enum kernel_load_data_id id)
* @eventname: event name to be used for the buffer entry. * @eventname: event name to be used for the buffer entry.
* @func: IMA hook * @func: IMA hook
* @pcr: pcr to extend the measurement * @pcr: pcr to extend the measurement
* @keyring: keyring name to determine the action to be performed
* *
* Based on policy, the buffer is measured into the ima log. * Based on policy, the buffer is measured into the ima log.
*/ */
void process_buffer_measurement(const void *buf, int size, void process_buffer_measurement(const void *buf, int size,
const char *eventname, enum ima_hooks func, const char *eventname, enum ima_hooks func,
int pcr) int pcr, const char *keyring)
{ {
int ret = 0; int ret = 0;
struct ima_template_entry *entry = NULL; struct ima_template_entry *entry = NULL;
...@@ -668,7 +669,7 @@ void process_buffer_measurement(const void *buf, int size, ...@@ -668,7 +669,7 @@ void process_buffer_measurement(const void *buf, int size,
if (func) { if (func) {
security_task_getsecid(current, &secid); security_task_getsecid(current, &secid);
action = ima_get_action(NULL, current_cred(), secid, 0, func, action = ima_get_action(NULL, current_cred(), secid, 0, func,
&pcr, &template); &pcr, &template, keyring);
if (!(action & IMA_MEASURE)) if (!(action & IMA_MEASURE))
return; return;
} }
...@@ -721,7 +722,7 @@ void ima_kexec_cmdline(const void *buf, int size) ...@@ -721,7 +722,7 @@ void ima_kexec_cmdline(const void *buf, int size)
{ {
if (buf && size != 0) if (buf && size != 0)
process_buffer_measurement(buf, size, "kexec-cmdline", process_buffer_measurement(buf, size, "kexec-cmdline",
KEXEC_CMDLINE, 0); KEXEC_CMDLINE, 0, NULL);
} }
static int __init init_ima(void) static int __init init_ima(void)
......
...@@ -79,6 +79,7 @@ struct ima_rule_entry { ...@@ -79,6 +79,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;
char *keyrings; /* Measure keys added to these keyrings */
struct ima_template_desc *template; struct ima_template_desc *template;
}; };
...@@ -356,6 +357,50 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, ...@@ -356,6 +357,50 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
return NOTIFY_OK; return NOTIFY_OK;
} }
/**
* ima_match_keyring - determine whether the keyring matches the measure rule
* @rule: a pointer to a rule
* @keyring: name of the keyring to match against the measure rule
* @cred: a pointer to a credentials structure for user validation
*
* Returns true if keyring matches one in the rule, false otherwise.
*/
static bool ima_match_keyring(struct ima_rule_entry *rule,
const char *keyring, const struct cred *cred)
{
char *keyrings, *next_keyring, *keyrings_ptr;
bool matched = false;
if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
return false;
if (!rule->keyrings)
return true;
if (!keyring)
return false;
keyrings = kstrdup(rule->keyrings, GFP_KERNEL);
if (!keyrings)
return false;
/*
* "keyrings=" is specified in the policy in the format below:
* keyrings=.builtin_trusted_keys|.ima|.evm
*/
keyrings_ptr = keyrings;
while ((next_keyring = strsep(&keyrings_ptr, "|")) != NULL) {
if (!strcmp(next_keyring, keyring)) {
matched = true;
break;
}
}
kfree(keyrings);
return matched;
}
/** /**
* ima_match_rules - determine whether an inode matches the measure rule. * ima_match_rules - determine whether an inode matches the measure rule.
* @rule: a pointer to a rule * @rule: a pointer to a rule
...@@ -364,18 +409,23 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, ...@@ -364,18 +409,23 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
* @secid: the secid of the task to be validated * @secid: the secid of the task to be validated
* @func: LIM hook identifier * @func: LIM hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @keyring: keyring name to check in policy for KEY_CHECK func
* *
* Returns true on rule match, false on failure. * Returns true on rule match, false on failure.
*/ */
static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
const struct cred *cred, u32 secid, const struct cred *cred, u32 secid,
enum ima_hooks func, int mask) enum ima_hooks func, int mask,
const char *keyring)
{ {
int i; int i;
if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) { if ((func == KEXEC_CMDLINE) || (func == KEY_CHECK)) {
if ((rule->flags & IMA_FUNC) && (rule->func == func)) if ((rule->flags & IMA_FUNC) && (rule->func == func)) {
if (func == KEY_CHECK)
return ima_match_keyring(rule, keyring, cred);
return true; return true;
}
return false; return false;
} }
if ((rule->flags & IMA_FUNC) && if ((rule->flags & IMA_FUNC) &&
...@@ -479,6 +529,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) ...@@ -479,6 +529,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @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 * @template_desc: the template that should be used for this rule
* @keyring: the keyring name, if given, to be used to check in the policy.
* keyring can be NULL if func is anything other than KEY_CHECK.
* *
* 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.
...@@ -489,7 +541,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) ...@@ -489,7 +541,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
*/ */
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_template_desc **template_desc,
const char *keyring)
{ {
struct ima_rule_entry *entry; struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1); int action = 0, actmask = flags | (flags << 1);
...@@ -503,7 +556,8 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, ...@@ -503,7 +556,8 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
if (!(entry->action & actmask)) if (!(entry->action & actmask))
continue; continue;
if (!ima_match_rules(entry, inode, cred, secid, func, mask)) if (!ima_match_rules(entry, inode, cred, secid, func, mask,
keyring))
continue; continue;
action |= entry->flags & IMA_ACTION_FLAGS; action |= entry->flags & IMA_ACTION_FLAGS;
......
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