535.247.01

This commit is contained in:
Bernhard Stoeckner
2025-04-17 17:45:32 +02:00
parent 855c3c9d3c
commit f468568958
33 changed files with 641 additions and 199 deletions

View File

@@ -63,7 +63,9 @@
* old or even just user disabled. If we should use LKCA, include headers, else
* define stubs to return errors.
*/
#if defined(NV_CRYPTO_PRESENT) && defined (NV_CONFIG_CRYPTO_PRESENT)
#if defined(NV_CRYPTO_PRESENT) && defined (NV_CONFIG_CRYPTO_PRESENT) && \
(defined(NV_CRYPTO_AKCIPHER_VERIFY_PRESENT) || \
(defined(NV_CRYPTO_SIG_H_PRESENT) && defined(NV_ECC_DIGITS_FROM_BYTES_PRESENT)))
#define USE_LKCA 1
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -30,14 +30,26 @@ MODULE_SOFTDEP("pre: ecdh_generic,ecdsa_generic");
#include <crypto/akcipher.h>
#include <crypto/ecdh.h>
#include <crypto/internal/ecc.h>
#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
#include <crypto/sig.h>
struct signature
{
u64 r[ECC_MAX_DIGITS];
u64 s[ECC_MAX_DIGITS];
};
#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
#define ECDSA_PUBKEY_HEADER_XY_PRESENT (0x4)
struct ecc_ctx {
unsigned int curve_id;
u64 priv_key[ECC_MAX_DIGITS]; // In big endian
struct {
// ecdsa wants byte preceding pub_key to be set to '4'
u64 pub_key_prefix;
// ecdsa pubkey has header indicating length of pubkey
u8 padding[7];
u8 pub_key_prefix;
u64 pub_key[2 * ECC_MAX_DIGITS];
};
@@ -46,7 +58,7 @@ struct ecc_ctx {
char const *name;
int size;
};
#endif
#endif // USE_LKCA
void *libspdm_ec_new_by_nid(size_t nid)
{
@@ -77,7 +89,7 @@ void *libspdm_ec_new_by_nid(size_t nid)
ctx->priv_key_set = false;
return ctx;
#endif
#endif // USE_LKCA
}
void libspdm_ec_free(void *ec_context)
@@ -109,7 +121,7 @@ bool lkca_ecdsa_set_priv_key(void *context, uint8_t *key, size_t key_size)
ctx->pub_key_set = true;
ctx->priv_key_set = true;
return true;
#endif
#endif // USE_LKCA
}
bool lkca_ec_set_pub_key(void *ec_context, const uint8_t *public_key,
@@ -139,7 +151,7 @@ bool lkca_ec_set_pub_key(void *ec_context, const uint8_t *public_key,
memcpy(ctx->pub_key, public_key, public_key_size);
ctx->pub_key_set = true;
return true;
#endif
#endif // USE_LKCA
}
bool lkca_ec_get_pub_key(void *ec_context, uint8_t *public_key,
@@ -158,7 +170,7 @@ bool lkca_ec_get_pub_key(void *ec_context, uint8_t *public_key,
memcpy(public_key, ctx->pub_key, ctx->size);
return true;
#endif
#endif // USE_LKCA
}
bool lkca_ec_generate_key(void *ec_context, uint8_t *public_data,
@@ -185,7 +197,7 @@ bool lkca_ec_generate_key(void *ec_context, uint8_t *public_data,
ctx->pub_key_set = true;
return true;
#endif
#endif // USE_LKCA
}
bool lkca_ec_compute_key(void *ec_context, const uint8_t *peer_public,
@@ -218,28 +230,87 @@ bool lkca_ec_compute_key(void *ec_context, const uint8_t *peer_public,
*key_size = ctx->size / 2;
return true;
#endif
#endif // USE_LKCA
}
bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
const uint8_t *message_hash, size_t hash_size,
const uint8_t *signature, size_t sig_size)
#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
static bool lkca_ecdsa_verify_crypto_sig(void *ec_context, size_t hash_nid,
const uint8_t *message_hash, size_t hash_size,
const uint8_t *signature, size_t sig_size)
{
#ifndef USE_LKCA
return false;
#else
#else // USE_LKCA
struct ecc_ctx *ctx = ec_context;
u8 *pub_key;
int err;
DECLARE_CRYPTO_WAIT(wait);
struct crypto_sig * tfm = NULL;
struct signature sig;
if (sig_size != ctx->size || !ctx->pub_key_set)
{
return false;
}
tfm = crypto_alloc_sig(ctx->name, CRYPTO_ALG_TYPE_SIG, 0);
if (IS_ERR(tfm)) {
pr_info("crypto_alloc_sig failed in lkca_ecdsa_verify\n");
return false;
}
// modify header of pubkey to indicate size
pub_key = (u8 *) &(ctx->pub_key_prefix);
*pub_key = ECDSA_PUBKEY_HEADER_XY_PRESENT;
err = crypto_sig_set_pubkey(tfm, pub_key, ctx->size + 1);
if (err != 0)
{
pr_info("crypto_sig_set_pubkey failed in lkca_ecdsa_verify: %d", -err);
goto failTfm;
}
//
// Compared to the way we receive the signature, we need to:
// - swap order of all digits
// - swap endianness for each digit
//
memset(&sig, 0, sizeof(sig));
ecc_digits_from_bytes(signature, ctx->size/2, sig.r, ECC_MAX_DIGITS);
ecc_digits_from_bytes(signature + ctx->size/2, ctx->size/2, sig.s, ECC_MAX_DIGITS);
err = crypto_sig_verify(tfm, (void *)&sig, sizeof(sig), message_hash, hash_size);
if (err != 0)
{
pr_info("crypto_sig_verify failed in lkca_ecdsa_verify %d\n", -err);
}
failTfm:
crypto_free_sig(tfm);
return err == 0;
#endif // USE_LKCA
}
#else // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
static bool lkca_ecdsa_verify_akcipher(void *ec_context, size_t hash_nid,
const uint8_t *message_hash, size_t hash_size,
const uint8_t *signature, size_t sig_size)
{
#ifndef USE_LKCA
return false;
#else // USE_LKCA
struct ecc_ctx *ctx = ec_context;
u8 *pub_key;
int err;
DECLARE_CRYPTO_WAIT(wait);
// Roundabout way
u64 ber_max_len = 3 + 2 * (4 + (ECC_MAX_BYTES));
u64 ber_len = 0;
u8 *ber = NULL;
u8 *pub_key;
struct akcipher_request *req = NULL;
struct crypto_akcipher *tfm = NULL;
struct scatterlist sg;
DECLARE_CRYPTO_WAIT(wait);
int err;
if (sig_size != ctx->size) {
return false;
@@ -251,21 +322,21 @@ bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
tfm = crypto_alloc_akcipher(ctx->name, CRYPTO_ALG_TYPE_AKCIPHER, 0);
if (IS_ERR(tfm)) {
pr_info("ALLOC FAILED\n");
pr_info("crypto_alloc_akcipher failed in lkca_ecdsa_verify\n");
return false;
}
pub_key = (u8 *) ctx->pub_key;
pub_key--; // Go back into byte of pub_key_prefix
*pub_key = 4; // And set it to 4 to placate kernel
// modify header of pubkey to indicate size
pub_key = (u8 *) &(ctx->pub_key_prefix);
*pub_key = ECDSA_PUBKEY_HEADER_XY_PRESENT;
if ((err = crypto_akcipher_set_pub_key(tfm, pub_key, ctx->size + 1)) != 0) {
pr_info("SET PUB KEY FAILED: %d\n", -err);
pr_info("crypto_akcipher_set_pub_key failed in lkca_ecdsa_verify: %d\n", -err);
goto failTfm;
}
req = akcipher_request_alloc(tfm, GFP_KERNEL);
if (IS_ERR(req)) {
pr_info("REQUEST ALLOC FAILED\n");
pr_info("akcipher_request_alloc failed in lkca_ecdsa_verify\n");
goto failTfm;
}
@@ -310,9 +381,8 @@ bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait);
akcipher_request_set_crypt(req, &sg, NULL, ber_len, hash_size);
err = crypto_wait_req(crypto_akcipher_verify(req), &wait);
if (err != 0){
pr_info("Verify FAILED %d\n", -err);
pr_info("crypto_akcipher_verify failed in lkca_ecdsa_verify %d\n", -err);
}
kfree(ber);
@@ -322,5 +392,19 @@ failTfm:
crypto_free_akcipher(tfm);
return err == 0;
#endif
#endif // USE_LKCA
}
#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
bool lkca_ecdsa_verify(void *ec_context, size_t hash_nid,
const uint8_t *message_hash, size_t hash_size,
const uint8_t *signature, size_t sig_size)
{
#ifndef NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
return lkca_ecdsa_verify_crypto_sig(ec_context, hash_nid, message_hash, hash_size,
signature, sig_size);
#else // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
return lkca_ecdsa_verify_akcipher(ec_context, hash_nid, message_hash, hash_size,
signature, sig_size);
#endif // NV_CRYPTO_AKCIPHER_VERIFY_PRESENT
}

View File

@@ -143,6 +143,10 @@ nvidia_vma_access(
return -EINVAL;
}
if (write && !(mmap_context->prot & NV_PROTECT_WRITEABLE))
{
return -EACCES;
}
offset = mmap_context->mmap_start;
if (nv->flags & NV_FLAG_CONTROL)

View File

@@ -159,6 +159,7 @@ NV_CONFTEST_FUNCTION_COMPILE_TESTS += vga_tryget
NV_CONFTEST_FUNCTION_COMPILE_TESTS += cc_platform_has
NV_CONFTEST_FUNCTION_COMPILE_TESTS += seq_read_iter
NV_CONFTEST_FUNCTION_COMPILE_TESTS += follow_pfn
NV_CONFTEST_FUNCTION_COMPILE_TESTS += ptep_get
NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_gem_object_get
NV_CONFTEST_FUNCTION_COMPILE_TESTS += drm_gem_object_put_unlocked
NV_CONFTEST_FUNCTION_COMPILE_TESTS += add_memory_driver_managed
@@ -225,7 +226,11 @@ NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_tsec_comms_alloc_me
NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_tsec_comms_free_gscco_mem
NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_memory_block_size_bytes
NV_CONFTEST_SYMBOL_COMPILE_TESTS += crypto
NV_CONFTEST_SYMBOL_COMPILE_TESTS += crypto_akcipher_verify
NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_follow_pte
NV_CONFTEST_SYMBOL_COMPILE_TESTS += follow_pte_arg_vma
NV_CONFTEST_SYMBOL_COMPILE_TESTS += is_export_symbol_present_follow_pfnmap_start
NV_CONFTEST_SYMBOL_COMPILE_TESTS += ecc_digits_from_bytes
NV_CONFTEST_TYPE_COMPILE_TESTS += dma_ops
NV_CONFTEST_TYPE_COMPILE_TESTS += swiotlb_dma_ops
@@ -268,3 +273,4 @@ NV_CONFTEST_GENERIC_COMPILE_TESTS += mdev_available
NV_CONFTEST_GENERIC_COMPILE_TESTS += cmd_uphy_display_port_init
NV_CONFTEST_GENERIC_COMPILE_TESTS += cmd_uphy_display_port_off
NV_CONFTEST_GENERIC_COMPILE_TESTS += memory_failure_mf_sw_simulated_defined
NV_CONFTEST_GENERIC_COMPILE_TESTS += module_import_ns_takes_constant

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 1999-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 1999-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -32,14 +32,27 @@
#define NV_NUM_PIN_PAGES_PER_ITERATION 0x80000
#endif
static inline int nv_follow_pfn(struct vm_area_struct *vma,
unsigned long address,
unsigned long *pfn)
static inline int nv_follow_flavors(struct vm_area_struct *vma,
unsigned long address,
unsigned long *pfn)
{
#if defined(NV_FOLLOW_PFN_PRESENT)
return follow_pfn(vma, address, pfn);
#else
#if NV_IS_EXPORT_SYMBOL_PRESENT_follow_pte
#if NV_IS_EXPORT_SYMBOL_PRESENT_follow_pfnmap_start
struct follow_pfnmap_args args = {};
int rc;
args.address = address;
args.vma = vma;
rc = follow_pfnmap_start(&args);
if (rc)
return rc;
*pfn = args.pfn;
follow_pfnmap_end(&args);
return 0;
#elif NV_IS_EXPORT_SYMBOL_PRESENT_follow_pte
int status = 0;
spinlock_t *ptl;
pte_t *ptep;
@@ -47,17 +60,40 @@ static inline int nv_follow_pfn(struct vm_area_struct *vma,
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
return status;
//
// The first argument of follow_pte() was changed from
// mm_struct to vm_area_struct in kernel 6.10.
//
#if defined(NV_FOLLOW_PTE_ARG1_VMA)
status = follow_pte(vma, address, &ptep, &ptl);
#else
status = follow_pte(vma->vm_mm, address, &ptep, &ptl);
#endif
if (status)
return status;
#if defined(NV_PTEP_GET_PRESENT)
*pfn = pte_pfn(ptep_get(ptep));
#else
*pfn = pte_pfn(READ_ONCE(*ptep));
#endif
// The lock is acquired inside follow_pte()
pte_unmap_unlock(ptep, ptl);
return 0;
#else // NV_IS_EXPORT_SYMBOL_PRESENT_follow_pte
#else
return -1;
#endif // NV_IS_EXPORT_SYMBOL_PRESENT_follow_pte
#endif // NV_IS_EXPORT_SYMBOL_PRESENT_follow_pfnmap_start
}
static inline int nv_follow_pfn(struct vm_area_struct *vma,
unsigned long address,
unsigned long *pfn)
{
#if defined(NV_FOLLOW_PFN_PRESENT)
return follow_pfn(vma, address, pfn);
#else
return nv_follow_flavors(vma, address, pfn);
#endif
}