aboutsummaryrefslogtreecommitdiffstats
path: root/certs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 08:50:52 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 08:50:52 -0700
commit0302e28dee643932ee7b3c112ebccdbb9f8ec32c (patch)
tree405d4cb3f772ef069ed7f291adc4b74a4e73346e /certs
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial (diff)
parenttpm: Fix reference count to main device (diff)
downloadlinux-dev-0302e28dee643932ee7b3c112ebccdbb9f8ec32c.tar.xz
linux-dev-0302e28dee643932ee7b3c112ebccdbb9f8ec32c.zip
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "Highlights: IMA: - provide ">" and "<" operators for fowner/uid/euid rules KEYS: - add a system blacklist keyring - add KEYCTL_RESTRICT_KEYRING, exposes keyring link restriction functionality to userland via keyctl() LSM: - harden LSM API with __ro_after_init - add prlmit security hook, implement for SELinux - revive security_task_alloc hook TPM: - implement contextual TPM command 'spaces'" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (98 commits) tpm: Fix reference count to main device tpm_tis: convert to using locality callbacks tpm: fix handling of the TPM 2.0 event logs tpm_crb: remove a cruft constant keys: select CONFIG_CRYPTO when selecting DH / KDF apparmor: Make path_max parameter readonly apparmor: fix parameters so that the permission test is bypassed at boot apparmor: fix invalid reference to index variable of iterator line 836 apparmor: use SHASH_DESC_ON_STACK security/apparmor/lsm.c: set debug messages apparmor: fix boolreturn.cocci warnings Smack: Use GFP_KERNEL for smk_netlbl_mls(). smack: fix double free in smack_parse_opts_str() KEYS: add SP800-56A KDF support for DH KEYS: Keyring asymmetric key restrict method with chaining KEYS: Restrict asymmetric key linkage using a specific keychain KEYS: Add a lookup_restriction function for the asymmetric key type KEYS: Add KEYCTL_RESTRICT_KEYRING KEYS: Consistent ordering for __key_link_begin and restrict check KEYS: Add an optional lookup_restriction hook to key_type ...
Diffstat (limited to 'certs')
-rw-r--r--certs/Kconfig18
-rw-r--r--certs/Makefile6
-rw-r--r--certs/blacklist.c174
-rw-r--r--certs/blacklist.h3
-rw-r--r--certs/blacklist_hashes.c6
-rw-r--r--certs/blacklist_nohashes.c5
-rw-r--r--certs/system_keyring.c39
7 files changed, 243 insertions, 8 deletions
diff --git a/certs/Kconfig b/certs/Kconfig
index fc5955f5fc8a..6ce51ede9e9b 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -64,4 +64,22 @@ config SECONDARY_TRUSTED_KEYRING
those keys are not blacklisted and are vouched for by a key built
into the kernel or already in the secondary trusted keyring.
+config SYSTEM_BLACKLIST_KEYRING
+ bool "Provide system-wide ring of blacklisted keys"
+ depends on KEYS
+ help
+ Provide a system keyring to which blacklisted keys can be added.
+ Keys in the keyring are considered entirely untrusted. Keys in this
+ keyring are used by the module signature checking to reject loading
+ of modules signed with a blacklisted key.
+
+config SYSTEM_BLACKLIST_HASH_LIST
+ string "Hashes to be preloaded into the system blacklist keyring"
+ depends on SYSTEM_BLACKLIST_KEYRING
+ help
+ If set, this option should be the filename of a list of hashes in the
+ form "<hash>", "<hash>", ... . This will be included into a C
+ wrapper to incorporate the list into the kernel. Each <hash> should
+ be a string of hex digits.
+
endmenu
diff --git a/certs/Makefile b/certs/Makefile
index 2773c4afa24c..4119bb376ea1 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -3,6 +3,12 @@
#
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
+else
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o
+endif
ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
diff --git a/certs/blacklist.c b/certs/blacklist.c
new file mode 100644
index 000000000000..3eddce0e307a
--- /dev/null
+++ b/certs/blacklist.c
@@ -0,0 +1,174 @@
+/* System hash blacklist.
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "blacklist: "fmt
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <keys/system_keyring.h>
+#include "blacklist.h"
+
+static struct key *blacklist_keyring;
+
+/*
+ * The description must be a type prefix, a colon and then an even number of
+ * hex digits. The hash is kept in the description.
+ */
+static int blacklist_vet_description(const char *desc)
+{
+ int n = 0;
+
+ if (*desc == ':')
+ return -EINVAL;
+ for (; *desc; desc++)
+ if (*desc == ':')
+ goto found_colon;
+ return -EINVAL;
+
+found_colon:
+ desc++;
+ for (; *desc; desc++) {
+ if (!isxdigit(*desc))
+ return -EINVAL;
+ n++;
+ }
+
+ if (n == 0 || n & 1)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * The hash to be blacklisted is expected to be in the description. There will
+ * be no payload.
+ */
+static int blacklist_preparse(struct key_preparsed_payload *prep)
+{
+ if (prep->datalen > 0)
+ return -EINVAL;
+ return 0;
+}
+
+static void blacklist_free_preparse(struct key_preparsed_payload *prep)
+{
+}
+
+static void blacklist_describe(const struct key *key, struct seq_file *m)
+{
+ seq_puts(m, key->description);
+}
+
+static struct key_type key_type_blacklist = {
+ .name = "blacklist",
+ .vet_description = blacklist_vet_description,
+ .preparse = blacklist_preparse,
+ .free_preparse = blacklist_free_preparse,
+ .instantiate = generic_key_instantiate,
+ .describe = blacklist_describe,
+};
+
+/**
+ * mark_hash_blacklisted - Add a hash to the system blacklist
+ * @hash - The hash as a hex string with a type prefix (eg. "tbs:23aa429783")
+ */
+int mark_hash_blacklisted(const char *hash)
+{
+ key_ref_t key;
+
+ key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+ "blacklist",
+ hash,
+ NULL,
+ 0,
+ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW),
+ KEY_ALLOC_NOT_IN_QUOTA |
+ KEY_ALLOC_BUILT_IN);
+ if (IS_ERR(key)) {
+ pr_err("Problem blacklisting hash (%ld)\n", PTR_ERR(key));
+ return PTR_ERR(key);
+ }
+ return 0;
+}
+
+/**
+ * is_hash_blacklisted - Determine if a hash is blacklisted
+ * @hash: The hash to be checked as a binary blob
+ * @hash_len: The length of the binary hash
+ * @type: Type of hash
+ */
+int is_hash_blacklisted(const u8 *hash, size_t hash_len, const char *type)
+{
+ key_ref_t kref;
+ size_t type_len = strlen(type);
+ char *buffer, *p;
+ int ret = 0;
+
+ buffer = kmalloc(type_len + 1 + hash_len * 2 + 1, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ p = memcpy(buffer, type, type_len);
+ p += type_len;
+ *p++ = ':';
+ bin2hex(p, hash, hash_len);
+ p += hash_len * 2;
+ *p = 0;
+
+ kref = keyring_search(make_key_ref(blacklist_keyring, true),
+ &key_type_blacklist, buffer);
+ if (!IS_ERR(kref)) {
+ key_ref_put(kref);
+ ret = -EKEYREJECTED;
+ }
+
+ kfree(buffer);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(is_hash_blacklisted);
+
+/*
+ * Intialise the blacklist
+ */
+static int __init blacklist_init(void)
+{
+ const char *const *bl;
+
+ if (register_key_type(&key_type_blacklist) < 0)
+ panic("Can't allocate system blacklist key type\n");
+
+ blacklist_keyring =
+ keyring_alloc(".blacklist",
+ KUIDT_INIT(0), KGIDT_INIT(0),
+ current_cred(),
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ |
+ KEY_USR_SEARCH,
+ KEY_ALLOC_NOT_IN_QUOTA |
+ KEY_FLAG_KEEP,
+ NULL, NULL);
+ if (IS_ERR(blacklist_keyring))
+ panic("Can't allocate system blacklist keyring\n");
+
+ for (bl = blacklist_hashes; *bl; bl++)
+ if (mark_hash_blacklisted(*bl) < 0)
+ pr_err("- blacklisting failed\n");
+ return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(blacklist_init);
diff --git a/certs/blacklist.h b/certs/blacklist.h
new file mode 100644
index 000000000000..150d82da8e99
--- /dev/null
+++ b/certs/blacklist.h
@@ -0,0 +1,3 @@
+#include <linux/kernel.h>
+
+extern const char __initdata *const blacklist_hashes[];
diff --git a/certs/blacklist_hashes.c b/certs/blacklist_hashes.c
new file mode 100644
index 000000000000..5bd449f7db17
--- /dev/null
+++ b/certs/blacklist_hashes.c
@@ -0,0 +1,6 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
+ , NULL
+};
diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c
new file mode 100644
index 000000000000..851de10706a5
--- /dev/null
+++ b/certs/blacklist_nohashes.c
@@ -0,0 +1,5 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+ NULL
+};
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 50979d6dcecd..6251d1b27f0c 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include <crypto/pkcs7.h>
@@ -32,11 +33,13 @@ extern __initconst const unsigned long system_certificate_list_size;
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in the built in system keyring.
*/
-int restrict_link_by_builtin_trusted(struct key *keyring,
+int restrict_link_by_builtin_trusted(struct key *dest_keyring,
const struct key_type *type,
- const union key_payload *payload)
+ const union key_payload *payload,
+ struct key *restriction_key)
{
- return restrict_link_by_signature(builtin_trusted_keys, type, payload);
+ return restrict_link_by_signature(dest_keyring, type, payload,
+ builtin_trusted_keys);
}
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
@@ -49,20 +52,40 @@ int restrict_link_by_builtin_trusted(struct key *keyring,
* keyrings.
*/
int restrict_link_by_builtin_and_secondary_trusted(
- struct key *keyring,
+ struct key *dest_keyring,
const struct key_type *type,
- const union key_payload *payload)
+ const union key_payload *payload,
+ struct key *restrict_key)
{
/* If we have a secondary trusted keyring, then that contains a link
* through to the builtin keyring and the search will follow that link.
*/
if (type == &key_type_keyring &&
- keyring == secondary_trusted_keys &&
+ dest_keyring == secondary_trusted_keys &&
payload == &builtin_trusted_keys->payload)
/* Allow the builtin keyring to be added to the secondary */
return 0;
- return restrict_link_by_signature(secondary_trusted_keys, type, payload);
+ return restrict_link_by_signature(dest_keyring, type, payload,
+ secondary_trusted_keys);
+}
+
+/**
+ * Allocate a struct key_restriction for the "builtin and secondary trust"
+ * keyring. Only for use in system_trusted_keyring_init().
+ */
+static __init struct key_restriction *get_builtin_and_secondary_restriction(void)
+{
+ struct key_restriction *restriction;
+
+ restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+
+ if (!restriction)
+ panic("Can't allocate secondary trusted keyring restriction\n");
+
+ restriction->check = restrict_link_by_builtin_and_secondary_trusted;
+
+ return restriction;
}
#endif
@@ -91,7 +114,7 @@ static __init int system_trusted_keyring_init(void)
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
KEY_USR_WRITE),
KEY_ALLOC_NOT_IN_QUOTA,
- restrict_link_by_builtin_and_secondary_trusted,
+ get_builtin_and_secondary_restriction(),
NULL);
if (IS_ERR(secondary_trusted_keys))
panic("Can't allocate secondary trusted keyring\n");