linux/security/integrity/digsig_asymmetric.c
Linus Torvalds 028db3e290 Revert "Merge tag 'keys-acl-20190703' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs"
This reverts merge 0f75ef6a9c (and thus
effectively commits

   7a1ade8475 ("keys: Provide KEYCTL_GRANT_PERMISSION")
   2e12256b9a ("keys: Replace uid/gid/perm permissions checking with an ACL")

that the merge brought in).

It turns out that it breaks booting with an encrypted volume, and Eric
biggers reports that it also breaks the fscrypt tests [1] and loading of
in-kernel X.509 certificates [2].

The root cause of all the breakage is likely the same, but David Howells
is off email so rather than try to work it out it's getting reverted in
order to not impact the rest of the merge window.

 [1] https://lore.kernel.org/lkml/20190710011559.GA7973@sol.localdomain/
 [2] https://lore.kernel.org/lkml/20190710013225.GB7973@sol.localdomain/

Link: https://lore.kernel.org/lkml/CAHk-=wjxoeMJfeBahnWH=9zShKp2bsVy527vo3_y8HfOdhwAAw@mail.gmail.com/
Reported-by: Eric Biggers <ebiggers@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-07-10 18:43:43 -07:00

145 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Intel Corporation
*
* Author:
* Dmitry Kasatkin <dmitry.kasatkin@intel.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/ratelimit.h>
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <crypto/hash_info.h>
#include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
#include "integrity.h"
/*
* Request an asymmetric key.
*/
static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
{
struct key *key;
char name[12];
sprintf(name, "id:%08x", keyid);
pr_debug("key search: \"%s\"\n", name);
key = get_ima_blacklist_keyring();
if (key) {
key_ref_t kref;
kref = keyring_search(make_key_ref(key, 1),
&key_type_asymmetric, name, true);
if (!IS_ERR(kref)) {
pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
return ERR_PTR(-EKEYREJECTED);
}
}
if (keyring) {
/* search in specific keyring */
key_ref_t kref;
kref = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, name, true);
if (IS_ERR(kref))
key = ERR_CAST(kref);
else
key = key_ref_to_ptr(kref);
} else {
key = request_key(&key_type_asymmetric, name, NULL);
}
if (IS_ERR(key)) {
pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
name, PTR_ERR(key));
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return key;
}
}
pr_debug("%s() = 0 [%x]\n", __func__, key_serial(key));
return key;
}
int asymmetric_verify(struct key *keyring, const char *sig,
int siglen, const char *data, int datalen)
{
struct public_key_signature pks;
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
struct key *key;
int ret = -ENOMEM;
if (siglen <= sizeof(*hdr))
return -EBADMSG;
siglen -= sizeof(*hdr);
if (siglen != be16_to_cpu(hdr->sig_size))
return -EBADMSG;
if (hdr->hash_algo >= HASH_ALGO__LAST)
return -ENOPKG;
key = request_asymmetric_key(keyring, be32_to_cpu(hdr->keyid));
if (IS_ERR(key))
return PTR_ERR(key);
memset(&pks, 0, sizeof(pks));
pks.hash_algo = hash_algo_name[hdr->hash_algo];
if (hdr->hash_algo == HASH_ALGO_STREEBOG_256 ||
hdr->hash_algo == HASH_ALGO_STREEBOG_512) {
/* EC-RDSA and Streebog should go together. */
pks.pkey_algo = "ecrdsa";
pks.encoding = "raw";
} else {
pks.pkey_algo = "rsa";
pks.encoding = "pkcs1";
}
pks.digest = (u8 *)data;
pks.digest_size = datalen;
pks.s = hdr->sig;
pks.s_size = siglen;
ret = verify_signature(key, &pks);
key_put(key);
pr_debug("%s() = %d\n", __func__, ret);
return ret;
}
/**
* integrity_kernel_module_request - prevent crypto-pkcs1pad(rsa,*) requests
* @kmod_name: kernel module name
*
* We have situation, when public_key_verify_signature() in case of RSA
* algorithm use alg_name to store internal information in order to
* construct an algorithm on the fly, but crypto_larval_lookup() will try
* to use alg_name in order to load kernel module with same name.
* Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
* we are safe to fail such module request from crypto_larval_lookup().
*
* In this way we prevent modprobe execution during digsig verification
* and avoid possible deadlock if modprobe and/or it's dependencies
* also signed with digsig.
*/
int integrity_kernel_module_request(char *kmod_name)
{
if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
return -EINVAL;
return 0;
}