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/jmorris/linux-security

Pull integrity updates from James Morris:
 "In Linux 4.19, a new LSM hook named security_kernel_load_data was
  upstreamed, allowing LSMs and IMA to prevent the kexec_load syscall.
  Different signature verification methods exist for verifying the
  kexec'ed kernel image. This adds additional support in IMA to prevent
  loading unsigned kernel images via the kexec_load syscall,
  independently of the IMA policy rules, based on the runtime "secure
  boot" flag. An initial IMA kselftest is included.

  In addition, this pull request defines a new, separate keyring named
  ".platform" for storing the preboot/firmware keys needed for verifying
  the kexec'ed kernel image's signature and includes the associated IMA
  kexec usage of the ".platform" keyring.

  (David Howell's and Josh Boyer's patches for reading the
  preboot/firmware keys, which were previously posted for a different
  use case scenario, are included here)"

* 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  integrity: Remove references to module keyring
  ima: Use inode_is_open_for_write
  ima: Support platform keyring for kernel appraisal
  efi: Allow the "db" UEFI variable to be suppressed
  efi: Import certificates from UEFI Secure Boot
  efi: Add an EFI signature blob parser
  efi: Add EFI signature data types
  integrity: Load certs to the platform keyring
  integrity: Define a trusted platform keyring
  selftests/ima: kexec_load syscall test
  ima: don't measure/appraise files on efivarfs
  x86/ima: retry detecting secure boot mode
  docs: Extend trusted keys documentation for TPM 2.0
  x86/ima: define arch_get_ima_policy() for x86
  ima: add support for arch specific policies
  ima: refactor ima_init_policy()
  ima: prevent kexec_load syscall based on runtime secureboot flag
  x86/ima: define arch_ima_get_secureboot
  integrity: support new struct public_key_signature encoding field
  • Loading branch information
torvalds committed Jan 2, 2019
2 parents 8e143b9 + c7f7e58 commit f218a29
Show file tree
Hide file tree
Showing 20 changed files with 861 additions and 93 deletions.
31 changes: 30 additions & 1 deletion Documentation/security/keys/trusted-encrypted.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,33 @@ integrity verifications match. A loaded Trusted Key can be updated with new
when the kernel and initramfs are updated. The same key can have many saved
blobs under different PCR values, so multiple boots are easily supported.

TPM 1.2
-------

By default, trusted keys are sealed under the SRK, which has the default
authorization value (20 zeros). This can be set at takeownership time with the
trouser's utility: "tpm_takeownership -u -z".

TPM 2.0
-------

The user must first create a storage key and make it persistent, so the key is
available after reboot. This can be done using the following commands.

With the IBM TSS 2 stack::

#> tsscreateprimary -hi o -st
Handle 80000000
#> tssevictcontrol -hi o -ho 80000000 -hp 81000001

Or with the Intel TSS 2 stack::

#> tpm2_createprimary --hierarchy o -G rsa2048 -o key.ctxt
[...]
handle: 0x800000FF
#> tpm2_evictcontrol -c key.ctxt -p 0x81000001
persistentHandle: 0x81000001

Usage::

keyctl add trusted name "new keylen [options]" ring
Expand All @@ -30,7 +53,9 @@ Usage::
keyctl print keyid

options:
keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
keyhandle= ascii hex value of sealing key
TPM 1.2: default 0x40000000 (SRK)
TPM 2.0: no default; must be passed every time
keyauth= ascii hex auth for sealing key default 0x00...i
(40 ascii zeros)
blobauth= ascii hex auth for sealed data default 0x00...
Expand Down Expand Up @@ -84,6 +109,10 @@ Examples of trusted and encrypted key usage:

Create and save a trusted key named "kmk" of length 32 bytes::

Note: When using a TPM 2.0 with a persistent key with handle 0x81000001,
append 'keyhandle=0x81000001' to statements between quotes, such as
"new 32 keyhandle=0x81000001".

$ keyctl add trusted kmk "new 32" @u
440502848

Expand Down
4 changes: 4 additions & 0 deletions arch/x86/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,7 @@ ifeq ($(CONFIG_X86_64),y)
obj-$(CONFIG_MMCONF_FAM10H) += mmconf-fam10h_64.o
obj-y += vsmp_64.o
endif

ifdef CONFIG_EFI
obj-$(CONFIG_IMA) += ima_arch.o
endif
75 changes: 75 additions & 0 deletions arch/x86/kernel/ima_arch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2018 IBM Corporation
*/
#include <linux/efi.h>
#include <linux/ima.h>

extern struct boot_params boot_params;

static enum efi_secureboot_mode get_sb_mode(void)
{
efi_char16_t efi_SecureBoot_name[] = L"SecureBoot";
efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
efi_status_t status;
unsigned long size;
u8 secboot;

size = sizeof(secboot);

/* Get variable contents into buffer */
status = efi.get_variable(efi_SecureBoot_name, &efi_variable_guid,
NULL, &size, &secboot);
if (status == EFI_NOT_FOUND) {
pr_info("ima: secureboot mode disabled\n");
return efi_secureboot_mode_disabled;
}

if (status != EFI_SUCCESS) {
pr_info("ima: secureboot mode unknown\n");
return efi_secureboot_mode_unknown;
}

if (secboot == 0) {
pr_info("ima: secureboot mode disabled\n");
return efi_secureboot_mode_disabled;
}

pr_info("ima: secureboot mode enabled\n");
return efi_secureboot_mode_enabled;
}

bool arch_ima_get_secureboot(void)
{
static enum efi_secureboot_mode sb_mode;
static bool initialized;

if (!initialized && efi_enabled(EFI_BOOT)) {
sb_mode = boot_params.secure_boot;

if (sb_mode == efi_secureboot_mode_unset)
sb_mode = get_sb_mode();
initialized = true;
}

if (sb_mode == efi_secureboot_mode_enabled)
return true;
else
return false;
}

/* secureboot arch rules */
static const char * const sb_arch_rules[] = {
#if !IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
#endif /* CONFIG_KEXEC_VERIFY_SIG */
"measure func=KEXEC_KERNEL_CHECK",
NULL
};

const char * const *arch_get_ima_policy(void)
{
if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot())
return sb_arch_rules;
return NULL;
}
34 changes: 34 additions & 0 deletions include/linux/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ void efi_native_runtime_setup(void);
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)

#define EFI_CERT_SHA256_GUID EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
#define EFI_CERT_X509_GUID EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
#define EFI_CERT_X509_SHA256_GUID EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)

/*
* This GUID is used to pass to the kernel proper the struct screen_info
* structure that was populated by the stub based on the GOP protocol instance
Expand Down Expand Up @@ -934,6 +938,27 @@ typedef struct {
efi_memory_desc_t entry[0];
} efi_memory_attributes_table_t;

typedef struct {
efi_guid_t signature_owner;
u8 signature_data[];
} efi_signature_data_t;

typedef struct {
efi_guid_t signature_type;
u32 signature_list_size;
u32 signature_header_size;
u32 signature_size;
u8 signature_header[];
/* efi_signature_data_t signatures[][] */
} efi_signature_list_t;

typedef u8 efi_sha256_hash_t[32];

typedef struct {
efi_sha256_hash_t to_be_signed_hash;
efi_time_t time_of_revocation;
} efi_cert_x509_sha256_t;

/*
* All runtime access to EFI goes through this structure:
*/
Expand Down Expand Up @@ -1113,6 +1138,15 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm,
char * __init efi_md_typeattr_format(char *buf, size_t size,
const efi_memory_desc_t *md);


typedef void (*efi_element_handler_t)(const char *source,
const void *element_data,
size_t element_size);
extern int __init parse_efi_signature_list(
const char *source,
const void *data, size_t size,
efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *));

/**
* efi_range_is_wc - check the WC bit on an address range
* @start: starting kvirt address
Expand Down
15 changes: 15 additions & 0 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ extern void ima_post_path_mknod(struct dentry *dentry);
extern void ima_add_kexec_buffer(struct kimage *image);
#endif

#if defined(CONFIG_X86) && defined(CONFIG_EFI)
extern bool arch_ima_get_secureboot(void);
extern const char * const *arch_get_ima_policy(void);
#else
static inline bool arch_ima_get_secureboot(void)
{
return false;
}

static inline const char * const *arch_get_ima_policy(void)
{
return NULL;
}
#endif

#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
{
Expand Down
11 changes: 11 additions & 0 deletions security/integrity/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ config INTEGRITY_TRUSTED_KEYRING
.evm keyrings be signed by a key on the system trusted
keyring.

config INTEGRITY_PLATFORM_KEYRING
bool "Provide keyring for platform/firmware trusted keys"
depends on INTEGRITY_ASYMMETRIC_KEYS
depends on SYSTEM_BLACKLIST_KEYRING
depends on EFI
help
Provide a separate, distinct keyring for platform trusted keys, which
the kernel automatically populates during initialization from values
provided by the platform for verifying the kexec'ed kerned image
and, possibly, the initramfs signature.

config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
depends on AUDIT
Expand Down
5 changes: 5 additions & 0 deletions security/integrity/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ integrity-y := iint.o
integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \
platform_certs/efi_parser.o \
platform_certs/load_uefi.o
obj-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/load_uefi.o
$(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar

subdir-$(CONFIG_IMA) += ima
obj-$(CONFIG_IMA) += ima/
Expand Down
111 changes: 73 additions & 38 deletions security/integrity/digsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
".evm",
".ima",
#endif
"_module",
".platform",
};

#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
Expand Down Expand Up @@ -73,12 +73,38 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP;
}

int __init integrity_init_keyring(const unsigned int id)
static int __integrity_init_keyring(const unsigned int id, key_perm_t perm,
struct key_restriction *restriction)
{
const struct cred *cred = current_cred();
struct key_restriction *restriction;
int err = 0;

keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred, perm,
KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL);
if (IS_ERR(keyring[id])) {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
}

return err;
}

int __init integrity_init_keyring(const unsigned int id)
{
struct key_restriction *restriction;
key_perm_t perm;

perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW
| KEY_USR_READ | KEY_USR_SEARCH;

if (id == INTEGRITY_KEYRING_PLATFORM) {
restriction = NULL;
goto out;
}

if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
return 0;

Expand All @@ -87,32 +113,43 @@ int __init integrity_init_keyring(const unsigned int id)
return -ENOMEM;

restriction->check = restrict_link_to_ima;
perm |= KEY_USR_WRITE;

keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA,
restriction, NULL);
if (IS_ERR(keyring[id])) {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
out:
return __integrity_init_keyring(id, perm, restriction);
}

int __init integrity_add_key(const unsigned int id, const void *data,
off_t size, key_perm_t perm)
{
key_ref_t key;
int rc = 0;

if (!keyring[id])
return -EINVAL;

key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric",
NULL, data, size, perm,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate %d\n", rc);
} else {
pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description);
key_ref_put(key);
}
return err;

return rc;

}

int __init integrity_load_x509(const unsigned int id, const char *path)
{
key_ref_t key;
void *data;
loff_t size;
int rc;

if (!keyring[id])
return -EINVAL;
key_perm_t perm;

rc = kernel_read_file_from_path(path, &data, &size, 0,
READING_X509_CERTIFICATE);
Expand All @@ -121,23 +158,21 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
return rc;
}

key = key_create_or_update(make_key_ref(keyring[id], 1),
"asymmetric",
NULL,
data,
size,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate (%d): %s\n",
rc, path);
} else {
pr_notice("Loaded X.509 cert '%s': %s\n",
key_ref_to_ptr(key)->description, path);
key_ref_put(key);
}
perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ;

pr_info("Loading X.509 certificate: %s\n", path);
rc = integrity_add_key(id, (const void *)data, size, perm);

vfree(data);
return 0;
return rc;
}

int __init integrity_load_cert(const unsigned int id, const char *source,
const void *data, size_t len, key_perm_t perm)
{
if (!data)
return -EINVAL;

pr_info("Loading X.509 certificate: %s\n", source);
return integrity_add_key(id, data, len, perm);
}
Loading

0 comments on commit f218a29

Please sign in to comment.