Skip to content

Commit

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

Pull security subsystem updates from James Morris:
 "Highlights:

   - A new LSM, "LoadPin", from Kees Cook is added, which allows forcing
     of modules and firmware to be loaded from a specific device (this
     is from ChromeOS, where the device as a whole is verified
     cryptographically via dm-verity).

     This is disabled by default but can be configured to be enabled by
     default (don't do this if you don't know what you're doing).

   - Keys: allow authentication data to be stored in an asymmetric key.
     Lots of general fixes and updates.

   - SELinux: add restrictions for loading of kernel modules via
     finit_module().  Distinguish non-init user namespace capability
     checks.  Apply execstack check on thread stacks"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (48 commits)
  LSM: LoadPin: provide enablement CONFIG
  Yama: use atomic allocations when reporting
  seccomp: Fix comment typo
  ima: add support for creating files using the mknodat syscall
  ima: fix ima_inode_post_setattr
  vfs: forbid write access when reading a file into memory
  fs: fix over-zealous use of "const"
  selinux: apply execstack check on thread stacks
  selinux: distinguish non-init user namespace capability checks
  LSM: LoadPin for kernel file loading restrictions
  fs: define a string representation of the kernel_read_file_id enumeration
  Yama: consolidate error reporting
  string_helpers: add kstrdup_quotable_file
  string_helpers: add kstrdup_quotable_cmdline
  string_helpers: add kstrdup_quotable
  selinux: check ss_initialized before revalidating an inode label
  selinux: delay inode label lookup as long as possible
  selinux: don't revalidate an inode's label when explicitly setting it
  selinux: Change bool variable name to index.
  KEYS: Add KEYCTL_DH_COMPUTE command
  ...
  • Loading branch information
torvalds committed May 19, 2016
2 parents 2600a46 + b937190 commit f4f27d0
Show file tree
Hide file tree
Showing 82 changed files with 1,915 additions and 807 deletions.
17 changes: 17 additions & 0 deletions Documentation/security/LoadPin.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
LoadPin is a Linux Security Module that ensures all kernel-loaded files
(modules, firmware, etc) all originate from the same filesystem, with
the expectation that such a filesystem is backed by a read-only device
such as dm-verity or CDROM. This allows systems that have a verified
and/or unchangeable filesystem to enforce module and firmware loading
restrictions without needing to sign the files individually.

The LSM is selectable at build-time with CONFIG_SECURITY_LOADPIN, and
can be controlled at boot-time with the kernel command line option
"loadpin.enabled". By default, it is enabled, but can be disabled at
boot ("loadpin.enabled=0").

LoadPin starts pinning when it sees the first file loaded. If the
block device backing the filesystem is not read-only, a sysctl is
created to toggle pinning: /proc/sys/kernel/loadpin/enabled. (Having
a mutable filesystem means pinning is mutable too, but having the
sysctl allows for easy testing on systems with a mutable filesystem.)
52 changes: 52 additions & 0 deletions Documentation/security/keys.txt
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,36 @@ The keyctl syscall functions are:
A process must have search permission on the key for this function to be
successful.

(*) Compute a Diffie-Hellman shared secret or public key

long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
char *buffer, size_t buflen);

The params struct contains serial numbers for three keys:

- The prime, p, known to both parties
- The local private key
- The base integer, which is either a shared generator or the
remote public key

The value computed is:

result = base ^ private (mod prime)

If the base is the shared generator, the result is the local
public key. If the base is the remote public key, the result is
the shared secret.

The buffer length must be at least the length of the prime, or zero.

If the buffer length is nonzero, the length of the result is
returned when it is successfully calculated and copied in to the
buffer. When the buffer length is zero, the minimum required
buffer length is returned.

This function will return error EOPNOTSUPP if the key type is not
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller.

===============
KERNEL SERVICES
Expand Down Expand Up @@ -999,6 +1029,10 @@ payload contents" for more information.
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred,
key_perm_t perm,
int (*restrict_link)(struct key *,
const struct key_type *,
unsigned long,
const union key_payload *),
unsigned long flags,
struct key *dest);

Expand All @@ -1010,6 +1044,24 @@ payload contents" for more information.
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
towards the user's quota). Error ENOMEM can also be returned.

If restrict_link not NULL, it should point to a function that will be
called each time an attempt is made to link a key into the new keyring.
This function is called to check whether a key may be added into the keying
or not. Callers of key_create_or_update() within the kernel can pass
KEY_ALLOC_BYPASS_RESTRICTION to suppress the check. An example of using
this is to manage rings of cryptographic keys that are set up when the
kernel boots where userspace is also permitted to add keys - provided they
can be verified by a key the kernel already has.

When called, the restriction function will be passed the keyring being
added to, the key flags value and the type and payload of the key being
added. Note that when a new key is being created, this is called between
payload preparsing and actual key creation. The function should return 0
to allow the link or an error to reject it.

A convenience function, restrict_link_reject, exists to always return
-EPERM to in this case.


(*) To check the validity of a key, this function can be called:

Expand Down
6 changes: 6 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -10025,6 +10025,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
S: Supported
F: security/apparmor/

LOADPIN SECURITY MODULE
M: Kees Cook <[email protected]>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
S: Supported
F: security/loadpin/

YAMA SECURITY MODULE
M: Kees Cook <[email protected]>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
Expand Down
18 changes: 4 additions & 14 deletions arch/x86/kernel/kexec-bzimage64.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/efi.h>
#include <linux/verify_pefile.h>
#include <keys/system_keyring.h>
#include <linux/verification.h>

#include <asm/bootparam.h>
#include <asm/setup.h>
Expand Down Expand Up @@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data)
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
{
bool trusted;
int ret;

ret = verify_pefile_signature(kernel, kernel_len,
system_trusted_keyring,
VERIFYING_KEXEC_PE_SIGNATURE,
&trusted);
if (ret < 0)
return ret;
if (!trusted)
return -EKEYREJECTED;
return 0;
return verify_pefile_signature(kernel, kernel_len,
NULL,
VERIFYING_KEXEC_PE_SIGNATURE);
}
#endif

Expand Down
9 changes: 9 additions & 0 deletions certs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ config MODULE_SIG_KEY
config SYSTEM_TRUSTED_KEYRING
bool "Provide system-wide ring of trusted keys"
depends on KEYS
depends on ASYMMETRIC_KEY_TYPE
help
Provide a system keyring to which trusted keys can be added. Keys in
the keyring are considered to be trusted. Keys may be added at will
Expand Down Expand Up @@ -55,4 +56,12 @@ config SYSTEM_EXTRA_CERTIFICATE_SIZE
This is the number of bytes reserved in the kernel image for a
certificate to be inserted.

config SECONDARY_TRUSTED_KEYRING
bool "Provide a keyring to which extra trustable keys may be added"
depends on SYSTEM_TRUSTED_KEYRING
help
If set, provide a keyring to which extra keys may be added, provided
those keys are not blacklisted and are vouched for by a key built
into the kernel or already in the secondary trusted keyring.

endmenu
139 changes: 113 additions & 26 deletions certs/system_keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,88 @@
#include <keys/system_keyring.h>
#include <crypto/pkcs7.h>

struct key *system_trusted_keyring;
EXPORT_SYMBOL_GPL(system_trusted_keyring);
static struct key *builtin_trusted_keys;
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
static struct key *secondary_trusted_keys;
#endif

extern __initconst const u8 system_certificate_list[];
extern __initconst const unsigned long system_certificate_list_size;

/**
* restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
*
* 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,
const struct key_type *type,
const union key_payload *payload)
{
return restrict_link_by_signature(builtin_trusted_keys, type, payload);
}

#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
/**
* restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
* addition by both builtin and secondary keyrings
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in either the built-in or the secondary system
* keyrings.
*/
int restrict_link_by_builtin_and_secondary_trusted(
struct key *keyring,
const struct key_type *type,
const union key_payload *payload)
{
/* 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 &&
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);
}
#endif

/*
* Load the compiled-in keys
* Create the trusted keyrings
*/
static __init int system_trusted_keyring_init(void)
{
pr_notice("Initialise system trusted keyring\n");
pr_notice("Initialise system trusted keyrings\n");

system_trusted_keyring =
keyring_alloc(".system_keyring",
builtin_trusted_keys =
keyring_alloc(".builtin_trusted_keys",
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, NULL);
if (IS_ERR(system_trusted_keyring))
panic("Can't allocate system trusted keyring\n");
KEY_ALLOC_NOT_IN_QUOTA,
NULL, NULL);
if (IS_ERR(builtin_trusted_keys))
panic("Can't allocate builtin trusted keyring\n");

#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
secondary_trusted_keys =
keyring_alloc(".secondary_trusted_keys",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
KEY_USR_WRITE),
KEY_ALLOC_NOT_IN_QUOTA,
restrict_link_by_builtin_and_secondary_trusted,
NULL);
if (IS_ERR(secondary_trusted_keys))
panic("Can't allocate secondary trusted keyring\n");

if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
panic("Can't link trusted keyrings\n");
#endif

set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
return 0;
}

Expand Down Expand Up @@ -76,16 +135,16 @@ static __init int load_system_certificate_list(void)
if (plen > end - p)
goto dodgy_cert;

key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
"asymmetric",
NULL,
p,
plen,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA |
KEY_ALLOC_TRUSTED |
KEY_ALLOC_BUILT_IN);
KEY_ALLOC_BUILT_IN |
KEY_ALLOC_BYPASS_RESTRICTION);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
Expand All @@ -108,27 +167,35 @@ late_initcall(load_system_certificate_list);
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION

/**
* Verify a PKCS#7-based signature on system data.
* @data: The data to be verified.
* verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
* @data: The data to be verified (NULL if expecting internal data).
* @len: Size of @data.
* @raw_pkcs7: The PKCS#7 message that is the signature.
* @pkcs7_len: The size of @raw_pkcs7.
* @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
* (void *)1UL for all trusted keys).
* @usage: The use to which the key is being put.
* @view_content: Callback to gain access to content.
* @ctx: Context for callback.
*/
int system_verify_data(const void *data, unsigned long len,
const void *raw_pkcs7, size_t pkcs7_len,
enum key_being_used_for usage)
int verify_pkcs7_signature(const void *data, size_t len,
const void *raw_pkcs7, size_t pkcs7_len,
struct key *trusted_keys,
enum key_being_used_for usage,
int (*view_content)(void *ctx,
const void *data, size_t len,
size_t asn1hdrlen),
void *ctx)
{
struct pkcs7_message *pkcs7;
bool trusted;
int ret;

pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
if (IS_ERR(pkcs7))
return PTR_ERR(pkcs7);

/* The data should be detached - so we need to supply it. */
if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
pr_err("PKCS#7 signature with non-detached data\n");
ret = -EBADMSG;
goto error;
Expand All @@ -138,20 +205,40 @@ int system_verify_data(const void *data, unsigned long len,
if (ret < 0)
goto error;

ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
if (ret < 0)
if (!trusted_keys) {
trusted_keys = builtin_trusted_keys;
} else if (trusted_keys == (void *)1UL) {
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
trusted_keys = secondary_trusted_keys;
#else
trusted_keys = builtin_trusted_keys;
#endif
}
ret = pkcs7_validate_trust(pkcs7, trusted_keys);
if (ret < 0) {
if (ret == -ENOKEY)
pr_err("PKCS#7 signature not signed with a trusted key\n");
goto error;
}

if (view_content) {
size_t asn1hdrlen;

ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
if (ret < 0) {
if (ret == -ENODATA)
pr_devel("PKCS#7 message does not contain data\n");
goto error;
}

if (!trusted) {
pr_err("PKCS#7 signature not signed with a trusted key\n");
ret = -ENOKEY;
ret = view_content(ctx, data, len, asn1hdrlen);
}

error:
pkcs7_free_message(pkcs7);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL_GPL(system_verify_data);
EXPORT_SYMBOL_GPL(verify_pkcs7_signature);

#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
6 changes: 3 additions & 3 deletions crypto/asymmetric_keys/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
menuconfig ASYMMETRIC_KEY_TYPE
tristate "Asymmetric (public-key cryptographic) key type"
bool "Asymmetric (public-key cryptographic) key type"
depends on KEYS
help
This option provides support for a key type that holds the data for
Expand Down Expand Up @@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER

config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
depends on PKCS7_MESSAGE_PARSER
select SYSTEM_TRUSTED_KEYRING
depends on SYSTEM_DATA_VERIFICATION
help
This option provides a type of key that can be loaded up from a
PKCS#7 message - provided the message is signed by a trusted key. If
Expand All @@ -54,6 +53,7 @@ config PKCS7_TEST_KEY
config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
depends on SYSTEM_DATA_VERIFICATION
select ASN1
select OID_REGISTRY
help
Expand Down
Loading

0 comments on commit f4f27d0

Please sign in to comment.