Skip to content

Commit

Permalink
Merge branch 'next-integrity.measure-keys' into next-integrity
Browse files Browse the repository at this point in the history
From "KEYS: Measure keys when they are created or updated" cover letter:

Keys created or updated in the system are currently not measured.
Therefore an attestation service, for instance, would not be able to
attest whether or not the trusted keys keyring(s), for instance, contain
only known good (trusted) keys.

IMA measures system files, command line arguments passed to kexec,
boot aggregate, etc. It can be used to measure keys as well.
But there is no mechanism available in the kernel for IMA to
know when a key is created or updated.

This change aims to address measuring keys created or updated
in the system.

To achieve the above the following changes have been made:

 - Added a new IMA hook namely, ima_post_key_create_or_update, which
   measures the key. This IMA hook is called from key_create_or_update
   function. The key measurement can be controlled through IMA policy.

   A new IMA policy function KEY_CHECK has been added to measure keys.
   "keyrings=" option can be specified for KEY_CHECK to limit
   measuring the keys loaded onto the specified keyrings only.

   uid can be specified to further restrict key measurement for keys
   created by specific user.

   # measure keys loaded onto any keyring
   measure func=KEY_CHECK

   # measure keys loaded onto the IMA keyring only for root user
   measure func=KEY_CHECK uid=0 keyring=".ima"

   # measure keys on the BUILTIN and IMA keyrings into a different PCR
   measure func=KEY_CHECK keyring=".builtin_trusted_keys|.ima" pcr=11
  • Loading branch information
mimizohar committed Dec 12, 2019
2 parents 96c9e1d + 2b60c0e commit f47825c
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 20 deletions.
16 changes: 14 additions & 2 deletions Documentation/ABI/testing/ima_policy
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ Description:
lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]]
option: [[appraise_type=]] [template=] [permit_directio]
[appraise_flag=]
[appraise_flag=] [keyrings=]
base: func:= [BPRM_CHECK][MMAP_CHECK][CREDS_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
[KEXEC_CMDLINE]
[KEXEC_CMDLINE] [KEY_CHECK]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
Expand All @@ -42,6 +42,9 @@ Description:
appraise_flag:= [check_blacklist]
Currently, blacklist check is only for files signed with appended
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
(eg, ima-ng). Only valid when action is "measure".
pcr:= decimal value
Expand Down Expand Up @@ -113,3 +116,12 @@ Description:
Example of appraise rule allowing modsig appended signatures:

appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig|modsig

Example of measure rule using KEY_CHECK to measure all keys:

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
14 changes: 14 additions & 0 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
{}
#endif

#if defined(CONFIG_IMA) && defined(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE)
extern void ima_post_key_create_or_update(struct key *keyring,
struct key *key,
const void *payload, size_t plen,
unsigned long flags, bool create);
#else
static inline void ima_post_key_create_or_update(struct key *keyring,
struct key *key,
const void *payload,
size_t plen,
unsigned long flags,
bool create) {}
#endif /* CONFIG_IMA && CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE */

#ifdef CONFIG_IMA_APPRAISE
extern bool is_ima_appraise_enabled(void);
extern void ima_inode_post_setattr(struct dentry *dentry);
Expand Down
1 change: 1 addition & 0 deletions security/integrity/ima/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += ima_asymmetric_keys.o
9 changes: 6 additions & 3 deletions security/integrity/ima/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ static inline unsigned long ima_hash_key(u8 *digest)
hook(KEXEC_INITRAMFS_CHECK) \
hook(POLICY_CHECK) \
hook(KEXEC_CMDLINE) \
hook(KEY_CHECK) \
hook(MAX_CHECK)
#define __ima_hook_enumify(ENUM) ENUM,

Expand All @@ -207,7 +208,8 @@ struct modsig;
/* 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,
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_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size,
Expand All @@ -219,7 +221,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
struct ima_template_desc *template_desc);
void process_buffer_measurement(const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr);
int pcr, const char *keyring);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data,
Expand All @@ -234,7 +236,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,
struct ima_template_desc **template_desc);
struct ima_template_desc **template_desc,
const char *keyring);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flag(void);
Expand Down
8 changes: 5 additions & 3 deletions security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* @func: caller identifier
* @pcr: pointer filled in if matched measure policy sets pcr=
* @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:
* subj=, obj=, type=, func=, mask=, fsmagic=
* subj,obj, and type: are LSM specific.
* func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
* | KEXEC_CMDLINE
* | KEXEC_CMDLINE | KEY_CHECK
* mask: contains the permission mask
* fsmagic: hex value
*
Expand All @@ -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 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;

flags &= ima_policy_flag;

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

/*
Expand Down
4 changes: 2 additions & 2 deletions security/integrity/ima/ima_appraise.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,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, NULL);
IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
}

static int ima_fix_xattr(struct dentry *dentry,
Expand Down Expand Up @@ -330,7 +330,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(digest, digestsize,
"blacklisted-hash", NONE,
pcr);
pcr, NULL);
}

return rc;
Expand Down
58 changes: 58 additions & 0 deletions security/integrity/ima/ima_asymmetric_keys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Microsoft Corporation
*
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
*
* File: ima_asymmetric_keys.c
* Defines an IMA hook to measure asymmetric keys on key
* create or update.
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <keys/asymmetric-type.h>
#include "ima.h"

/**
* ima_post_key_create_or_update - measure asymmetric keys
* @keyring: keyring to which the key is linked to
* @key: created or updated key
* @payload: The data used to instantiate or update the key.
* @payload_len: The length of @payload.
* @flags: key flags
* @create: flag indicating whether the key was created or updated
*
* Keys can only be measured, not appraised.
* The payload data used to instantiate or update the key is measured.
*/
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)
{
/* Only asymmetric keys are handled by this hook. */
if (key->type != &key_type_asymmetric)
return;

if (!payload || (payload_len == 0))
return;

/*
* keyring->description points to the name of the keyring
* (such as ".builtin_trusted_keys", ".ima", etc.) to
* which the given key is linked to.
*
* The name of the keyring is passed in the "eventname"
* parameter to process_buffer_measurement() and is set
* in the "eventname" field in ima_event_data for
* 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,
keyring->description, KEY_CHECK, 0,
keyring->description);
}
12 changes: 8 additions & 4 deletions security/integrity/ima/ima_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
* Included is the appraise submask.
*/
action = ima_get_action(inode, cred, secid, mask, func, &pcr,
&template_desc);
&template_desc, NULL);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
Expand Down Expand Up @@ -632,12 +632,13 @@ int ima_load_data(enum kernel_load_data_id id)
* @eventname: event name to be used for the buffer entry.
* @func: IMA hook
* @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.
*/
void process_buffer_measurement(const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr)
int pcr, const char *keyring)
{
int ret = 0;
struct ima_template_entry *entry = NULL;
Expand All @@ -655,6 +656,9 @@ void process_buffer_measurement(const void *buf, int size,
int action = 0;
u32 secid;

if (!ima_policy_flag)
return;

/*
* Both LSM hooks and auxilary based buffer measurements are
* based on policy. To avoid code duplication, differentiate
Expand All @@ -665,7 +669,7 @@ void process_buffer_measurement(const void *buf, int size,
if (func) {
security_task_getsecid(current, &secid);
action = ima_get_action(NULL, current_cred(), secid, 0, func,
&pcr, &template);
&pcr, &template, keyring);
if (!(action & IMA_MEASURE))
return;
}
Expand Down Expand Up @@ -718,7 +722,7 @@ void ima_kexec_cmdline(const void *buf, int size)
{
if (buf && size != 0)
process_buffer_measurement(buf, size, "kexec-cmdline",
KEXEC_CMDLINE, 0);
KEXEC_CMDLINE, 0, NULL);
}

static int __init init_ima(void)
Expand Down
Loading

0 comments on commit f47825c

Please sign in to comment.