Skip to content

Commit

Permalink
Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/zohar/linux-integrity

Pull IMA updates from Mimi Zohar:
 "Two new features - measuring certificates and querying IMA for a file
  hash - and three bug fixes:

   - Measuring certificates is like the rest of IMA, based on policy,
     but requires loading a custom policy. Certificates loaded onto a
     keyring, for example during early boot, before a custom policy has
     been loaded, are queued and only processed after loading the custom
     policy.

   - IMA calculates and caches files hashes. Other kernel subsystems,
     and possibly kernel modules, are interested in accessing these
     cached file hashes.

  The bug fixes prevent classifying a file short read (e.g. shutdown) as
  an invalid file signature, add a missing blank when displaying the
  securityfs policy rules containing LSM labels, and, lastly, fix the
  handling of the IMA policy information for unknown LSM labels"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  IMA: Defined delayed workqueue to free the queued keys
  IMA: Call workqueue functions to measure queued keys
  IMA: Define workqueue for early boot key measurements
  IMA: pre-allocate buffer to hold keyrings string
  ima: ima/lsm policy rule loading logic bug fixes
  ima: add the ability to query the cached hash of a given file
  ima: Add a space after printing LSM rules for readability
  IMA: fix measuring asymmetric keys Kconfig
  IMA: Read keyrings= option from the IMA policy
  IMA: Add support to limit measuring keys
  KEYS: Call the IMA hook to measure keys
  IMA: Define an IMA hook to measure keys
  IMA: Add KEY_CHECK func to measure keys
  IMA: Check IMA policy flag
  ima: avoid appraise error for hash calc interrupt
  • Loading branch information
torvalds committed Jan 29, 2020
2 parents 2cf64d7 + d54e17b commit 73a0bff
Show file tree
Hide file tree
Showing 14 changed files with 540 additions and 40 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
20 changes: 20 additions & 0 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry);
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
extern void ima_kexec_cmdline(const void *buf, int size);

#ifdef CONFIG_IMA_KEXEC
Expand Down Expand Up @@ -91,6 +92,11 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
return;
}

static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
{
return -EOPNOTSUPP;
}

static inline void ima_kexec_cmdline(const void *buf, int size) {}
#endif /* CONFIG_IMA */

Expand All @@ -101,6 +107,20 @@ static inline void ima_add_kexec_buffer(struct kimage *image)
{}
#endif

#ifdef CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS
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_MEASURE_ASYMMETRIC_KEYS */

#ifdef CONFIG_IMA_APPRAISE
extern bool is_ima_appraise_enabled(void);
extern void ima_inode_post_setattr(struct dentry *dentry);
Expand Down
12 changes: 12 additions & 0 deletions security/integrity/ima/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,15 @@ config IMA_APPRAISE_SIGNED_INIT
default n
help
This option requires user-space init to be signed.

config IMA_MEASURE_ASYMMETRIC_KEYS
bool
depends on IMA
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
default y

config IMA_QUEUE_EARLY_BOOT_KEYS
bool
depends on IMA_MEASURE_ASYMMETRIC_KEYS
depends on SYSTEM_TRUSTED_KEYRING
default y
2 changes: 2 additions & 0 deletions security/integrity/ima/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ 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_IMA_MEASURE_ASYMMETRIC_KEYS) += ima_asymmetric_keys.o
obj-$(CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS) += ima_queue_keys.o
33 changes: 30 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 @@ -204,10 +205,35 @@ extern const char *const func_tokens[];

struct modsig;

#ifdef CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS
/*
* To track keys that need to be measured.
*/
struct ima_key_entry {
struct list_head list;
void *payload;
size_t payload_len;
char *keyring_name;
};
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);
#else
static inline void ima_init_key_queue(void) {}
static inline bool ima_should_queue_key(void) { return false; }
static inline bool ima_queue_key(struct key *keyring,
const void *payload,
size_t payload_len) { return false; }
static inline void ima_process_queued_keys(void) {}
#endif /* CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS */

/* 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 +245,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 +260,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
66 changes: 66 additions & 0 deletions security/integrity/ima/ima_asymmetric_keys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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)
{
bool queued = false;

/* Only asymmetric keys are handled by this hook. */
if (key->type != &key_type_asymmetric)
return;

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

if (ima_should_queue_key())
queued = ima_queue_key(keyring, payload, payload_len);

if (queued)
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);
}
4 changes: 3 additions & 1 deletion security/integrity/ima/ima_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,10 @@ static int ima_calc_file_hash_tfm(struct file *file,
rc = rbuf_len;
break;
}
if (rbuf_len == 0)
if (rbuf_len == 0) { /* unexpected EOF */
rc = -EINVAL;
break;
}
offset += rbuf_len;

rc = crypto_shash_update(shash, rbuf, rbuf_len);
Expand Down
8 changes: 7 additions & 1 deletion security/integrity/ima/ima_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,11 @@ int __init ima_init(void)

ima_init_policy();

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

ima_init_key_queue();

return rc;
}
Loading

0 comments on commit 73a0bff

Please sign in to comment.