cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ima_modsig.c (3542B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * IMA support for appraising module-style appended signatures.
      4 *
      5 * Copyright (C) 2019  IBM Corporation
      6 *
      7 * Author:
      8 * Thiago Jung Bauermann <bauerman@linux.ibm.com>
      9 */
     10
     11#include <linux/types.h>
     12#include <linux/module_signature.h>
     13#include <keys/asymmetric-type.h>
     14#include <crypto/pkcs7.h>
     15
     16#include "ima.h"
     17
     18struct modsig {
     19	struct pkcs7_message *pkcs7_msg;
     20
     21	enum hash_algo hash_algo;
     22
     23	/* This digest will go in the 'd-modsig' field of the IMA template. */
     24	const u8 *digest;
     25	u32 digest_size;
     26
     27	/*
     28	 * This is what will go to the measurement list if the template requires
     29	 * storing the signature.
     30	 */
     31	int raw_pkcs7_len;
     32	u8 raw_pkcs7[];
     33};
     34
     35/*
     36 * ima_read_modsig - Read modsig from buf.
     37 *
     38 * Return: 0 on success, error code otherwise.
     39 */
     40int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
     41		    struct modsig **modsig)
     42{
     43	const size_t marker_len = strlen(MODULE_SIG_STRING);
     44	const struct module_signature *sig;
     45	struct modsig *hdr;
     46	size_t sig_len;
     47	const void *p;
     48	int rc;
     49
     50	if (buf_len <= marker_len + sizeof(*sig))
     51		return -ENOENT;
     52
     53	p = buf + buf_len - marker_len;
     54	if (memcmp(p, MODULE_SIG_STRING, marker_len))
     55		return -ENOENT;
     56
     57	buf_len -= marker_len;
     58	sig = (const struct module_signature *)(p - sizeof(*sig));
     59
     60	rc = mod_check_sig(sig, buf_len, func_tokens[func]);
     61	if (rc)
     62		return rc;
     63
     64	sig_len = be32_to_cpu(sig->sig_len);
     65	buf_len -= sig_len + sizeof(*sig);
     66
     67	/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
     68	hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
     69	if (!hdr)
     70		return -ENOMEM;
     71
     72	hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
     73	if (IS_ERR(hdr->pkcs7_msg)) {
     74		rc = PTR_ERR(hdr->pkcs7_msg);
     75		kfree(hdr);
     76		return rc;
     77	}
     78
     79	memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
     80	hdr->raw_pkcs7_len = sig_len;
     81
     82	/* We don't know the hash algorithm yet. */
     83	hdr->hash_algo = HASH_ALGO__LAST;
     84
     85	*modsig = hdr;
     86
     87	return 0;
     88}
     89
     90/**
     91 * ima_collect_modsig - Calculate the file hash without the appended signature.
     92 *
     93 * Since the modsig is part of the file contents, the hash used in its signature
     94 * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
     95 * calculates a separate one for signature verification.
     96 */
     97void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
     98{
     99	int rc;
    100
    101	/*
    102	 * Provide the file contents (minus the appended sig) so that the PKCS7
    103	 * code can calculate the file hash.
    104	 */
    105	size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
    106		sizeof(struct module_signature);
    107	rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
    108	if (rc)
    109		return;
    110
    111	/* Ask the PKCS7 code to calculate the file hash. */
    112	rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
    113			      &modsig->digest_size, &modsig->hash_algo);
    114}
    115
    116int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
    117{
    118	return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
    119					VERIFYING_MODULE_SIGNATURE, NULL, NULL);
    120}
    121
    122int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
    123			  const u8 **digest, u32 *digest_size)
    124{
    125	*algo = modsig->hash_algo;
    126	*digest = modsig->digest;
    127	*digest_size = modsig->digest_size;
    128
    129	return 0;
    130}
    131
    132int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
    133		       u32 *data_len)
    134{
    135	*data = &modsig->raw_pkcs7;
    136	*data_len = modsig->raw_pkcs7_len;
    137
    138	return 0;
    139}
    140
    141void ima_free_modsig(struct modsig *modsig)
    142{
    143	if (!modsig)
    144		return;
    145
    146	pkcs7_free_message(modsig->pkcs7_msg);
    147	kfree(modsig);
    148}