forked from Minki/linux
556d971bda
If we can't parse the PKCS7 in the appended modsig, we will free the modsig
structure and then access one of its members to determine the error value.
Fixes: 39b0709636
("ima: Implement support for module-style appended signatures")
Reported-by: kbuild test robot <lkp@intel.com>
Reported-by: Julia Lawall <julia.lawall@lip6.fr>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com>
Reviewed-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
169 lines
4.0 KiB
C
169 lines
4.0 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* IMA support for appraising module-style appended signatures.
|
|
*
|
|
* Copyright (C) 2019 IBM Corporation
|
|
*
|
|
* Author:
|
|
* Thiago Jung Bauermann <bauerman@linux.ibm.com>
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/module_signature.h>
|
|
#include <keys/asymmetric-type.h>
|
|
#include <crypto/pkcs7.h>
|
|
|
|
#include "ima.h"
|
|
|
|
struct modsig {
|
|
struct pkcs7_message *pkcs7_msg;
|
|
|
|
enum hash_algo hash_algo;
|
|
|
|
/* This digest will go in the 'd-modsig' field of the IMA template. */
|
|
const u8 *digest;
|
|
u32 digest_size;
|
|
|
|
/*
|
|
* This is what will go to the measurement list if the template requires
|
|
* storing the signature.
|
|
*/
|
|
int raw_pkcs7_len;
|
|
u8 raw_pkcs7[];
|
|
};
|
|
|
|
/**
|
|
* ima_hook_supports_modsig - can the policy allow modsig for this hook?
|
|
*
|
|
* modsig is only supported by hooks using ima_post_read_file(), because only
|
|
* they preload the contents of the file in a buffer. FILE_CHECK does that in
|
|
* some cases, but not when reached from vfs_open(). POLICY_CHECK can support
|
|
* it, but it's not useful in practice because it's a text file so deny.
|
|
*/
|
|
bool ima_hook_supports_modsig(enum ima_hooks func)
|
|
{
|
|
switch (func) {
|
|
case KEXEC_KERNEL_CHECK:
|
|
case KEXEC_INITRAMFS_CHECK:
|
|
case MODULE_CHECK:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ima_read_modsig - Read modsig from buf.
|
|
*
|
|
* Return: 0 on success, error code otherwise.
|
|
*/
|
|
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
|
struct modsig **modsig)
|
|
{
|
|
const size_t marker_len = strlen(MODULE_SIG_STRING);
|
|
const struct module_signature *sig;
|
|
struct modsig *hdr;
|
|
size_t sig_len;
|
|
const void *p;
|
|
int rc;
|
|
|
|
if (buf_len <= marker_len + sizeof(*sig))
|
|
return -ENOENT;
|
|
|
|
p = buf + buf_len - marker_len;
|
|
if (memcmp(p, MODULE_SIG_STRING, marker_len))
|
|
return -ENOENT;
|
|
|
|
buf_len -= marker_len;
|
|
sig = (const struct module_signature *)(p - sizeof(*sig));
|
|
|
|
rc = mod_check_sig(sig, buf_len, func_tokens[func]);
|
|
if (rc)
|
|
return rc;
|
|
|
|
sig_len = be32_to_cpu(sig->sig_len);
|
|
buf_len -= sig_len + sizeof(*sig);
|
|
|
|
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
|
|
hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
|
|
if (!hdr)
|
|
return -ENOMEM;
|
|
|
|
hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
|
|
if (IS_ERR(hdr->pkcs7_msg)) {
|
|
rc = PTR_ERR(hdr->pkcs7_msg);
|
|
kfree(hdr);
|
|
return rc;
|
|
}
|
|
|
|
memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
|
|
hdr->raw_pkcs7_len = sig_len;
|
|
|
|
/* We don't know the hash algorithm yet. */
|
|
hdr->hash_algo = HASH_ALGO__LAST;
|
|
|
|
*modsig = hdr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ima_collect_modsig - Calculate the file hash without the appended signature.
|
|
*
|
|
* Since the modsig is part of the file contents, the hash used in its signature
|
|
* isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
|
|
* calculates a separate one for signature verification.
|
|
*/
|
|
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
|
|
{
|
|
int rc;
|
|
|
|
/*
|
|
* Provide the file contents (minus the appended sig) so that the PKCS7
|
|
* code can calculate the file hash.
|
|
*/
|
|
size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
|
|
sizeof(struct module_signature);
|
|
rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
|
|
if (rc)
|
|
return;
|
|
|
|
/* Ask the PKCS7 code to calculate the file hash. */
|
|
rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
|
|
&modsig->digest_size, &modsig->hash_algo);
|
|
}
|
|
|
|
int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
|
|
{
|
|
return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
|
|
VERIFYING_MODULE_SIGNATURE, NULL, NULL);
|
|
}
|
|
|
|
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
|
|
const u8 **digest, u32 *digest_size)
|
|
{
|
|
*algo = modsig->hash_algo;
|
|
*digest = modsig->digest;
|
|
*digest_size = modsig->digest_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
|
u32 *data_len)
|
|
{
|
|
*data = &modsig->raw_pkcs7;
|
|
*data_len = modsig->raw_pkcs7_len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ima_free_modsig(struct modsig *modsig)
|
|
{
|
|
if (!modsig)
|
|
return;
|
|
|
|
pkcs7_free_message(modsig->pkcs7_msg);
|
|
kfree(modsig);
|
|
}
|