Linux Modules
 help / color / mirror / Atom feed
* [PATCH] arm64/acpi: Fix multiple issues in ACPI boot support code
From: Fidal Palamparambil @ 2025-09-06 12:27 UTC (permalink / raw)
  To: linux-modules
  Cc: mcgrof, petr.pavlu, da.gomez, samitolvanen, linux-kernel,
	Fidal palamparambil

From: Fidal palamparambil <rootuserhere@gmail.com>

- Fixed memory leak in acpi_fadt_sanity_check() by ensuring acpi_put_table()
  is called in all error paths
- Corrected error handling in parse_acpi() by removing incorrect snprintf() usage
- Added missing compiler_attributes.h include for fallthrough support
- Verified proper NULL pointer checks in acpi_os_ioremap()

These fixes address potential memory leaks, compilation warnings, and
improper error handling in the ARM64 ACPI boot support code.

Signed-off-by: Fidal palamparambil <rootuserhere@gmail.com>
---
 arch/arm64/kernel/acpi.c    |  17 +-
 arch/arm64/kernel/acpi.orig | 466 ++++++++++++++++++++++++++++++++++++
 2 files changed, 480 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/kernel/acpi.orig

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 4d529ff7ba51..218f39e5ae0f 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -14,6 +14,7 @@
 
 #include <linux/acpi.h>
 #include <linux/arm-smccc.h>
+#include <linux/compiler_attributes.h>
 #include <linux/cpumask.h>
 #include <linux/efi.h>
 #include <linux/efi-bgrt.h>
@@ -55,16 +56,26 @@ static int __init parse_acpi(char *arg)
 
 	/* "acpi=off" disables both ACPI table parsing and interpreter */
 	if (strcmp(arg, "off") == 0)
+	{
 		param_acpi_off = true;
+	}
 	else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
+	{
 		param_acpi_on = true;
+	}
 	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+	{
 		param_acpi_force = true;
+	}
 	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
+	{
 		param_acpi_nospcr = true;
+	}
 	else
-		return -EINVAL;	/* Core will print when we return error */
-
+	{
+		pr_err("ACPI: Invalid option '%s'\n", arg);
+		return -EINVAL;
+	}
 	return 0;
 }
 early_param("acpi", parse_acpi);
@@ -463,4 +474,4 @@ int acpi_unmap_cpu(int cpu)
 	return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
-#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
\ No newline at end of file
diff --git a/arch/arm64/kernel/acpi.orig b/arch/arm64/kernel/acpi.orig
new file mode 100644
index 000000000000..4d529ff7ba51
--- /dev/null
+++ b/arch/arm64/kernel/acpi.orig
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  ARM64 Specific Low-Level ACPI Boot Support
+ *
+ *  Copyright (C) 2013-2014, Linaro Ltd.
+ *	Author: Al Stone <al.stone@linaro.org>
+ *	Author: Graeme Gregory <graeme.gregory@linaro.org>
+ *	Author: Hanjun Guo <hanjun.guo@linaro.org>
+ *	Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ *	Author: Naresh Bhat <naresh.bhat@linaro.org>
+ */
+
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
+#include <linux/cpumask.h>
+#include <linux/efi.h>
+#include <linux/efi-bgrt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irq_work.h>
+#include <linux/memblock.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+#include <linux/smp.h>
+#include <linux/serial_core.h>
+#include <linux/suspend.h>
+#include <linux/pgtable.h>
+
+#include <acpi/ghes.h>
+#include <acpi/processor.h>
+#include <asm/cputype.h>
+#include <asm/cpu_ops.h>
+#include <asm/daifflags.h>
+#include <asm/smp_plat.h>
+
+int acpi_noirq = 1;		/* skip ACPI IRQ initialization */
+int acpi_disabled = 1;
+EXPORT_SYMBOL(acpi_disabled);
+
+int acpi_pci_disabled = 1;	/* skip ACPI PCI scan and IRQ initialization */
+EXPORT_SYMBOL(acpi_pci_disabled);
+
+static bool param_acpi_off __initdata;
+static bool param_acpi_on __initdata;
+static bool param_acpi_force __initdata;
+static bool param_acpi_nospcr __initdata;
+
+static int __init parse_acpi(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+
+	/* "acpi=off" disables both ACPI table parsing and interpreter */
+	if (strcmp(arg, "off") == 0)
+		param_acpi_off = true;
+	else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
+		param_acpi_on = true;
+	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+		param_acpi_force = true;
+	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
+		param_acpi_nospcr = true;
+	else
+		return -EINVAL;	/* Core will print when we return error */
+
+	return 0;
+}
+early_param("acpi", parse_acpi);
+
+static bool __init dt_is_stub(void)
+{
+	int node;
+
+	fdt_for_each_subnode(node, initial_boot_params, 0) {
+		const char *name = fdt_get_name(initial_boot_params, node, NULL);
+		if (strcmp(name, "chosen") == 0)
+			continue;
+		if (strcmp(name, "hypervisor") == 0 &&
+		    of_flat_dt_is_compatible(node, "xen,xen"))
+			continue;
+
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * __acpi_map_table() will be called before page_init(), so early_ioremap()
+ * or early_memremap() should be called here to for ACPI table mapping.
+ */
+void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
+{
+	if (!size)
+		return NULL;
+
+	return early_memremap(phys, size);
+}
+
+void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
+{
+	if (!map || !size)
+		return;
+
+	early_memunmap(map, size);
+}
+
+bool __init acpi_psci_present(void)
+{
+	return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
+}
+
+/* Whether HVC must be used instead of SMC as the PSCI conduit */
+bool acpi_psci_use_hvc(void)
+{
+	return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
+}
+
+/*
+ * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity
+ *			      checks on it
+ *
+ * Return 0 on success,  <0 on failure
+ */
+static int __init acpi_fadt_sanity_check(void)
+{
+	struct acpi_table_header *table;
+	struct acpi_table_fadt *fadt;
+	acpi_status status;
+	int ret = 0;
+
+	/*
+	 * FADT is required on arm64; retrieve it to check its presence
+	 * and carry out revision and ACPI HW reduced compliancy tests
+	 */
+	status = acpi_get_table(ACPI_SIG_FADT, 0, &table);
+	if (ACPI_FAILURE(status)) {
+		const char *msg = acpi_format_exception(status);
+
+		pr_err("Failed to get FADT table, %s\n", msg);
+		return -ENODEV;
+	}
+
+	fadt = (struct acpi_table_fadt *)table;
+
+	/*
+	 * Revision in table header is the FADT Major revision, and there
+	 * is a minor revision of FADT which was introduced by ACPI 5.1,
+	 * we only deal with ACPI 5.1 or newer revision to get GIC and SMP
+	 * boot protocol configuration data.
+	 */
+	if (table->revision < 5 ||
+	   (table->revision == 5 && fadt->minor_revision < 1)) {
+		pr_err(FW_BUG "Unsupported FADT revision %d.%d, should be 5.1+\n",
+		       table->revision, fadt->minor_revision);
+
+		if (!fadt->arm_boot_flags) {
+			ret = -EINVAL;
+			goto out;
+		}
+		pr_err("FADT has ARM boot flags set, assuming 5.1\n");
+	}
+
+	if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
+		pr_err("FADT not ACPI hardware reduced compliant\n");
+		ret = -EINVAL;
+	}
+
+out:
+	/*
+	 * acpi_get_table() creates FADT table mapping that
+	 * should be released after parsing and before resuming boot
+	 */
+	acpi_put_table(table);
+	return ret;
+}
+
+/*
+ * acpi_boot_table_init() called from setup_arch(), always.
+ *	1. find RSDP and get its address, and then find XSDT
+ *	2. extract all tables and checksums them all
+ *	3. check ACPI FADT revision
+ *	4. check ACPI FADT HW reduced flag
+ *
+ * We can parse ACPI boot-time tables such as MADT after
+ * this function is called.
+ *
+ * On return ACPI is enabled if either:
+ *
+ * - ACPI tables are initialized and sanity checks passed
+ * - acpi=force was passed in the command line and ACPI was not disabled
+ *   explicitly through acpi=off command line parameter
+ *
+ * ACPI is disabled on function return otherwise
+ */
+void __init acpi_boot_table_init(void)
+{
+	int ret;
+
+	/*
+	 * Enable ACPI instead of device tree unless
+	 * - ACPI has been disabled explicitly (acpi=off), or
+	 * - the device tree is not empty (it has more than just a /chosen node,
+	 *   and a /hypervisor node when running on Xen)
+	 *   and ACPI has not been [force] enabled (acpi=on|force)
+	 */
+	if (param_acpi_off ||
+	    (!param_acpi_on && !param_acpi_force && !dt_is_stub()))
+		goto done;
+
+	/*
+	 * ACPI is disabled at this point. Enable it in order to parse
+	 * the ACPI tables and carry out sanity checks
+	 */
+	enable_acpi();
+
+	/*
+	 * If ACPI tables are initialized and FADT sanity checks passed,
+	 * leave ACPI enabled and carry on booting; otherwise disable ACPI
+	 * on initialization error.
+	 * If acpi=force was passed on the command line it forces ACPI
+	 * to be enabled even if its initialization failed.
+	 */
+	if (acpi_table_init() || acpi_fadt_sanity_check()) {
+		pr_err("Failed to init ACPI tables\n");
+		if (!param_acpi_force)
+			disable_acpi();
+	}
+
+done:
+	if (acpi_disabled) {
+		if (earlycon_acpi_spcr_enable)
+			early_init_dt_scan_chosen_stdout();
+	} else {
+#ifdef CONFIG_HIBERNATION
+		struct acpi_table_header *facs = NULL;
+		acpi_get_table(ACPI_SIG_FACS, 1, &facs);
+		if (facs) {
+			swsusp_hardware_signature =
+				((struct acpi_table_facs *)facs)->hardware_signature;
+			acpi_put_table(facs);
+		}
+#endif
+
+		/*
+		 * For varying privacy and security reasons, sometimes need
+		 * to completely silence the serial console output, and only
+		 * enable it when needed.
+		 * But there are many existing systems that depend on this
+		 * behaviour, use acpi=nospcr to disable console in ACPI SPCR
+		 * table as default serial console.
+		 */
+		ret = acpi_parse_spcr(earlycon_acpi_spcr_enable,
+			!param_acpi_nospcr);
+		if (!ret || param_acpi_nospcr || !IS_ENABLED(CONFIG_ACPI_SPCR_TABLE))
+			pr_info("Use ACPI SPCR as default console: No\n");
+		else
+			pr_info("Use ACPI SPCR as default console: Yes\n");
+
+		if (IS_ENABLED(CONFIG_ACPI_BGRT))
+			acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
+	}
+}
+
+static pgprot_t __acpi_get_writethrough_mem_attribute(void)
+{
+	/*
+	 * Although UEFI specifies the use of Normal Write-through for
+	 * EFI_MEMORY_WT, it is seldom used in practice and not implemented
+	 * by most (all?) CPUs. Rather than allocate a MAIR just for this
+	 * purpose, emit a warning and use Normal Non-cacheable instead.
+	 */
+	pr_warn_once("No MAIR allocation for EFI_MEMORY_WT; treating as Normal Non-cacheable\n");
+	return __pgprot(PROT_NORMAL_NC);
+}
+
+pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
+{
+	/*
+	 * According to "Table 8 Map: EFI memory types to AArch64 memory
+	 * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is
+	 * mapped to a corresponding MAIR attribute encoding.
+	 * The EFI memory attribute advises all possible capabilities
+	 * of a memory region.
+	 */
+
+	u64 attr;
+
+	attr = efi_mem_attributes(addr);
+	if (attr & EFI_MEMORY_WB)
+		return PAGE_KERNEL;
+	if (attr & EFI_MEMORY_WC)
+		return __pgprot(PROT_NORMAL_NC);
+	if (attr & EFI_MEMORY_WT)
+		return __acpi_get_writethrough_mem_attribute();
+	return __pgprot(PROT_DEVICE_nGnRnE);
+}
+
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+{
+	efi_memory_desc_t *md, *region = NULL;
+	pgprot_t prot;
+
+	if (WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))
+		return NULL;
+
+	for_each_efi_memory_desc(md) {
+		u64 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+		if (phys < md->phys_addr || phys >= end)
+			continue;
+
+		if (phys + size > end) {
+			pr_warn(FW_BUG "requested region covers multiple EFI memory regions\n");
+			return NULL;
+		}
+		region = md;
+		break;
+	}
+
+	/*
+	 * It is fine for AML to remap regions that are not represented in the
+	 * EFI memory map at all, as it only describes normal memory, and MMIO
+	 * regions that require a virtual mapping to make them accessible to
+	 * the EFI runtime services.
+	 */
+	prot = __pgprot(PROT_DEVICE_nGnRnE);
+	if (region) {
+		switch (region->type) {
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+		case EFI_PERSISTENT_MEMORY:
+			if (memblock_is_map_memory(phys) ||
+			    !memblock_is_region_memory(phys, size)) {
+				pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+				return NULL;
+			}
+			/*
+			 * Mapping kernel memory is permitted if the region in
+			 * question is covered by a single memblock with the
+			 * NOMAP attribute set: this enables the use of ACPI
+			 * table overrides passed via initramfs, which are
+			 * reserved in memory using arch_reserve_mem_area()
+			 * below. As this particular use case only requires
+			 * read access, fall through to the R/O mapping case.
+			 */
+			fallthrough;
+
+		case EFI_RUNTIME_SERVICES_CODE:
+			/*
+			 * This would be unusual, but not problematic per se,
+			 * as long as we take care not to create a writable
+			 * mapping for executable code.
+			 */
+			prot = PAGE_KERNEL_RO;
+			break;
+
+		case EFI_ACPI_RECLAIM_MEMORY:
+			/*
+			 * ACPI reclaim memory is used to pass firmware tables
+			 * and other data that is intended for consumption by
+			 * the OS only, which may decide it wants to reclaim
+			 * that memory and use it for something else. We never
+			 * do that, but we usually add it to the linear map
+			 * anyway, in which case we should use the existing
+			 * mapping.
+			 */
+			if (memblock_is_map_memory(phys))
+				return (void __iomem *)__phys_to_virt(phys);
+			fallthrough;
+
+		default:
+			if (region->attribute & EFI_MEMORY_WB)
+				prot = PAGE_KERNEL;
+			else if (region->attribute & EFI_MEMORY_WC)
+				prot = __pgprot(PROT_NORMAL_NC);
+			else if (region->attribute & EFI_MEMORY_WT)
+				prot = __acpi_get_writethrough_mem_attribute();
+		}
+	}
+	return ioremap_prot(phys, size, prot);
+}
+
+/*
+ * Claim Synchronous External Aborts as a firmware first notification.
+ *
+ * Used by KVM and the arch do_sea handler.
+ * @regs may be NULL when called from process context.
+ */
+int apei_claim_sea(struct pt_regs *regs)
+{
+	int err = -ENOENT;
+	bool return_to_irqs_enabled;
+	unsigned long current_flags;
+
+	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
+		return err;
+
+	current_flags = local_daif_save_flags();
+
+	/* current_flags isn't useful here as daif doesn't tell us about pNMI */
+	return_to_irqs_enabled = !irqs_disabled_flags(arch_local_save_flags());
+
+	if (regs)
+		return_to_irqs_enabled = interrupts_enabled(regs);
+
+	/*
+	 * SEA can interrupt SError, mask it and describe this as an NMI so
+	 * that APEI defers the handling.
+	 */
+	local_daif_restore(DAIF_ERRCTX);
+	nmi_enter();
+	err = ghes_notify_sea();
+	nmi_exit();
+
+	/*
+	 * APEI NMI-like notifications are deferred to irq_work. Unless
+	 * we interrupted irqs-masked code, we can do that now.
+	 */
+	if (!err) {
+		if (return_to_irqs_enabled) {
+			local_daif_restore(DAIF_PROCCTX_NOIRQ);
+			__irq_enter();
+			irq_work_run();
+			__irq_exit();
+		} else {
+			pr_warn_ratelimited("APEI work queued but not completed");
+			err = -EINPROGRESS;
+		}
+	}
+
+	local_daif_restore(current_flags);
+
+	return err;
+}
+
+void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+	memblock_mark_nomap(addr, size);
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
+		 int *pcpu)
+{
+	/* If an error code is passed in this stub can't fix it */
+	if (*pcpu < 0) {
+		pr_warn_once("Unable to map CPU to valid ID\n");
+		return *pcpu;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_map_cpu);
+
+int acpi_unmap_cpu(int cpu)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_unmap_cpu);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
-- 
2.50.1.windows.1


^ permalink raw reply related

* [PATCH] arm64/acpi : Fix multiple issues in ACPI boot support code
From: Fidal Palamparambil @ 2025-09-06 12:17 UTC (permalink / raw)
  To: linux-modules
  Cc: mcgrof, petr.pavlu, da.gomez, samitolvanen, linux-kernel,
	Fidal palamparambil

From: Fidal palamparambil <rootuserhere@gmail.com>

- Fixed memory leak in acpi_fadt_sanity_check() by ensuring acpi_put_table()
  is called in all error paths
- Corrected error handling in parse_acpi() by removing incorrect snprintf() usage
- Added missing compiler_attributes.h include for fallthrough support
- Verified proper NULL pointer checks in acpi_os_ioremap()

These fixes address potential memory leaks, compilation warnings, and
improper error handling in the ARM64 ACPI boot support code.

Signed-off-by: Fidal palamparambil <rootuserhere@gmail.com>
---
 arch/arm64/kernel/acpi.c    |  17 +-
 arch/arm64/kernel/acpi.orig | 466 ++++++++++++++++++++++++++++++++++++
 2 files changed, 480 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/kernel/acpi.orig

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 4d529ff7ba51..218f39e5ae0f 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -14,6 +14,7 @@
 
 #include <linux/acpi.h>
 #include <linux/arm-smccc.h>
+#include <linux/compiler_attributes.h>
 #include <linux/cpumask.h>
 #include <linux/efi.h>
 #include <linux/efi-bgrt.h>
@@ -55,16 +56,26 @@ static int __init parse_acpi(char *arg)
 
 	/* "acpi=off" disables both ACPI table parsing and interpreter */
 	if (strcmp(arg, "off") == 0)
+	{
 		param_acpi_off = true;
+	}
 	else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
+	{
 		param_acpi_on = true;
+	}
 	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+	{
 		param_acpi_force = true;
+	}
 	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
+	{
 		param_acpi_nospcr = true;
+	}
 	else
-		return -EINVAL;	/* Core will print when we return error */
-
+	{
+		pr_err("ACPI: Invalid option '%s'\n", arg);
+		return -EINVAL;
+	}
 	return 0;
 }
 early_param("acpi", parse_acpi);
@@ -463,4 +474,4 @@ int acpi_unmap_cpu(int cpu)
 	return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
-#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
\ No newline at end of file
diff --git a/arch/arm64/kernel/acpi.orig b/arch/arm64/kernel/acpi.orig
new file mode 100644
index 000000000000..4d529ff7ba51
--- /dev/null
+++ b/arch/arm64/kernel/acpi.orig
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  ARM64 Specific Low-Level ACPI Boot Support
+ *
+ *  Copyright (C) 2013-2014, Linaro Ltd.
+ *	Author: Al Stone <al.stone@linaro.org>
+ *	Author: Graeme Gregory <graeme.gregory@linaro.org>
+ *	Author: Hanjun Guo <hanjun.guo@linaro.org>
+ *	Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ *	Author: Naresh Bhat <naresh.bhat@linaro.org>
+ */
+
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/acpi.h>
+#include <linux/arm-smccc.h>
+#include <linux/cpumask.h>
+#include <linux/efi.h>
+#include <linux/efi-bgrt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irq_work.h>
+#include <linux/memblock.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+#include <linux/smp.h>
+#include <linux/serial_core.h>
+#include <linux/suspend.h>
+#include <linux/pgtable.h>
+
+#include <acpi/ghes.h>
+#include <acpi/processor.h>
+#include <asm/cputype.h>
+#include <asm/cpu_ops.h>
+#include <asm/daifflags.h>
+#include <asm/smp_plat.h>
+
+int acpi_noirq = 1;		/* skip ACPI IRQ initialization */
+int acpi_disabled = 1;
+EXPORT_SYMBOL(acpi_disabled);
+
+int acpi_pci_disabled = 1;	/* skip ACPI PCI scan and IRQ initialization */
+EXPORT_SYMBOL(acpi_pci_disabled);
+
+static bool param_acpi_off __initdata;
+static bool param_acpi_on __initdata;
+static bool param_acpi_force __initdata;
+static bool param_acpi_nospcr __initdata;
+
+static int __init parse_acpi(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+
+	/* "acpi=off" disables both ACPI table parsing and interpreter */
+	if (strcmp(arg, "off") == 0)
+		param_acpi_off = true;
+	else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
+		param_acpi_on = true;
+	else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+		param_acpi_force = true;
+	else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
+		param_acpi_nospcr = true;
+	else
+		return -EINVAL;	/* Core will print when we return error */
+
+	return 0;
+}
+early_param("acpi", parse_acpi);
+
+static bool __init dt_is_stub(void)
+{
+	int node;
+
+	fdt_for_each_subnode(node, initial_boot_params, 0) {
+		const char *name = fdt_get_name(initial_boot_params, node, NULL);
+		if (strcmp(name, "chosen") == 0)
+			continue;
+		if (strcmp(name, "hypervisor") == 0 &&
+		    of_flat_dt_is_compatible(node, "xen,xen"))
+			continue;
+
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * __acpi_map_table() will be called before page_init(), so early_ioremap()
+ * or early_memremap() should be called here to for ACPI table mapping.
+ */
+void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
+{
+	if (!size)
+		return NULL;
+
+	return early_memremap(phys, size);
+}
+
+void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
+{
+	if (!map || !size)
+		return;
+
+	early_memunmap(map, size);
+}
+
+bool __init acpi_psci_present(void)
+{
+	return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
+}
+
+/* Whether HVC must be used instead of SMC as the PSCI conduit */
+bool acpi_psci_use_hvc(void)
+{
+	return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
+}
+
+/*
+ * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity
+ *			      checks on it
+ *
+ * Return 0 on success,  <0 on failure
+ */
+static int __init acpi_fadt_sanity_check(void)
+{
+	struct acpi_table_header *table;
+	struct acpi_table_fadt *fadt;
+	acpi_status status;
+	int ret = 0;
+
+	/*
+	 * FADT is required on arm64; retrieve it to check its presence
+	 * and carry out revision and ACPI HW reduced compliancy tests
+	 */
+	status = acpi_get_table(ACPI_SIG_FADT, 0, &table);
+	if (ACPI_FAILURE(status)) {
+		const char *msg = acpi_format_exception(status);
+
+		pr_err("Failed to get FADT table, %s\n", msg);
+		return -ENODEV;
+	}
+
+	fadt = (struct acpi_table_fadt *)table;
+
+	/*
+	 * Revision in table header is the FADT Major revision, and there
+	 * is a minor revision of FADT which was introduced by ACPI 5.1,
+	 * we only deal with ACPI 5.1 or newer revision to get GIC and SMP
+	 * boot protocol configuration data.
+	 */
+	if (table->revision < 5 ||
+	   (table->revision == 5 && fadt->minor_revision < 1)) {
+		pr_err(FW_BUG "Unsupported FADT revision %d.%d, should be 5.1+\n",
+		       table->revision, fadt->minor_revision);
+
+		if (!fadt->arm_boot_flags) {
+			ret = -EINVAL;
+			goto out;
+		}
+		pr_err("FADT has ARM boot flags set, assuming 5.1\n");
+	}
+
+	if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
+		pr_err("FADT not ACPI hardware reduced compliant\n");
+		ret = -EINVAL;
+	}
+
+out:
+	/*
+	 * acpi_get_table() creates FADT table mapping that
+	 * should be released after parsing and before resuming boot
+	 */
+	acpi_put_table(table);
+	return ret;
+}
+
+/*
+ * acpi_boot_table_init() called from setup_arch(), always.
+ *	1. find RSDP and get its address, and then find XSDT
+ *	2. extract all tables and checksums them all
+ *	3. check ACPI FADT revision
+ *	4. check ACPI FADT HW reduced flag
+ *
+ * We can parse ACPI boot-time tables such as MADT after
+ * this function is called.
+ *
+ * On return ACPI is enabled if either:
+ *
+ * - ACPI tables are initialized and sanity checks passed
+ * - acpi=force was passed in the command line and ACPI was not disabled
+ *   explicitly through acpi=off command line parameter
+ *
+ * ACPI is disabled on function return otherwise
+ */
+void __init acpi_boot_table_init(void)
+{
+	int ret;
+
+	/*
+	 * Enable ACPI instead of device tree unless
+	 * - ACPI has been disabled explicitly (acpi=off), or
+	 * - the device tree is not empty (it has more than just a /chosen node,
+	 *   and a /hypervisor node when running on Xen)
+	 *   and ACPI has not been [force] enabled (acpi=on|force)
+	 */
+	if (param_acpi_off ||
+	    (!param_acpi_on && !param_acpi_force && !dt_is_stub()))
+		goto done;
+
+	/*
+	 * ACPI is disabled at this point. Enable it in order to parse
+	 * the ACPI tables and carry out sanity checks
+	 */
+	enable_acpi();
+
+	/*
+	 * If ACPI tables are initialized and FADT sanity checks passed,
+	 * leave ACPI enabled and carry on booting; otherwise disable ACPI
+	 * on initialization error.
+	 * If acpi=force was passed on the command line it forces ACPI
+	 * to be enabled even if its initialization failed.
+	 */
+	if (acpi_table_init() || acpi_fadt_sanity_check()) {
+		pr_err("Failed to init ACPI tables\n");
+		if (!param_acpi_force)
+			disable_acpi();
+	}
+
+done:
+	if (acpi_disabled) {
+		if (earlycon_acpi_spcr_enable)
+			early_init_dt_scan_chosen_stdout();
+	} else {
+#ifdef CONFIG_HIBERNATION
+		struct acpi_table_header *facs = NULL;
+		acpi_get_table(ACPI_SIG_FACS, 1, &facs);
+		if (facs) {
+			swsusp_hardware_signature =
+				((struct acpi_table_facs *)facs)->hardware_signature;
+			acpi_put_table(facs);
+		}
+#endif
+
+		/*
+		 * For varying privacy and security reasons, sometimes need
+		 * to completely silence the serial console output, and only
+		 * enable it when needed.
+		 * But there are many existing systems that depend on this
+		 * behaviour, use acpi=nospcr to disable console in ACPI SPCR
+		 * table as default serial console.
+		 */
+		ret = acpi_parse_spcr(earlycon_acpi_spcr_enable,
+			!param_acpi_nospcr);
+		if (!ret || param_acpi_nospcr || !IS_ENABLED(CONFIG_ACPI_SPCR_TABLE))
+			pr_info("Use ACPI SPCR as default console: No\n");
+		else
+			pr_info("Use ACPI SPCR as default console: Yes\n");
+
+		if (IS_ENABLED(CONFIG_ACPI_BGRT))
+			acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
+	}
+}
+
+static pgprot_t __acpi_get_writethrough_mem_attribute(void)
+{
+	/*
+	 * Although UEFI specifies the use of Normal Write-through for
+	 * EFI_MEMORY_WT, it is seldom used in practice and not implemented
+	 * by most (all?) CPUs. Rather than allocate a MAIR just for this
+	 * purpose, emit a warning and use Normal Non-cacheable instead.
+	 */
+	pr_warn_once("No MAIR allocation for EFI_MEMORY_WT; treating as Normal Non-cacheable\n");
+	return __pgprot(PROT_NORMAL_NC);
+}
+
+pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
+{
+	/*
+	 * According to "Table 8 Map: EFI memory types to AArch64 memory
+	 * types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is
+	 * mapped to a corresponding MAIR attribute encoding.
+	 * The EFI memory attribute advises all possible capabilities
+	 * of a memory region.
+	 */
+
+	u64 attr;
+
+	attr = efi_mem_attributes(addr);
+	if (attr & EFI_MEMORY_WB)
+		return PAGE_KERNEL;
+	if (attr & EFI_MEMORY_WC)
+		return __pgprot(PROT_NORMAL_NC);
+	if (attr & EFI_MEMORY_WT)
+		return __acpi_get_writethrough_mem_attribute();
+	return __pgprot(PROT_DEVICE_nGnRnE);
+}
+
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+{
+	efi_memory_desc_t *md, *region = NULL;
+	pgprot_t prot;
+
+	if (WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))
+		return NULL;
+
+	for_each_efi_memory_desc(md) {
+		u64 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+		if (phys < md->phys_addr || phys >= end)
+			continue;
+
+		if (phys + size > end) {
+			pr_warn(FW_BUG "requested region covers multiple EFI memory regions\n");
+			return NULL;
+		}
+		region = md;
+		break;
+	}
+
+	/*
+	 * It is fine for AML to remap regions that are not represented in the
+	 * EFI memory map at all, as it only describes normal memory, and MMIO
+	 * regions that require a virtual mapping to make them accessible to
+	 * the EFI runtime services.
+	 */
+	prot = __pgprot(PROT_DEVICE_nGnRnE);
+	if (region) {
+		switch (region->type) {
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+		case EFI_PERSISTENT_MEMORY:
+			if (memblock_is_map_memory(phys) ||
+			    !memblock_is_region_memory(phys, size)) {
+				pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+				return NULL;
+			}
+			/*
+			 * Mapping kernel memory is permitted if the region in
+			 * question is covered by a single memblock with the
+			 * NOMAP attribute set: this enables the use of ACPI
+			 * table overrides passed via initramfs, which are
+			 * reserved in memory using arch_reserve_mem_area()
+			 * below. As this particular use case only requires
+			 * read access, fall through to the R/O mapping case.
+			 */
+			fallthrough;
+
+		case EFI_RUNTIME_SERVICES_CODE:
+			/*
+			 * This would be unusual, but not problematic per se,
+			 * as long as we take care not to create a writable
+			 * mapping for executable code.
+			 */
+			prot = PAGE_KERNEL_RO;
+			break;
+
+		case EFI_ACPI_RECLAIM_MEMORY:
+			/*
+			 * ACPI reclaim memory is used to pass firmware tables
+			 * and other data that is intended for consumption by
+			 * the OS only, which may decide it wants to reclaim
+			 * that memory and use it for something else. We never
+			 * do that, but we usually add it to the linear map
+			 * anyway, in which case we should use the existing
+			 * mapping.
+			 */
+			if (memblock_is_map_memory(phys))
+				return (void __iomem *)__phys_to_virt(phys);
+			fallthrough;
+
+		default:
+			if (region->attribute & EFI_MEMORY_WB)
+				prot = PAGE_KERNEL;
+			else if (region->attribute & EFI_MEMORY_WC)
+				prot = __pgprot(PROT_NORMAL_NC);
+			else if (region->attribute & EFI_MEMORY_WT)
+				prot = __acpi_get_writethrough_mem_attribute();
+		}
+	}
+	return ioremap_prot(phys, size, prot);
+}
+
+/*
+ * Claim Synchronous External Aborts as a firmware first notification.
+ *
+ * Used by KVM and the arch do_sea handler.
+ * @regs may be NULL when called from process context.
+ */
+int apei_claim_sea(struct pt_regs *regs)
+{
+	int err = -ENOENT;
+	bool return_to_irqs_enabled;
+	unsigned long current_flags;
+
+	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
+		return err;
+
+	current_flags = local_daif_save_flags();
+
+	/* current_flags isn't useful here as daif doesn't tell us about pNMI */
+	return_to_irqs_enabled = !irqs_disabled_flags(arch_local_save_flags());
+
+	if (regs)
+		return_to_irqs_enabled = interrupts_enabled(regs);
+
+	/*
+	 * SEA can interrupt SError, mask it and describe this as an NMI so
+	 * that APEI defers the handling.
+	 */
+	local_daif_restore(DAIF_ERRCTX);
+	nmi_enter();
+	err = ghes_notify_sea();
+	nmi_exit();
+
+	/*
+	 * APEI NMI-like notifications are deferred to irq_work. Unless
+	 * we interrupted irqs-masked code, we can do that now.
+	 */
+	if (!err) {
+		if (return_to_irqs_enabled) {
+			local_daif_restore(DAIF_PROCCTX_NOIRQ);
+			__irq_enter();
+			irq_work_run();
+			__irq_exit();
+		} else {
+			pr_warn_ratelimited("APEI work queued but not completed");
+			err = -EINPROGRESS;
+		}
+	}
+
+	local_daif_restore(current_flags);
+
+	return err;
+}
+
+void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+	memblock_mark_nomap(addr, size);
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
+		 int *pcpu)
+{
+	/* If an error code is passed in this stub can't fix it */
+	if (*pcpu < 0) {
+		pr_warn_once("Unable to map CPU to valid ID\n");
+		return *pcpu;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_map_cpu);
+
+int acpi_unmap_cpu(int cpu)
+{
+	return 0;
+}
+EXPORT_SYMBOL(acpi_unmap_cpu);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
-- 
2.50.1.windows.1


^ permalink raw reply related

* [PATCH] module : fix signature checker pointer arithmetic and bounds check
From: Fidal Palamparambil @ 2025-09-05 15:45 UTC (permalink / raw)
  To: linux-modules
  Cc: mcgrof, petr.pavlu, da.gomez, samitolvanen, linux-kernel,
	Fidal palamparambil

From: Fidal palamparambil <rootuserhere@gmail.com>

This patch fixes :
 - invalid module_param type (bool_enable_only → bool)
 - unsafe pointer arithmetic on void *
 - missing bounds check for sig_len, preventing underflow/OOB
 - export set_module_sig_enforced for consistency

Signed-off-by : Fidal Palamparambil <rootuserhere@gmail.com>
Signed-off-by: Fidal palamparambil <rootuserhere@gmail.com>
---
 kernel/module/signing.c    |  48 ++++++++------
 kernel/module/signing.orig | 125 +++++++++++++++++++++++++++++++++++++
 2 files changed, 155 insertions(+), 18 deletions(-)
 create mode 100644 kernel/module/signing.orig

diff --git a/kernel/module/signing.c b/kernel/module/signing.c
index a2ff4242e623..8dda6cd2fd73 100644
--- a/kernel/module/signing.c
+++ b/kernel/module/signing.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
-/* Module signature checker
+/*
+ * Module signature checker
  *
  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -20,11 +21,11 @@
 #define MODULE_PARAM_PREFIX "module."
 
 static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
-module_param(sig_enforce, bool_enable_only, 0644);
+module_param(sig_enforce, bool, 0644);
 
 /*
- * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
- * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
+ * Export sig_enforce kernel cmdline parameter to allow other subsystems to
+ * rely on that instead of directly on CONFIG_MODULE_SIG_FORCE config.
  */
 bool is_module_sig_enforced(void)
 {
@@ -36,6 +37,7 @@ void set_module_sig_enforced(void)
 {
 	sig_enforce = true;
 }
+EXPORT_SYMBOL(set_module_sig_enforced);
 
 /*
  * Verify the signature on a module.
@@ -45,44 +47,55 @@ int mod_verify_sig(const void *mod, struct load_info *info)
 	struct module_signature ms;
 	size_t sig_len, modlen = info->len;
 	int ret;
+	const unsigned char *data = mod;
 
 	pr_devel("==>%s(,%zu)\n", __func__, modlen);
 
 	if (modlen <= sizeof(ms))
 		return -EBADMSG;
 
-	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
+	memcpy(&ms, data + (modlen - sizeof(ms)), sizeof(ms));
 
 	ret = mod_check_sig(&ms, modlen, "module");
 	if (ret)
 		return ret;
 
 	sig_len = be32_to_cpu(ms.sig_len);
+
+	/* Ensure sig_len is valid to prevent underflow/oob */
+	if (sig_len > modlen - sizeof(ms))
+		return -EBADMSG;
+
 	modlen -= sig_len + sizeof(ms);
 	info->len = modlen;
 
-	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+	return verify_pkcs7_signature(data, modlen, data + modlen, sig_len,
 				      VERIFY_USE_SECONDARY_KEYRING,
 				      VERIFYING_MODULE_SIGNATURE,
 				      NULL, NULL);
 }
 
+/*
+ * Check signature validity of a module during load.
+ */
 int module_sig_check(struct load_info *info, int flags)
 {
 	int err = -ENODATA;
 	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
 	const char *reason;
-	const void *mod = info->hdr;
+	const unsigned char *mod = info->hdr;
 	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
 				       MODULE_INIT_IGNORE_VERMAGIC);
+
 	/*
-	 * Do not allow mangled modules as a module with version information
-	 * removed is no longer the module that was signed.
+	 * Do not allow mangled modules: a module with version info removed
+	 * is no longer the module that was signed.
 	 */
 	if (!mangled_module &&
 	    info->len > markerlen &&
-	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
-		/* We truncate the module to discard the signature */
+	    memcmp(mod + info->len - markerlen,
+		   MODULE_SIG_STRING, markerlen) == 0) {
+		/* Truncate the module to discard the signature marker */
 		info->len -= markerlen;
 		err = mod_verify_sig(mod, info);
 		if (!err) {
@@ -92,9 +105,8 @@ int module_sig_check(struct load_info *info, int flags)
 	}
 
 	/*
-	 * We don't permit modules to be loaded into the trusted kernels
-	 * without a valid signature on them, but if we're not enforcing,
-	 * certain errors are non-fatal.
+	 * Enforced mode: only allow modules with a valid signature.
+	 * Non-enforced mode: certain errors are downgraded to warnings.
 	 */
 	switch (err) {
 	case -ENODATA:
@@ -106,12 +118,12 @@ int module_sig_check(struct load_info *info, int flags)
 	case -ENOKEY:
 		reason = "module with unavailable key";
 		break;
-
 	default:
 		/*
-		 * All other errors are fatal, including lack of memory,
-		 * unparseable signatures, and signature check failures --
-		 * even if signatures aren't required.
+		 * All other errors are fatal, including:
+		 * - OOM
+		 * - unparseable signatures
+		 * - invalid signature failures
 		 */
 		return err;
 	}
diff --git a/kernel/module/signing.orig b/kernel/module/signing.orig
new file mode 100644
index 000000000000..a2ff4242e623
--- /dev/null
+++ b/kernel/module/signing.orig
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Module signature checker
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/module_signature.h>
+#include <linux/string.h>
+#include <linux/verification.h>
+#include <linux/security.h>
+#include <crypto/public_key.h>
+#include <uapi/linux/module.h>
+#include "internal.h"
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "module."
+
+static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
+module_param(sig_enforce, bool_enable_only, 0644);
+
+/*
+ * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
+ * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
+ */
+bool is_module_sig_enforced(void)
+{
+	return sig_enforce;
+}
+EXPORT_SYMBOL(is_module_sig_enforced);
+
+void set_module_sig_enforced(void)
+{
+	sig_enforce = true;
+}
+
+/*
+ * Verify the signature on a module.
+ */
+int mod_verify_sig(const void *mod, struct load_info *info)
+{
+	struct module_signature ms;
+	size_t sig_len, modlen = info->len;
+	int ret;
+
+	pr_devel("==>%s(,%zu)\n", __func__, modlen);
+
+	if (modlen <= sizeof(ms))
+		return -EBADMSG;
+
+	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
+
+	ret = mod_check_sig(&ms, modlen, "module");
+	if (ret)
+		return ret;
+
+	sig_len = be32_to_cpu(ms.sig_len);
+	modlen -= sig_len + sizeof(ms);
+	info->len = modlen;
+
+	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+				      VERIFY_USE_SECONDARY_KEYRING,
+				      VERIFYING_MODULE_SIGNATURE,
+				      NULL, NULL);
+}
+
+int module_sig_check(struct load_info *info, int flags)
+{
+	int err = -ENODATA;
+	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+	const char *reason;
+	const void *mod = info->hdr;
+	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
+				       MODULE_INIT_IGNORE_VERMAGIC);
+	/*
+	 * Do not allow mangled modules as a module with version information
+	 * removed is no longer the module that was signed.
+	 */
+	if (!mangled_module &&
+	    info->len > markerlen &&
+	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
+		/* We truncate the module to discard the signature */
+		info->len -= markerlen;
+		err = mod_verify_sig(mod, info);
+		if (!err) {
+			info->sig_ok = true;
+			return 0;
+		}
+	}
+
+	/*
+	 * We don't permit modules to be loaded into the trusted kernels
+	 * without a valid signature on them, but if we're not enforcing,
+	 * certain errors are non-fatal.
+	 */
+	switch (err) {
+	case -ENODATA:
+		reason = "unsigned module";
+		break;
+	case -ENOPKG:
+		reason = "module with unsupported crypto";
+		break;
+	case -ENOKEY:
+		reason = "module with unavailable key";
+		break;
+
+	default:
+		/*
+		 * All other errors are fatal, including lack of memory,
+		 * unparseable signatures, and signature check failures --
+		 * even if signatures aren't required.
+		 */
+		return err;
+	}
+
+	if (is_module_sig_enforced()) {
+		pr_notice("Loading of %s is rejected\n", reason);
+		return -EKEYREJECTED;
+	}
+
+	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
+}
-- 
2.50.1.windows.1


^ permalink raw reply related

* Re: [PATCH] module: harden module signature checking
From: Sami Tolvanen @ 2025-09-05 15:22 UTC (permalink / raw)
  To: Coder; +Cc: linux-modules, mcgrof, petr.pavlu@suse.com, da.gomez,
	linux-kernel
In-Reply-To: <CAE5b5zgXZ8UGEo_oOKGUqyWPOSfA9nBJw0_wzxRvEQZTjt6DLw@mail.gmail.com>

Hi,

On Fri, Sep 5, 2025 at 6:38 AM Coder <rootuserhere@gmail.com> wrote:
>
> From: Fidal Palamparambil <rootuserhere@gmail.com>
> Date: Fri, 5 Sep 2025 17:16:01 +0400
> Subject: [PATCH] module: harden module signature checking
> Cc: mcgrof@kernel.org, petr.pavlu@suse.com, da.gomez@kernel.org, samitolvanen@google.com, linux-kernel@vger.kernel.org
>
> module: harden module signature checking
>
> This patch makes small defensive and style improvements to the
> module signature checker:
>
>  - avoid void * arithmetic by casting module header to const u8 *
>  - add an explicit bounds check for ms.sig_len before using it
>  - restore info->len to its original value when verification fails so
>    the loader does not observe a truncated length unexpectedly
>  - use READ_ONCE/WRITE_ONCE for sig_enforce to avoid rare SMP visibility
>    races
>
> These changes are intended to improve clarity and robustness; they do not
> change the signature verification policy or behavior.
>
> Signed-off-by: Fidal Palamparambil <rootuserhere@gmail.com>
>
> ---
>
> diff --git a/kernel/module-signing.c b/kernel/module-signing.c
> index abcdef1..1234567 100644
> --- a/kernel/module-signing.c
> +++ b/kernel/module-signing.c

We used to have kernel/module_signing.c before v5.19, but I'm not sure
if kernel/module-signing.c has ever existed. How exactly did you
generate this patch?

Sami

^ permalink raw reply

* Re: [Question] Non-usage of PKEY_ID_PGP and PKEY_ID_X509 in module signing
From: Sami Tolvanen @ 2025-09-05 15:09 UTC (permalink / raw)
  To: Yunseong Kim
  Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen <samitolvanen@google.com> David Howells,
	David Woodhouse, linux-modules, keyrings, linux-kernel
In-Reply-To: <a40e660e-5a45-420a-8d37-51324242ab9b@kzalloc.com>

Hi,

On Tue, Aug 26, 2025 at 11:58 AM Yunseong Kim <ysk@kzalloc.com> wrote:
>
> Given that the module signature infrastructure seems hardcoded to use
> PKCS#7, could anyone clarify if PKEY_ID_PGP and PKEY_ID_X509 are used
> elsewhere in the kernel? Are they perhaps placeholders for future
> implementations or remnants of past ones?

If you search LKML archives, you'll find some past efforts to add PGP
signing support at least. The patches never ended up being merged
though. See the discussion here, for example:

https://lore.kernel.org/lkml/20220111180318.591029-1-roberto.sassu@huawei.com/

> If they are indeed unused and there are no plans to support them, would
> a patch to clean up these unused enum values be welcome? Or is there
> another reason for keeping them?

Perhaps the folks involved back then can chime in, but I'm fine with
removing these. I'm not sure how likely it is, but if someone at some
point makes a compelling case for supporting other key and signature
types, I'm sure they can add back the constants too.

Sami

^ permalink raw reply

* [PATCH 1/1] module: replace use of system_wq with system_percpu_wq
From: Marco Crivellari @ 2025-09-05  9:01 UTC (permalink / raw)
  To: linux-kernel, linux-modules
  Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
	Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
	Luis Chamberlain, Petr Pavlu
In-Reply-To: <20250905090130.101724-1-marco.crivellari@suse.com>

Currently if a user enqueue a work item using schedule_delayed_work() the
used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
schedule_work() that is using system_wq and queue_work(), that makes use
again of WORK_CPU_UNBOUND.

This lack of consistentcy cannot be addressed without refactoring the API.

system_wq is a per-CPU worqueue, yet nothing in its name tells about that
CPU affinity constraint, which is very often not required by users. Make
it clear by adding a system_percpu_wq.

queue_work() / queue_delayed_work() mod_delayed_work() will now use the
new per-cpu wq: whether the user still stick on the old name a warn will
be printed along a wq redirect to the new one.

This patch add the new system_percpu_wq except for mm, fs and net
subsystem, whom are handled in separated patches.

The old wq will be kept for a few release cylces.

Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
 kernel/module/dups.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/module/dups.c b/kernel/module/dups.c
index bd2149fbe117..e72fa393a2ec 100644
--- a/kernel/module/dups.c
+++ b/kernel/module/dups.c
@@ -113,7 +113,7 @@ static void kmod_dup_request_complete(struct work_struct *work)
 	 * let this linger forever as this is just a boot optimization for
 	 * possible abuses of vmalloc() incurred by finit_module() thrashing.
 	 */
-	queue_delayed_work(system_wq, &kmod_req->delete_work, 60 * HZ);
+	queue_delayed_work(system_percpu_wq, &kmod_req->delete_work, 60 * HZ);
 }
 
 bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
@@ -240,7 +240,7 @@ void kmod_dup_request_announce(char *module_name, int ret)
 	 * There is no rush. But we also don't want to hold the
 	 * caller up forever or introduce any boot delays.
 	 */
-	queue_work(system_wq, &kmod_req->complete_work);
+	queue_work(system_percpu_wq, &kmod_req->complete_work);
 
 out:
 	mutex_unlock(&kmod_dup_mutex);
-- 
2.51.0


^ permalink raw reply related

* [PATCH 0/1] module: replace wq users and add WQ_PERCPU to alloc_workqueue() users
From: Marco Crivellari @ 2025-09-05  9:01 UTC (permalink / raw)
  To: linux-kernel, linux-modules
  Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
	Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
	Luis Chamberlain, Petr Pavlu

Hi!

Below is a summary of a discussion about the Workqueue API and cpu isolation
considerations. Details and more information are available here:

        "workqueue: Always use wq_select_unbound_cpu() for WORK_CPU_UNBOUND."
        https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/

=== Current situation: problems ===

Let's consider a nohz_full system with isolated CPUs: wq_unbound_cpumask is
set to the housekeeping CPUs, for !WQ_UNBOUND the local CPU is selected.

This leads to different scenarios if a work item is scheduled on an isolated
CPU where "delay" value is 0 or greater then 0:
        schedule_delayed_work(, 0);

This will be handled by __queue_work() that will queue the work item on the
current local (isolated) CPU, while:

        schedule_delayed_work(, 1);

Will move the timer on an housekeeping CPU, and schedule the work there.

Currently if a user enqueue a work item using schedule_delayed_work() the
used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
schedule_work() that is using system_wq and queue_work(), that makes use
again of WORK_CPU_UNBOUND.

This lack of consistentcy cannot be addressed without refactoring the API.

=== Plan and future plans ===

This patchset is the first stone on a refactoring needed in order to
address the points aforementioned; it will have a positive impact also
on the cpu isolation, in the long term, moving away percpu workqueue in
favor to an unbound model.

These are the main steps:
1)  API refactoring (that this patch is introducing)
    -   Make more clear and uniform the system wq names, both per-cpu and
        unbound. This to avoid any possible confusion on what should be
        used.

    -   Introduction of WQ_PERCPU: this flag is the complement of WQ_UNBOUND,
        introduced in this patchset and used on all the callers that are not
        currently using WQ_UNBOUND.

        WQ_UNBOUND will be removed in a future release cycle.

        Most users don't need to be per-cpu, because they don't have
        locality requirements, because of that, a next future step will be
        make "unbound" the default behavior.

2)  Check who really needs to be per-cpu
    -   Remove the WQ_PERCPU flag when is not strictly required.

3)  Add a new API (prefer local cpu)
    -   There are users that don't require a local execution, like mentioned
        above; despite that, local execution yeld to performance gain.

        This new API will prefer the local execution, without requiring it.

=== Introduced Changes by this series ===

1) [P 1] Replace use of system_wq

        system_wq is a per-CPU workqueue, but his name is not clear.

        Because of that, system_wq has been renamed in system_percpu_wq.

=== For Maintainers ===

There are prerequisites for this series, already merged in the master branch.
The commits are:

128ea9f6ccfb6960293ae4212f4f97165e42222d ("workqueue: Add system_percpu_wq and
system_dfl_wq")

930c2ea566aff59e962c50b2421d5fcc3b98b8be ("workqueue: Add new WQ_PERCPU flag")


Thanks!

Marco Crivellari (1):
  module: replace use of system_wq with system_percpu_wq

 kernel/module/dups.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

-- 
2.51.0


^ permalink raw reply

* Re: [PATCH RFC 103/104] Documentation/crypto: add fips140.rst
From: Vegard Nossum @ 2025-09-04 22:28 UTC (permalink / raw)
  To: Randy Dunlap, Herbert Xu, David S. Miller, linux-crypto,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Jonathan Corbet,
	linux-doc
In-Reply-To: <de23961f-ae2f-414b-8473-ce9eb17646fb@infradead.org>


On 05/09/2025 00:14, Randy Dunlap wrote:
> On 9/4/25 8:52 AM, Vegard Nossum wrote:
>> +``fips140.ko`` is not really an ordinary kernel module -- it is not
>> +meant to be loaded with ``modprobe`` or ``insmod``; instead, it is
>> +embedded into the ``vmlinux`` image at build time. This avoid any
>> +chicken-and-egg issues around how to verify cryptographic signatures
>> +without using unverified crypto code. ``fips140.ko`` is loaded during
>> +early boot -- before any crypto code is used by the kernel.
> 
> Hm, I was going to look at how that is done, but I cannot find any
> downloadable fips140 source code. Is it available for free download
> somewhere?
> 
> Is it GPL-v2 licensed?

Yes, it's the existing kernel crypto code but built as an external/out-
of-tree module.

>> +References
>> +==========
>> +
>> +.. [#fips140] <https://csrc.nist.gov/pubs/fips/140-3/final>
>> +.. [#static_call] <https://lwn.net/Articles/815908/>
> 
> Where are the other 103 patches?

Sorry, I guess git-send-email doesn't add everybody from individual
patches to the entire series. Here's the top of the thread with more of
an intro:

https://lore.kernel.org/all/20250904155216.460962-1-vegard.nossum@oracle.com/


Vegard

^ permalink raw reply

* Re: [PATCH RFC 097/104] crypto: fips140: manual fixups for lib/crypto/sha256.c
From: Vegard Nossum @ 2025-09-04 22:20 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez, Ard Biesheuvel, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules
In-Reply-To: <20250904213521.GE854551@google.com>


On 04/09/2025 23:35, Eric Biggers wrote:
> On Thu, Sep 04, 2025 at 05:52:09PM +0200, Vegard Nossum wrote:
>> Don't build arch-specific SHA256 code yet when building the FIPS 140
>> standalone module.

Emphasis on "yet" :-)

> I'm afraid you can't just not support the architecture-optimized crypto
> code.  It's usually much faster than the generic C code (often more than
> an order of magnitude faster), and it's really important to include.
> This applies to all algorithms.

We can easily support it with the exact same method as the generic code
and in fact we do this for the 6.12-based Oracle kernel. I noticed that
the architecture-specific crypto has been reworked since 6.12 so I
decided to drop it to keep the patch set a bit smaller; after all, this
still results in something that can be certified.

I think we can start with the x86 and arm64 code (and only the subset
which is NIST approved)? If anybody has a need for anything else, I can
add it to the patch set on an as-needed basis, let me know what you
would like to see there.

(It might be a bit annoying to deal with the CONFIG_ options for the
arch-specific stuff, but I think we can handle it.)


Vegard

^ permalink raw reply

* Re: [PATCH RFC 103/104] Documentation/crypto: add fips140.rst
From: Randy Dunlap @ 2025-09-04 22:14 UTC (permalink / raw)
  To: Vegard Nossum, Herbert Xu, David S. Miller, linux-crypto,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Jonathan Corbet,
	linux-doc
In-Reply-To: <20250904155216.460962-104-vegard.nossum@oracle.com>



On 9/4/25 8:52 AM, Vegard Nossum wrote:
> Add documentation for the FIPS140 standalone module.
> 
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: linux-doc@vger.kernel.org
> Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
> ---
>  Documentation/crypto/fips140.rst | 231 +++++++++++++++++++++++++++++++
>  Documentation/crypto/index.rst   |   1 +
>  2 files changed, 232 insertions(+)
>  create mode 100644 Documentation/crypto/fips140.rst
> 
> diff --git a/Documentation/crypto/fips140.rst b/Documentation/crypto/fips140.rst
> new file mode 100644
> index 000000000000..14a7fb7a69ed
> --- /dev/null
> +++ b/Documentation/crypto/fips140.rst
> @@ -0,0 +1,231 @@
> +=========================
> +FIPS140 standalone module
> +=========================
> +
> +:Author: Vegard Nossum <vegard.nossum@oracle.com>
> +
> +
> +Target audience
> +===============
> +
> +This document is primarily meant for Linux distribution developers and
> +maintainers. It may also be interesting for kernel developers
> +contributing to the kernel's crypto code as it explains some of the
> +concepts and rationale behind the architecture of the crypto code and
> +how FIPS support is implemented.
> +
> +
> +Introduction
> +============
> +
> +FIPS 140-3 is a Federal Information Protection Standard, "Security
> +Requirements for Cryptographic Modules", maintained by the US National
> +Institute of Standards and Technology (NIST). [#fips140]_
> +
> +Binary implementation of specific approved cryptographic algorithms
> +can be certified as part of the Cryptographic Module Validation
> +Program (CMVP). In practice, the certification process includes both
> +source and binary code, though the end result is a certification
> +attached to the binary code.
> +
> +Having FIPS 140-3 certification is a requirement for running in many
> +secure contexts -- many Linux distros certify their kernels in order
> +to satisfy these requirements.
> +
> +Many distros have certified the entire kernel as a "FIPS module" (not
> +to be confused with kernel modules). Unfortunately, this means that
> +one cannot change any part of the kernel without invalidating the
> +certification. Moreover, certification is a costly process that can
> +last up to or even more than 12 months.
> +
> +The FIPS 140 standalone module (AKA ``fips140.ko``) fixes this situation
> +by allowing one to build the kernel's crypto code once and reuse it in
> +subsequent builds, thus enabling the rest of the kernel to receive bug
> +fixes and updates without invalidating the certification of the FIPS
> +module.
> +
> +
> +Design
> +======
> +
> +Requirements:
> +
> +- the FIPS module must not impose a stable internal kernel API on
> +  mainline or stable kernels
> +- the FIPS module must be a single, contiguous binary file and its HMAC
> +  (for easy verification)
> +- all crypto algorithms and code must reside within the FIPS module
> +- no crypto code in the FIPS module can be used before the FIPS module
> +  has executed its self-tests
> +- the FIPS module only comes into play when the kernel is booted with
> +  ``fips=1``
> +- source code should be shared between the kernel and the FIPS module
> +  where possible
> +
> +In order to satisfy these requirements, we have settled on a design
> +where the FIPS module duplicates the crypto API and all the algorithm
> +implementations that are part of the FIPS module. To avoid source code
> +duplication, we use symlinks from ``fips140/`` to the rest of the kernel
> +tree and build this directory as an external module -- in other words,
> +all the code and algorithms is built twice; once as part of vmlinux
> +and/or regular (non-FIPS) kernel modules, and once as part of
> +``fips140.ko``.
> +
> +To allow hot-swapping the crypto code (API + algorithms) at runtime
> +(i.e. when ``fips=1`` is detected during boot), we wrap any exported
> +symbols in C macros. These macros use static calls (see [#static_call]_)
> +to patch any and all users of the crypto code to call the FIPS module's
> +version of these functions instead of the functions in vmlinux.
> +
> +``fips140.ko`` is not really an ordinary kernel module -- it is not
> +meant to be loaded with ``modprobe`` or ``insmod``; instead, it is
> +embedded into the ``vmlinux`` image at build time. This avoid any
> +chicken-and-egg issues around how to verify cryptographic signatures
> +without using unverified crypto code. ``fips140.ko`` is loaded during
> +early boot -- before any crypto code is used by the kernel.

Hm, I was going to look at how that is done, but I cannot find any
downloadable fips140 source code. Is it available for free download
somewhere?

Is it GPL-v2 licensed?


> +
> +The code for the FIPS 140 standalone module is therefore split into
> +two parts: the module itself (``fips140.ko``) and the loader
> +(``crypto/fips140-loader.c``). The loader is **NOT** part of the module
> +itself and is not covered by the certification; however, it is
> +essentially just a wrapper around the kernel module loader that runs
> +during early boot.
> +
> +We provide no explicit mechanisms to ensure compatibility between a
> +precompiled FIPS module and the rest of the kernel; this is the
> +responsibility of distros that choose to use the standalone FIPS module.
> +
> +
> +Building
> +========
> +
> +First off, ensure that ``CONFIG_CRYPTO_FIPS140_EXTMOD`` is enabled.
> +
> +Prepare for building out-of-tree module::
> +
> +  make modules_prepare
> +
> +Build fips140.ko as an out-of-tree module::
> +
> +  make M=fips140/ KBUILD_MODPOST_WARN=1
> +  cp fips140/fips140.ko crypto/
> +
> +Generate fips140.hmac::
> +
> +  hmac_key=$(awk -F'"' '/^CONFIG_CRYPTO_FIPS140_HMAC_KEY=/{print $2}' .config)
> +  openssl dgst -sha256 -hmac $hmac_key -binary -out crypto/fips140.hmac crypto/fips140.ko
> +
> +Build the rest of the kernel::
> +
> +  make
> +
> +
> +Adopting a standaline FIPS module for your distro
> +=================================================
> +
> +1. Carefully select which algorithms you want your FIPS module to
> +   provide (``CONFIG_FIPS140_*`` and ``CONFIG_CRYPTO_FIPS140_*``
> +   options)
> +
> +2. Integrate building ``fips140/`` as an out-of-tree module with the
> +   build system used by your distro's package manager.
> +
> +   - You may want to strip and separate out debuginfo before copying
> +     ``fips140.ko`` into ``crypto/``.
> +   - You need a mechanism to save and reintroduce the precompiled
> +     ``fips140.ko`` between builds.
> +   - All of this "build support" infrastructure is out of scope for
> +     mainline.
> +
> +3. Verify that the FIPS module satisfies your specific operational
> +   requirements.
> +
> +4. Submit the FIPS module to the certifying lab.
> +
> +.. warning::
> +   Mainline developers cannot and will not assist in getting a specific
> +   FIPS module certified. The code provided in the mainline source tree
> +   is intended to make certification of standalone FIPS modules easier,
> +   but we do not guarantee that a build will be certifiable as-is out of
> +   the box. Moreover, different distributions have different use cases,
> +   different requirements, etc. and all of this influences the specifics
> +   of any given FIPS module. Mainline developers will not be responsible
> +   for the certification or certifiability of your FIPS module.
> +
> +
> +Useful commands
> +===============
> +
> +
> +Extracting ``fips140.ko`` from ``vmlinux``
> +------------------------------------------
> +
> +To extract ``fips140.ko`` and ``fips140.hmac`` from an existing
> +``vmlinux`` build, use::
> +
> +  $ scripts/extract-fips140 /path/to/vmlinux
> +  extracted fips140.ko
> +  extracted fips140.hmac
> +
> +
> +Verifying the ``fips140.ko`` HMAC digest
> +----------------------------------------
> +
> +To verify the HMAC digest of ``fips140.ko``, use::
> +
> +  $ key="Sphinx of black quartz, judge my vow"
> +  $ openssl dgst -sha256 -hmac "$key" -binary fips140.ko > fips140.hmac-computed
> +  $ cmp -s fips140.hmac fips140.hmac-computed && echo ok
> +  ok
> +
> +
> +List the symbols used by ``fips140.ko``
> +---------------------------------------
> +
> +To list the kernel symbols used by ``fips140.ko`` (useful for checking
> +whether all the necessary crypto functions have been included in the
> +module), use::
> +
> +  $ nm --undefined-only fips140.ko
> +
> +
> +Quick crypto verification using AF_ALG
> +--------------------------------------
> +
> +Testing whether the code works properly is fairly easy using Python
> +and the ``AF_ALG`` interface, e.g.::
> +
> +  import socket
> +
> +  ALG_SET_KEY = 1
> +
> +  s = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
> +  s.bind(('hash', 'hmac(sha256)'))
> +  s.setsockopt(socket.SOL_ALG, ALG_SET_KEY, b'x' * 16)
> +
> +  op, _ = s.accept()
> +  op.sendall(b'x' * 32)
> +  print(op.recv(32))
> +
> +
> +Tracing the crypto code
> +-----------------------
> +
> +Testing whether the FIPS module is used correctly can also be done
> +using a combination of Python (as above) and ``trace-cmd`` like this::
> +
> +  $ sudo trace-cmd record -p function_graph -g __sys_bind python hmac.py
> +  $ trace-cmd report
> +
> +
> +Contributing
> +============
> +
> +Patches welcome.

to what/where?

> +
> +
> +References
> +==========
> +
> +.. [#fips140] <https://csrc.nist.gov/pubs/fips/140-3/final>
> +.. [#static_call] <https://lwn.net/Articles/815908/>

Where are the other 103 patches?

thanks.
-- 
~Randy


^ permalink raw reply

* Re: [PATCH RFC 097/104] crypto: fips140: manual fixups for lib/crypto/sha256.c
From: Eric Biggers @ 2025-09-04 21:35 UTC (permalink / raw)
  To: Vegard Nossum
  Cc: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez, Ard Biesheuvel, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules
In-Reply-To: <20250904155216.460962-98-vegard.nossum@oracle.com>

On Thu, Sep 04, 2025 at 05:52:09PM +0200, Vegard Nossum wrote:
> Don't build arch-specific SHA256 code yet when building the FIPS 140
> standalone module.

I'm afraid you can't just not support the architecture-optimized crypto
code.  It's usually much faster than the generic C code (often more than
an order of magnitude faster), and it's really important to include.
This applies to all algorithms.

- Eric

^ permalink raw reply

* Re: [PATCH RFC 026/104] crypto: fips140: convert lib/crypto/sha256.c to using crypto API wrappers
From: Eric Biggers @ 2025-09-04 21:29 UTC (permalink / raw)
  To: Vegard Nossum
  Cc: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez, Ard Biesheuvel, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules
In-Reply-To: <20250904155216.460962-27-vegard.nossum@oracle.com>

On Thu, Sep 04, 2025 at 05:50:58PM +0200, Vegard Nossum wrote:
>  /**
>   * sha256() - Compute SHA-256 message digest in one shot
> @@ -373,7 +392,9 @@ void sha256_final(struct sha256_ctx *ctx, u8 out[SHA256_DIGEST_SIZE]);
>   *
>   * Context: Any context.
>   */
> -void sha256(const u8 *data, size_t len, u8 out[SHA256_DIGEST_SIZE]);
> +DECLARE_CRYPTO_API(sha256, void,
> +	(const u8 *data, size_t len, u8 out[SHA256_DIGEST_SIZE]),
> +	(data, len, out));

This makes all these function declarations awfully hard to read...  If
fips140.ko is really going to be supported at all, perhaps it would make
more sense for the override to happen in the function implementations?
E.g. the first line of the sha256() function implementation would be
FIPS_CALL(sha256, data, len, out) or similar, and that would either do
nothing, or call the sha256() from fips140.ko and return.

I think that would be *slightly* less invasive.  Though of course it
doesn't get around the problem that the fips140.ko override support
still has to be handled individually for every function...

- Eric

^ permalink raw reply

* Re: [PATCH RFC 006/104] KEYS: trusted: eat -ENOENT from the crypto API
From: Eric Biggers @ 2025-09-04 20:37 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Vegard Nossum, Herbert Xu, David S. Miller, linux-crypto,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Ard Biesheuvel,
	Jason A . Donenfeld, Greg Kroah-Hartman, Wang, Jay,
	Nicolai Stange, Vladis Dronov, Stephan Mueller, Sami Tolvanen,
	linux-modules, Vijaykumar Hegde, Sriharsha Yadagudde, Sumit Garg,
	Jarkko Sakkinen
In-Reply-To: <CAHk-=wizcBV_yos1SZW9Zty7960TCeEE1t2qE_Wmm8CMoim60Q@mail.gmail.com>

On Thu, Sep 04, 2025 at 01:22:32PM -0700, Linus Torvalds wrote:
> On Thu, 4 Sept 2025 at 13:05, Vegard Nossum <vegard.nossum@oracle.com> wrote:
> >
> > However, since commit 9d50a25eeb05c ("crypto: testmgr - desupport SHA-1
> > for FIPS 140") when booting with fips=1, the SHA-1 algorithm (or anything
> > that uses it, like HMAC-SHA-1) will be unavailable.
> >
> > security/keys/trusted-keys/trusted_tpm1.c is hard-coded to use SHA-1 and
> > will fail with -ENOENT when attempting to initialize the hash instance
> > using the crypto API _if_ the hardware is available. This in turn causes
> > the entire trusted.ko to fail to load.
> 
> Oh Christ.
> 
> Can we please just make that trusted_tpm1.c code use the sha1 library
> code directly instead of going through the crypto layer to get it?
> That would presumably neatly avoid the whole issue.
> 
> Eric - I haven't looked at how painful it is to just do conversions
> like that - I assume it's a boilerplate thing and trivial to do if
> you've one one. Please?

I already got to this one:
https://lore.kernel.org/r/20250809171941.5497-3-ebiggers@kernel.org/

And yes, as usual it's much simpler:

     2 files changed, 36 insertions(+), 190 deletions(-)

(And faster too, since the library APIs have much less overhead.)

Jarkko is taking it for 6.18, I believe.

- Eric

^ permalink raw reply

* Re: [PATCH RFC 006/104] KEYS: trusted: eat -ENOENT from the crypto API
From: Linus Torvalds @ 2025-09-04 20:22 UTC (permalink / raw)
  To: Vegard Nossum
  Cc: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez, Ard Biesheuvel, Eric Biggers,
	Jason A . Donenfeld, Greg Kroah-Hartman, Wang, Jay,
	Nicolai Stange, Vladis Dronov, Stephan Mueller, Sami Tolvanen,
	linux-modules, Vijaykumar Hegde, Sriharsha Yadagudde, Sumit Garg,
	Jarkko Sakkinen
In-Reply-To: <20250904155216.460962-7-vegard.nossum@oracle.com>

On Thu, 4 Sept 2025 at 13:05, Vegard Nossum <vegard.nossum@oracle.com> wrote:
>
> However, since commit 9d50a25eeb05c ("crypto: testmgr - desupport SHA-1
> for FIPS 140") when booting with fips=1, the SHA-1 algorithm (or anything
> that uses it, like HMAC-SHA-1) will be unavailable.
>
> security/keys/trusted-keys/trusted_tpm1.c is hard-coded to use SHA-1 and
> will fail with -ENOENT when attempting to initialize the hash instance
> using the crypto API _if_ the hardware is available. This in turn causes
> the entire trusted.ko to fail to load.

Oh Christ.

Can we please just make that trusted_tpm1.c code use the sha1 library
code directly instead of going through the crypto layer to get it?
That would presumably neatly avoid the whole issue.

Eric - I haven't looked at how painful it is to just do conversions
like that - I assume it's a boilerplate thing and trivial to do if
you've one one. Please?

             Linus

^ permalink raw reply

* [PATCH RFC 104/104] MAINTAINERS: add myself as FIPS140 standalone module maintainer
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

As a gesture of accepting responsibility for the FIPS140 code, add
myself to MAINTAINERS. This is not meant to override or supersede
crypto maintainers and in fact I'd expect any FIPS140-related patches
to still go through the crypto tree(s). I encourage others with an
interest in the long term maintenance of the FIPS140 code to add
themselves to this entry as well.

Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Biggers <ebiggers@kernel.org>
Cc: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index daf520a13bdf..655c32f47343 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9467,6 +9467,16 @@ L:	linux-can@vger.kernel.org
 S:	Maintained
 F:	drivers/net/can/usb/f81604.c
 
+FIPS 140 STANDALONE MODULE SUPPORT
+M:	Vegard Nossum <vegard.nossum@oracle.com>
+L:	linux-crypto@vger.kernel.org
+S:	Maintained
+F:	crypto/fips140*
+F:	fips140/
+F:	include/crypto/api.h
+F:	scripts/extract-fips140
+F:	Documentation/crypto/fips140.rst
+
 FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE
 M:	Clemens Ladisch <clemens@ladisch.de>
 M:	Takashi Sakamoto <o-takashi@sakamocchi.jp>
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 103/104] Documentation/crypto: add fips140.rst
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum,
	Jonathan Corbet, linux-doc
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Add documentation for the FIPS140 standalone module.

Cc: Jonathan Corbet <corbet@lwn.net>
Cc: linux-doc@vger.kernel.org
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 Documentation/crypto/fips140.rst | 231 +++++++++++++++++++++++++++++++
 Documentation/crypto/index.rst   |   1 +
 2 files changed, 232 insertions(+)
 create mode 100644 Documentation/crypto/fips140.rst

diff --git a/Documentation/crypto/fips140.rst b/Documentation/crypto/fips140.rst
new file mode 100644
index 000000000000..14a7fb7a69ed
--- /dev/null
+++ b/Documentation/crypto/fips140.rst
@@ -0,0 +1,231 @@
+=========================
+FIPS140 standalone module
+=========================
+
+:Author: Vegard Nossum <vegard.nossum@oracle.com>
+
+
+Target audience
+===============
+
+This document is primarily meant for Linux distribution developers and
+maintainers. It may also be interesting for kernel developers
+contributing to the kernel's crypto code as it explains some of the
+concepts and rationale behind the architecture of the crypto code and
+how FIPS support is implemented.
+
+
+Introduction
+============
+
+FIPS 140-3 is a Federal Information Protection Standard, "Security
+Requirements for Cryptographic Modules", maintained by the US National
+Institute of Standards and Technology (NIST). [#fips140]_
+
+Binary implementation of specific approved cryptographic algorithms
+can be certified as part of the Cryptographic Module Validation
+Program (CMVP). In practice, the certification process includes both
+source and binary code, though the end result is a certification
+attached to the binary code.
+
+Having FIPS 140-3 certification is a requirement for running in many
+secure contexts -- many Linux distros certify their kernels in order
+to satisfy these requirements.
+
+Many distros have certified the entire kernel as a "FIPS module" (not
+to be confused with kernel modules). Unfortunately, this means that
+one cannot change any part of the kernel without invalidating the
+certification. Moreover, certification is a costly process that can
+last up to or even more than 12 months.
+
+The FIPS 140 standalone module (AKA ``fips140.ko``) fixes this situation
+by allowing one to build the kernel's crypto code once and reuse it in
+subsequent builds, thus enabling the rest of the kernel to receive bug
+fixes and updates without invalidating the certification of the FIPS
+module.
+
+
+Design
+======
+
+Requirements:
+
+- the FIPS module must not impose a stable internal kernel API on
+  mainline or stable kernels
+- the FIPS module must be a single, contiguous binary file and its HMAC
+  (for easy verification)
+- all crypto algorithms and code must reside within the FIPS module
+- no crypto code in the FIPS module can be used before the FIPS module
+  has executed its self-tests
+- the FIPS module only comes into play when the kernel is booted with
+  ``fips=1``
+- source code should be shared between the kernel and the FIPS module
+  where possible
+
+In order to satisfy these requirements, we have settled on a design
+where the FIPS module duplicates the crypto API and all the algorithm
+implementations that are part of the FIPS module. To avoid source code
+duplication, we use symlinks from ``fips140/`` to the rest of the kernel
+tree and build this directory as an external module -- in other words,
+all the code and algorithms is built twice; once as part of vmlinux
+and/or regular (non-FIPS) kernel modules, and once as part of
+``fips140.ko``.
+
+To allow hot-swapping the crypto code (API + algorithms) at runtime
+(i.e. when ``fips=1`` is detected during boot), we wrap any exported
+symbols in C macros. These macros use static calls (see [#static_call]_)
+to patch any and all users of the crypto code to call the FIPS module's
+version of these functions instead of the functions in vmlinux.
+
+``fips140.ko`` is not really an ordinary kernel module -- it is not
+meant to be loaded with ``modprobe`` or ``insmod``; instead, it is
+embedded into the ``vmlinux`` image at build time. This avoid any
+chicken-and-egg issues around how to verify cryptographic signatures
+without using unverified crypto code. ``fips140.ko`` is loaded during
+early boot -- before any crypto code is used by the kernel.
+
+The code for the FIPS 140 standalone module is therefore split into
+two parts: the module itself (``fips140.ko``) and the loader
+(``crypto/fips140-loader.c``). The loader is **NOT** part of the module
+itself and is not covered by the certification; however, it is
+essentially just a wrapper around the kernel module loader that runs
+during early boot.
+
+We provide no explicit mechanisms to ensure compatibility between a
+precompiled FIPS module and the rest of the kernel; this is the
+responsibility of distros that choose to use the standalone FIPS module.
+
+
+Building
+========
+
+First off, ensure that ``CONFIG_CRYPTO_FIPS140_EXTMOD`` is enabled.
+
+Prepare for building out-of-tree module::
+
+  make modules_prepare
+
+Build fips140.ko as an out-of-tree module::
+
+  make M=fips140/ KBUILD_MODPOST_WARN=1
+  cp fips140/fips140.ko crypto/
+
+Generate fips140.hmac::
+
+  hmac_key=$(awk -F'"' '/^CONFIG_CRYPTO_FIPS140_HMAC_KEY=/{print $2}' .config)
+  openssl dgst -sha256 -hmac $hmac_key -binary -out crypto/fips140.hmac crypto/fips140.ko
+
+Build the rest of the kernel::
+
+  make
+
+
+Adopting a standaline FIPS module for your distro
+=================================================
+
+1. Carefully select which algorithms you want your FIPS module to
+   provide (``CONFIG_FIPS140_*`` and ``CONFIG_CRYPTO_FIPS140_*``
+   options)
+
+2. Integrate building ``fips140/`` as an out-of-tree module with the
+   build system used by your distro's package manager.
+
+   - You may want to strip and separate out debuginfo before copying
+     ``fips140.ko`` into ``crypto/``.
+   - You need a mechanism to save and reintroduce the precompiled
+     ``fips140.ko`` between builds.
+   - All of this "build support" infrastructure is out of scope for
+     mainline.
+
+3. Verify that the FIPS module satisfies your specific operational
+   requirements.
+
+4. Submit the FIPS module to the certifying lab.
+
+.. warning::
+   Mainline developers cannot and will not assist in getting a specific
+   FIPS module certified. The code provided in the mainline source tree
+   is intended to make certification of standalone FIPS modules easier,
+   but we do not guarantee that a build will be certifiable as-is out of
+   the box. Moreover, different distributions have different use cases,
+   different requirements, etc. and all of this influences the specifics
+   of any given FIPS module. Mainline developers will not be responsible
+   for the certification or certifiability of your FIPS module.
+
+
+Useful commands
+===============
+
+
+Extracting ``fips140.ko`` from ``vmlinux``
+------------------------------------------
+
+To extract ``fips140.ko`` and ``fips140.hmac`` from an existing
+``vmlinux`` build, use::
+
+  $ scripts/extract-fips140 /path/to/vmlinux
+  extracted fips140.ko
+  extracted fips140.hmac
+
+
+Verifying the ``fips140.ko`` HMAC digest
+----------------------------------------
+
+To verify the HMAC digest of ``fips140.ko``, use::
+
+  $ key="Sphinx of black quartz, judge my vow"
+  $ openssl dgst -sha256 -hmac "$key" -binary fips140.ko > fips140.hmac-computed
+  $ cmp -s fips140.hmac fips140.hmac-computed && echo ok
+  ok
+
+
+List the symbols used by ``fips140.ko``
+---------------------------------------
+
+To list the kernel symbols used by ``fips140.ko`` (useful for checking
+whether all the necessary crypto functions have been included in the
+module), use::
+
+  $ nm --undefined-only fips140.ko
+
+
+Quick crypto verification using AF_ALG
+--------------------------------------
+
+Testing whether the code works properly is fairly easy using Python
+and the ``AF_ALG`` interface, e.g.::
+
+  import socket
+
+  ALG_SET_KEY = 1
+
+  s = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
+  s.bind(('hash', 'hmac(sha256)'))
+  s.setsockopt(socket.SOL_ALG, ALG_SET_KEY, b'x' * 16)
+
+  op, _ = s.accept()
+  op.sendall(b'x' * 32)
+  print(op.recv(32))
+
+
+Tracing the crypto code
+-----------------------
+
+Testing whether the FIPS module is used correctly can also be done
+using a combination of Python (as above) and ``trace-cmd`` like this::
+
+  $ sudo trace-cmd record -p function_graph -g __sys_bind python hmac.py
+  $ trace-cmd report
+
+
+Contributing
+============
+
+Patches welcome.
+
+
+References
+==========
+
+.. [#fips140] <https://csrc.nist.gov/pubs/fips/140-3/final>
+.. [#static_call] <https://lwn.net/Articles/815908/>
diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst
index 100b47d049c0..e755ffd08d4f 100644
--- a/Documentation/crypto/index.rst
+++ b/Documentation/crypto/index.rst
@@ -27,3 +27,4 @@ for cryptographic use cases, as well as programming examples.
    descore-readme
    device_drivers/index
    krb5
+   fips140
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 100/104] crypto: fips140: add standalone FIPS 140 module
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

This code is partly based on the existing crypto/fips.c code and partly on
the Android FIPS 140 module [1]; __fips_initcalls/run_initcalls() based
loosely on code by Jay Wang <wanjay@amazon.com>.

[1]: https://android.googlesource.com/kernel/common/+/1ca1130ec62d/crypto/fips140-module.c

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 crypto/Kconfig         |  16 +--
 fips140/Kconfig        | 174 +++++++++++++++++++++++++++++++++
 fips140/Makefile       | 183 ++++++++++++++++++++++++++++++++++
 fips140/fips140-glue.c | 216 +++++++++++++++++++++++++++++++++++++++++
 fips140/fips140.lds    |   9 ++
 5 files changed, 583 insertions(+), 15 deletions(-)
 create mode 100644 fips140/Kconfig
 create mode 100644 fips140/Makefile
 create mode 100644 fips140/fips140-glue.c
 create mode 100644 fips140/fips140.lds

diff --git a/crypto/Kconfig b/crypto/Kconfig
index a2696ea30bde..f9b2f87ad04b 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -54,21 +54,7 @@ config CRYPTO_FIPS_VERSION
 	  This option provides the ability to override the FIPS Module Version.
 	  By default the KERNELRELEASE value is used.
 
-config CRYPTO_FIPS140_EXTMOD
-	bool "FIPS 140-3 external module"
-	depends on CRYPTO_FIPS
-	help
-	  Support loading a prebuilt FIPS 140-3 cryptographic module.
-
-config CRYPTO_FIPS140_HMAC_KEY
-	string "FIPS 140-3 external module HMAC key"
-	depends on CRYPTO_FIPS140_EXTMOD
-	default "Sphinx of black quartz, judge my vow"
-	help
-	  This is the HMAC key used to build and verify the integrity of
-	  the FIPS module.
-
-	  Must be at least 14 characters.
+source "fips140/Kconfig"
 
 config CRYPTO_ALGAPI
 	tristate
diff --git a/fips140/Kconfig b/fips140/Kconfig
new file mode 100644
index 000000000000..188c5f360eab
--- /dev/null
+++ b/fips140/Kconfig
@@ -0,0 +1,174 @@
+# NOTE: the structure of this file mirrors that of crypto/Kconfig
+# and crypto/asymmetric/keys/Kconfig
+
+config CRYPTO_FIPS140_EXTMOD
+	bool "FIPS 140-3 external module"
+	depends on MODULES
+	depends on CRYPTO_FIPS
+	help
+	  Support loading a prebuilt FIPS 140-3 cryptographic module.
+
+if CRYPTO_FIPS140_EXTMOD
+
+config CRYPTO_FIPS140_HMAC_KEY
+	string "FIPS 140-3 external module HMAC key"
+	default "Sphinx of black quartz, judge my vow"
+	help
+	  This is the HMAC key used to build and verify the integrity of
+	  the FIPS module.
+
+	  Must be at least 14 characters.
+
+config CRYPTO_FIPS140_PCRYPT
+	bool
+	default CRYPTO_PCRYPT
+
+menu "FIPS 140 external module algorithms"
+	depends on CRYPTO_FIPS140_EXTMOD
+
+#
+# Public-key cryptography
+#
+
+config CRYPTO_FIPS140_RSA
+	bool "RSA (Rivest-Shamir-Adleman)"
+	default CRYPTO_RSA
+
+config CRYPTO_FIPS140_DH
+	bool "DH (Diffie-Hellman)"
+	default CRYPTO_DH
+
+config CRYPTO_FIPS140_ECC
+	bool
+	default CRYPTO_ECC
+
+config CRYPTO_FIPS140_ECDH
+	bool "ECDH (Elliptic Curve Diffie-Hellman)"
+	select CRYPTO_FIPS140_ECC
+	default CRYPTO_ECDH
+
+config CRYPTO_FIPS140_ECDSA
+	bool "ECDSA (Elliptic Curve Digital Signature Algorithm)"
+	default CRYPTO_ECDSA
+
+#
+# Block ciphers
+#
+
+config CRYPTO_FIPS140_AES
+	bool "AES (Advanced Encryption Standard)"
+	default CRYPTO_AES
+
+#
+# Length-preserving ciphers and modes
+#
+
+config CRYPTO_FIPS140_CBC
+	bool "CBC (Cipher Block Chaining)"
+	default CRYPTO_CBC
+
+config CRYPTO_FIPS140_CTR
+	bool "CTR (Counter)"
+	default CRYPTO_CTR
+
+config CRYPTO_FIPS140_ECB
+	bool "ECB (Electronic Codebook)"
+	default CRYPTO_ECB
+
+config CRYPTO_FIPS140_XTS
+	bool "XTS (XOR Encrypt XOR with ciphertext stealing)"
+	default CRYPTO_XTS
+
+#
+# AEAD (authenticated encryption with associated data) ciphers
+#
+
+config CRYPTO_FIPS140_CCM
+	bool "CCM (Counter with Cipher Block Chaining-MAC)"
+	default CRYPTO_CCM
+
+config CRYPTO_FIPS140_GCM
+	bool "GCM (Galois/Counter Mode) and GMAC (GCM MAC)"
+	default CRYPTO_GCM
+
+config CRYPTO_FIPS140_GENIV
+	bool
+	default CRYPTO_GENIV
+
+config CRYPTO_FIPS140_SEQIV
+	bool "Sequence Number IV Generator"
+	select CRYPTO_FIPS140_GENIV
+	default CRYPTO_SEQIV
+
+config CRYPTO_FIPS140_ECHAINIV
+	bool "Encrypted Chain IV Generator"
+	select CRYPTO_FIPS140_GENIV
+	default CRYPTO_ECHAINIV
+
+config CRYPTO_FIPS140_ESSIV
+	bool "Encrypted Salt-Sector IV Generator"
+	default CRYPTO_ESSIV
+
+#
+# Hashes, digests, and MACs
+#
+
+config CRYPTO_FIPS140_CMAC
+	bool "CMAC (Cipher-based MAC)"
+	default CRYPTO_CMAC
+
+config CRYPTO_FIPS140_HMAC
+	bool "HMAC (Keyed-Hash MAC)"
+	default CRYPTO_HMAC
+
+config CRYPTO_FIPS140_SHA256
+	bool "SHA-244 and SHA-256"
+	default CRYPTO_SHA256
+
+config CRYPTO_FIPS140_SHA512
+	bool "SHA-384 and SHA-512"
+	default CRYPTO_SHA512
+
+config CRYPTO_FIPS140_SHA3
+	bool "SHA-3"
+	default CRYPTO_SHA3
+
+#
+# Random number generation
+#
+
+config CRYPTO_FIPS140_JITTERENTROPY
+	bool "CPU Jitter Non-Deterministic RNG (Random Number Generator)"
+	select CRYPTO_FIPS140_SHA3
+
+#
+# Asymmetric keys
+#
+
+config FIPS140_ASYMMETRIC_KEY_TYPE
+	bool "Asymmetric (public-key cryptographic) key type"
+	default ASYMMETRIC_KEY_TYPE
+
+if FIPS140_ASYMMETRIC_KEY_TYPE
+
+config FIPS140_ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+	bool "Asymmetric public-key crypto algorithm subtype"
+	default ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+
+config FIPS140_X509_CERTIFICATE_PARSER
+	bool "X.509 certificate parser"
+	default X509_CERTIFICATE_PARSER
+
+config FIPS140_PKCS8_PRIVATE_KEY_PARSER
+	bool "PKCS#8 private key parser"
+	default PKCS8_PRIVATE_KEY_PARSER
+
+config FIPS140_PKCS7_MESSAGE_PARSER
+	bool "PKCS#7 message parser"
+	default PKCS7_MESSAGE_PARSER
+
+endif
+
+endmenu
+
+endif # if CRYPTO_FIPS140_EXTMOD
diff --git a/fips140/Makefile b/fips140/Makefile
new file mode 100644
index 000000000000..47365f1b3e27
--- /dev/null
+++ b/fips140/Makefile
@@ -0,0 +1,183 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2014 Linaro Ltd <ard.biesheuvel@linaro.org>
+# Copyright © 2025, Oracle and/or its affiliates.
+#
+
+#
+# Global options
+#
+
+# make sure both .c and .S files see this
+subdir-ccflags-y += -DFIPS_MODULE=1
+subdir-asflags-y += -DFIPS_MODULE=1
+
+#
+# Glue
+#
+
+fips140-y := fips140-glue.o
+
+#
+# crypto/Makefile
+#
+
+fips140-y += crypto/algapi.o
+fips140-y += crypto/api.o
+fips140-y += crypto/ahash.o
+fips140-y += crypto/cryptd.o
+fips140-y += crypto/shash.o
+fips140-y += crypto/proc.o
+
+# cryptomgr.ko
+fips140-y += crypto/algboss.o crypto/testmgr.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_SHA3) += crypto/sha3_generic.o
+
+# jitterentropy_rng.ko
+CFLAGS_crypto/jitterentropy.o = -O0
+KASAN_SANITIZE_crypto/jitterentropy.o = n
+UBSAN_SANITIZE_crypto/jitterentropy.o = n
+fips140-$(CONFIG_CRYPTO_FIPS140_JITTERENTROPY) += crypto/jitterentropy.o crypto/jitterentropy-kcapi.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_SHA512) += crypto/sha512.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_PCRYPT) += crypto/pcrypt.o
+fips140-y += crypto/ghash-generic.o
+
+# crypto_simd.ko
+fips140-y += crypto/simd.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_HMAC) += crypto/hmac.o
+fips140-y += crypto/authenc.o
+fips140-y += crypto/authencesn.o
+
+# rsa_generic.ko
+fips140-$(CONFIG_CRYPTO_FIPS140_RSA) += $(addprefix crypto/, \
+	rsapubkey.asn1.o \
+	rsaprivkey.asn1.o \
+	rsa.o \
+	rsa_helper.o \
+	rsa-pkcs1pad.o \
+	rsassa-pkcs1.o \
+)
+
+fips140-$(CONFIG_CRYPTO_FIPS140_SHA256) += crypto/sha256.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_CMAC) += crypto/cmac.o
+fips140-$(CONFIG_CRYPTO_FIPS140_AES) += crypto/aes_generic.o
+fips140-$(CONFIG_CRYPTO_FIPS140_CBC) += crypto/cbc.o
+fips140-$(CONFIG_CRYPTO_FIPS140_CCM) += crypto/ccm.o
+fips140-$(CONFIG_CRYPTO_FIPS140_ECB) += crypto/ecb.o
+fips140-$(CONFIG_CRYPTO_FIPS140_CTR) += crypto/ctr.o
+fips140-$(CONFIG_CRYPTO_FIPS140_ECC) += crypto/ecc.o
+fips140-y += crypto/drbg.o
+
+fips140-$(CONFIG_CRYPTO_FIPS140_ECDH) += $(addprefix crypto/, \
+	ecdh.o \
+	ecdh_helper.o \
+)
+
+# ecdsa_generic.ko
+$(obj)/crypto/ecdsasignature.asn1.o: $(obj)/crypto/ecdsasignature.asn1.c $(obj)/crypto/ecdsasignature.asn1.h
+$(obj)/crypto/ecdsa.o: $(obj)/crypto/ecdsasignature.asn1.h
+fips140-$(CONFIG_CRYPTO_FIPS140_ECDSA) += $(addprefix crypto/, \
+	ecdsa.o \
+	ecdsa-x962.o \
+	ecdsa-p1363.o \
+	ecdsasignature.asn1.o \
+)
+
+# dh_generic.ko
+fips140-$(CONFIG_CRYPTO_FIPS140_DH) += $(addprefix crypto/, \
+	dh.o \
+	dh_helper.o \
+)
+
+fips140-$(CONFIG_CRYPTO_FIPS140_GCM) += crypto/gcm.o
+fips140-$(CRYPTO_FIPS140_XTS) += crypto/xts.o
+fips140-y += crypto/tcrypt.o
+
+fips140-y += crypto/aead.o
+fips140-y += crypto/kpp.o
+fips140-y += crypto/cipher.o
+fips140-y += crypto/akcipher.o
+fips140-y += crypto/skcipher.o
+fips140-y += crypto/lskcipher.o
+fips140-y += crypto/rng.o
+fips140-y += crypto/sig.o
+fips140-$(CONFIG_CRYPTO_FIPS140_GENIV) += crypto/geniv.o
+fips140-$(CONFIG_CRYPTO_FIPS140_SEQIV) += crypto/seqiv.o
+fips140-$(CONFIG_CRYPTO_FIPS140_ECHAINIV) += crypto/echainiv.o
+fips140-$(CONFIG_CRYPTO_FIPS140_ESSIV) += crypto/essiv.o
+
+#
+# crypto/asymmetric_keys/Makefile
+#
+
+fips140-$(CONFIG_FIPS140_ASYMMETRIC_KEY_TYPE) += \
+	$(addprefix crypto/asymmetric_keys/, \
+		asymmetric_type.o restrict.o signature.o)
+
+fips140-$(CONFIG_FIPS140_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += crypto/asymmetric_keys/public_key.o
+
+$(obj)/crypto/asymmetric_keys/x509_cert_parser.o: \
+	$(addprefix $(obj)/crypto/asymmetric_keys/, \
+		x509.asn1.h x509_akid.asn1.h)
+$(obj)/crypto/asymmetric_keys/x509.asn1.o: \
+	$(addprefix $(obj)/crypto/asymmetric_keys/, \
+		x509.asn1.c x509.asn1.h)
+$(obj)/crypto/asymmetric_keys/x509_akid.asn1.o: \
+	$(addprefix $(obj)/crypto/asymmetric_keys/, \
+		x509_akid.asn1.c x509_akid.asn1.h)
+
+fips140-$(CONFIG_FIPS140_X509_CERTIFICATE_PARSER) += \
+	$(addprefix crypto/asymmetric_keys/, \
+		x509_cert_parser.o \
+		x509_loader.o \
+		x509_akid.asn1.o \
+		x509.asn1.o \
+		x509_public_key.o \
+	)
+
+$(obj)/crypto/asymmetric_keys/pkcs8_parser.o: $(obj)/crypto/asymmetric_keys/pkcs8.asn1.h
+$(obj)/crypto/asymmetric_keys/pkcs8-asn1.o: \
+	$(addprefix $(obj)/crypto/asymmetric_keys/, \
+		pkcs8.asn1.c pkcs8.asn1.h)
+
+fips140-$(CONFIG_FIPS140_PKCS8_PRIVATE_KEY_PARSER) += \
+	$(addprefix crypto/asymmetric_keys/, \
+		pkcs8_parser.o \
+		pkcs8.asn1.o \
+	)
+
+fips140-$(CONFIG_FIPS140_PKCS7_MESSAGE_PARSER) += \
+	$(addprefix crypto/asymmetric_keys/, \
+		pkcs7_parser.o \
+		pkcs7_trust.o \
+		pkcs7_verify.o \
+		pkcs7_key_type.o \
+		pkcs7.asn1.o \
+	)
+
+$(obj)/crypto/asymmetric_keys/pkcs7_parser.o: $(obj)/crypto/asymmetric_keys/pkcs7.asn1.h
+$(obj)/crypto/asymmetric_keys/pkcs7.asn1.o: \
+	$(addprefix $(obj)/crypto/asymmetric_keys/, \
+		pkcs7.asn1.c pkcs7.asn1.h)
+
+#
+# lib/crypto/Makefile
+#
+
+fips140-y += lib/crypto/aes.o
+fips140-y += lib/crypto/aesgcm.o
+fips140-y += lib/crypto/sha256.o
+fips140-y += lib/crypto/sha512.o
+fips140-y += lib/crypto/gf128mul.o
+fips140-y += lib/crypto/memneq.o
+fips140-y += lib/crypto/utils.o
+
+# Use custom linker script to collect initcalls
+LDFLAGS_fips140.o += -T $(src)/fips140.lds
+
+obj-m += fips140.o
diff --git a/fips140/fips140-glue.c b/fips140/fips140-glue.c
new file mode 100644
index 000000000000..69db638c68d1
--- /dev/null
+++ b/fips140/fips140-glue.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * FIPS 140-3 and FIPS 200 support.
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com>
+ * Copyright 2021 Google LLC
+ * Copyright (c) 2025, Oracle and/or its affiliates.
+ */
+
+#include <generated/utsrelease.h>
+
+#include <linux/export.h>
+#include <linux/fips.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sysctl.h>
+
+#include <crypto/api.h>
+#include <crypto/hash.h>
+
+#include "crypto/internal.h"
+
+#define FIPS_MODULE_NAME CONFIG_CRYPTO_FIPS_NAME
+#ifdef CONFIG_CRYPTO_FIPS_CUSTOM_VERSION
+#define FIPS_MODULE_VERSION CONFIG_CRYPTO_FIPS_VERSION
+#else
+#define FIPS_MODULE_VERSION UTS_RELEASE
+#endif
+
+static char fips_name[] = FIPS_MODULE_NAME;
+static char fips_version[] = FIPS_MODULE_VERSION;
+
+/*
+ * FIPS 140-2 prefers the use of HMAC with a public key over a plain hash.
+ */
+static const u8 fips140_integ_hmac_key[] = CONFIG_CRYPTO_FIPS140_HMAC_KEY;
+
+int fips_operational = 0;
+
+static int verify_integrity(void)
+{
+	int err;
+
+	struct crypto_shash *tfm = NULL;
+	SHASH_DESC_ON_STACK(desc, dontcare);
+	u8 digest[SHA256_DIGEST_SIZE];
+
+	/*
+	 * Verify integrity
+	 */
+
+	tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+	if (IS_ERR(tfm))
+		panic("FIPS 140: failed to allocate hmac tfm (%ld)\n", PTR_ERR(tfm));
+
+	desc->tfm = tfm;
+	pr_info("FIPS 140: using '%s' for integrity check\n",
+		crypto_shash_driver_name(tfm));
+
+	err = crypto_shash_setkey(tfm, fips140_integ_hmac_key, strlen(fips140_integ_hmac_key));
+	if (err)
+		panic("FIPS 140: crypto_shash_setkey() failed: %d\n", err);
+
+	err = crypto_shash_init(desc);
+	if (err)
+		panic("FIPS 140: crypto_shash_init() failed: %d\n", err);
+
+	/* Compute HMAC over the module's source memory */
+	//err = crypto_shash_update(desc, THIS_MODULE->source_ptr, THIS_MODULE->source_len);
+	err = crypto_shash_update(desc, _binary_fips140_ko_start, _binary_fips140_ko_end - _binary_fips140_ko_start);
+	if (err)
+		panic("FIPS 140: crypto_shash_update() failed: %d\n", err);
+
+	err = crypto_shash_final(desc, digest);
+	if (err)
+		panic("FIPS 140: crypto_shash_final() failed: %d\n", err);
+
+	/* Zeroizing this is important; see the comment below. */
+	shash_desc_zero(desc);
+
+	if (err)
+		panic("FIPS 140: failed to calculate hmac shash (%d)\n", err);
+
+	pr_info("FIPS 140: expected digest: %*phN\n", (int)sizeof(digest), _binary_fips140_hmac_start);
+	pr_info("FIPS 140: computed digest: %*phN\n", (int)sizeof(digest), digest);
+
+	if (memcmp(digest, _binary_fips140_hmac_start, sizeof(digest)))
+		panic("FIPS 140: failed integrity check\n");
+
+	/*
+	 * FIPS 140-3 requires that all "temporary value(s) generated during the
+	 * integrity test" be zeroized (ref: FIPS 140-3 IG 9.7.B).  There is no
+	 * technical reason to do this given that these values are public
+	 * information, but this is the requirement so we follow it.
+	 */
+	crypto_free_shash(tfm);
+	memzero_explicit(digest, sizeof(digest));
+
+	return 0;
+}
+
+/* This technically is never supposed to change. */
+static int fips_standalone = 1;
+
+static struct ctl_table crypto_sysctl_table[] = {
+	{
+		.procname	= "fips_enabled",
+		/*
+		 * Note: we use fips_operational instead of fips_enabled,
+		 * since fips_enabled is more like "FIPS was requested",
+		 * and is nonzero before self testing and integrity testing
+		 * has finished. However, the difference is theoretical
+		 * since this file will not even be created until the
+		 * testing has completed.
+		 */
+		.data		= &fips_operational,
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.proc_handler	= proc_dointvec,
+	},
+	{
+		.procname	= "fips_name",
+		.data		= &fips_name,
+		.maxlen		= sizeof(fips_name),
+		.mode		= 0444,
+		.proc_handler	= proc_dostring,
+	},
+	{
+		.procname	= "fips_version",
+		.data		= &fips_version,
+		.maxlen		= sizeof(fips_version),
+		.mode		= 0444,
+		.proc_handler	= proc_dostring,
+	},
+	/*
+	 * Helper file for dracut that always returns "1" to indicate
+	 * that no userspace help is needed to get the FIPS module
+	 * operational.
+	 */
+	{
+		.procname	= "fips_standalone",
+		.data		= &fips_standalone,
+		.maxlen		= sizeof(fips_standalone),
+		.mode		= 0444,
+		.proc_handler	= proc_dointvec,
+	},
+};
+
+static struct ctl_table_header *crypto_sysctls;
+
+static int __init check_nonfips_alg_list(void)
+{
+	extern struct list_head nonfips_crypto_alg_list;
+
+	struct crypto_alg *q;
+	int err = 0;
+
+	list_for_each_entry(q, &nonfips_crypto_alg_list, cra_list) {
+		pr_err("FIPS 140: found registered non-FIPS algorithm %s (%s)\n", q->cra_name, q->cra_driver_name);
+		err = 1;
+	}
+
+	return err;
+}
+
+static int __init run_initcalls(void)
+{
+	extern unsigned long __fips_initcalls_start[];
+	extern unsigned long __fips_initcalls_end[];
+
+	for (unsigned long *initcall = __fips_initcalls_start;
+		initcall != __fips_initcalls_end; ++initcall)
+	{
+		int ret;
+		initcall_t fn;
+
+		fn = (initcall_t) *initcall;
+		pr_info("FIPS 140: calling %pS\n", fn);
+
+		ret = fn();
+		if (!ret || ret == -ENODEV)
+			continue;
+
+		panic("FIPS 140: initcall %pS failed: %d\n", fn, ret);
+	}
+
+	return 0;
+}
+
+static int __init fips140_init(void)
+{
+	pr_info("FIPS 140: %s version %s\n", fips_name, fips_version);
+
+	if (check_nonfips_alg_list())
+		panic("FIPS 140: found registered non-FIPS algorithms\n");
+
+	run_initcalls();
+
+	if (verify_integrity())
+		panic("FIPS 140: integrity check failed\n");
+
+	crypto_sysctls = register_sysctl("crypto", crypto_sysctl_table);
+	if (!crypto_sysctls)
+		panic("FIPS 140: failed to register sysctls");
+
+	fips_operational = 1;
+
+	pr_info("FIPS 140: operational\n");
+	return 0;
+}
+module_init(fips140_init);
+
+MODULE_DESCRIPTION("FIPS 140 Cryptographic Module");
+MODULE_LICENSE("GPL");
diff --git a/fips140/fips140.lds b/fips140/fips140.lds
new file mode 100644
index 000000000000..78ac3fa7a7db
--- /dev/null
+++ b/fips140/fips140.lds
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+SECTIONS {
+	.init.data : {
+		__fips_initcalls_start = .;
+		*(.fips_initcall)
+		__fips_initcalls_end = .;
+       }
+}
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 102/104] scripts/extract-fips140: new script
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Add a new script to extract a precompiled FIPS 140 module (.ko), its
authenticated digest (.hmac), and optionally also the .a of modules, from
a vmlinuz file.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 scripts/extract-fips140 | 53 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100755 scripts/extract-fips140

diff --git a/scripts/extract-fips140 b/scripts/extract-fips140
new file mode 100755
index 000000000000..00ec7631fa3c
--- /dev/null
+++ b/scripts/extract-fips140
@@ -0,0 +1,53 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Extract FIPS 140 cryptographic module (and hmac) from vmlinuz.
+#
+# Copyright © 2025, Oracle and/or its affiliates.
+#
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+extract_vmlinux = os.path.join(os.path.dirname(__file__), 'extract-vmlinux')
+
+parser = argparse.ArgumentParser()
+parser.add_argument('vmlinux')
+
+args = parser.parse_args()
+
+warnings = False
+
+with tempfile.TemporaryDirectory() as tmp_dir:
+    vmlinux_path = os.path.join(tmp_dir, 'vmlinux')
+    with open(vmlinux_path, 'w') as f:
+        subprocess.check_call([extract_vmlinux, args.vmlinux], stdout=f)
+
+    def extract_section(input_path, output_path, section):
+        tmp_output_path = os.path.join(tmp_dir, output_path)
+
+        subprocess.check_call([
+            'objcopy',
+            '--only-section', section,
+            '--output-target', 'binary',
+            input_path,
+            tmp_output_path,
+        ])
+
+        if os.path.getsize(tmp_output_path) == 0:
+            print(f"warning: failed to extract {output_path}; empty section {section}?", file=sys.stderr)
+            global warnings
+            warnings = True
+        else:
+            shutil.move(tmp_output_path, output_path)
+            print(f"extracted {output_path}")
+
+    extract_section(vmlinux_path, 'fips140.ko', '__fips140_module')
+    extract_section(vmlinux_path, 'fips140.hmac', '__fips140_digest')
+
+if warnings:
+    sys.exit(1)
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 099/104] crypto: fips140: add symlinks to kernel sources
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

In order to minimize source code duplication, we symlink all files under
fips140/ to their top-level source tree equivalents, e.g.:

  fips140/crypto/api.c -> crypto/api.c

We're going to build these files as an out-of-tree module (with
-DFIPS_MODULE=1).

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 fips140/crypto/aead.c                             | 1 +
 fips140/crypto/aes_generic.c                      | 1 +
 fips140/crypto/ahash.c                            | 1 +
 fips140/crypto/akcipher.c                         | 1 +
 fips140/crypto/algapi.c                           | 1 +
 fips140/crypto/algboss.c                          | 1 +
 fips140/crypto/api.c                              | 1 +
 fips140/crypto/asymmetric_keys/asymmetric_keys.h  | 1 +
 fips140/crypto/asymmetric_keys/asymmetric_type.c  | 1 +
 fips140/crypto/asymmetric_keys/mscode_parser.c    | 1 +
 fips140/crypto/asymmetric_keys/pkcs7.asn1         | 1 +
 fips140/crypto/asymmetric_keys/pkcs7_key_type.c   | 1 +
 fips140/crypto/asymmetric_keys/pkcs7_parser.c     | 1 +
 fips140/crypto/asymmetric_keys/pkcs7_parser.h     | 1 +
 fips140/crypto/asymmetric_keys/pkcs7_trust.c      | 1 +
 fips140/crypto/asymmetric_keys/pkcs7_verify.c     | 1 +
 fips140/crypto/asymmetric_keys/pkcs8.asn1         | 1 +
 fips140/crypto/asymmetric_keys/pkcs8_parser.c     | 1 +
 fips140/crypto/asymmetric_keys/public_key.c       | 1 +
 fips140/crypto/asymmetric_keys/restrict.c         | 1 +
 fips140/crypto/asymmetric_keys/selftest.c         | 1 +
 fips140/crypto/asymmetric_keys/selftest.h         | 1 +
 fips140/crypto/asymmetric_keys/selftest_ecdsa.c   | 1 +
 fips140/crypto/asymmetric_keys/selftest_rsa.c     | 1 +
 fips140/crypto/asymmetric_keys/signature.c        | 1 +
 fips140/crypto/asymmetric_keys/verify_pefile.c    | 1 +
 fips140/crypto/asymmetric_keys/verify_pefile.h    | 1 +
 fips140/crypto/asymmetric_keys/x509.asn1          | 1 +
 fips140/crypto/asymmetric_keys/x509_akid.asn1     | 1 +
 fips140/crypto/asymmetric_keys/x509_cert_parser.c | 1 +
 fips140/crypto/asymmetric_keys/x509_loader.c      | 1 +
 fips140/crypto/asymmetric_keys/x509_parser.h      | 1 +
 fips140/crypto/asymmetric_keys/x509_public_key.c  | 1 +
 fips140/crypto/authenc.c                          | 1 +
 fips140/crypto/authencesn.c                       | 1 +
 fips140/crypto/cbc.c                              | 1 +
 fips140/crypto/ccm.c                              | 1 +
 fips140/crypto/cipher.c                           | 1 +
 fips140/crypto/cmac.c                             | 1 +
 fips140/crypto/cryptd.c                           | 1 +
 fips140/crypto/ctr.c                              | 1 +
 fips140/crypto/dh.c                               | 1 +
 fips140/crypto/dh_helper.c                        | 1 +
 fips140/crypto/drbg.c                             | 1 +
 fips140/crypto/ecb.c                              | 1 +
 fips140/crypto/ecc.c                              | 1 +
 fips140/crypto/ecc_curve_defs.h                   | 1 +
 fips140/crypto/ecdh.c                             | 1 +
 fips140/crypto/ecdh_helper.c                      | 1 +
 fips140/crypto/ecdsa-p1363.c                      | 1 +
 fips140/crypto/ecdsa-x962.c                       | 1 +
 fips140/crypto/ecdsa.c                            | 1 +
 fips140/crypto/ecdsasignature.asn1                | 1 +
 fips140/crypto/echainiv.c                         | 1 +
 fips140/crypto/essiv.c                            | 1 +
 fips140/crypto/gcm.c                              | 1 +
 fips140/crypto/geniv.c                            | 1 +
 fips140/crypto/ghash-generic.c                    | 1 +
 fips140/crypto/hash.h                             | 1 +
 fips140/crypto/hmac.c                             | 1 +
 fips140/crypto/internal.h                         | 1 +
 fips140/crypto/jitterentropy-kcapi.c              | 1 +
 fips140/crypto/jitterentropy.c                    | 1 +
 fips140/crypto/jitterentropy.h                    | 1 +
 fips140/crypto/kpp.c                              | 1 +
 fips140/crypto/lskcipher.c                        | 1 +
 fips140/crypto/pcrypt.c                           | 1 +
 fips140/crypto/proc.c                             | 1 +
 fips140/crypto/rng.c                              | 1 +
 fips140/crypto/rsa-pkcs1pad.c                     | 1 +
 fips140/crypto/rsa.c                              | 1 +
 fips140/crypto/rsa_helper.c                       | 1 +
 fips140/crypto/rsaprivkey.asn1                    | 1 +
 fips140/crypto/rsapubkey.asn1                     | 1 +
 fips140/crypto/rsassa-pkcs1.c                     | 1 +
 fips140/crypto/seqiv.c                            | 1 +
 fips140/crypto/sha256.c                           | 1 +
 fips140/crypto/sha3_generic.c                     | 1 +
 fips140/crypto/sha512.c                           | 1 +
 fips140/crypto/shash.c                            | 1 +
 fips140/crypto/sig.c                              | 1 +
 fips140/crypto/simd.c                             | 1 +
 fips140/crypto/skcipher.c                         | 1 +
 fips140/crypto/skcipher.h                         | 1 +
 fips140/crypto/tcrypt.c                           | 1 +
 fips140/crypto/tcrypt.h                           | 1 +
 fips140/crypto/testmgr.c                          | 1 +
 fips140/crypto/testmgr.h                          | 1 +
 fips140/crypto/xts.c                              | 1 +
 fips140/lib/crypto/aes.c                          | 1 +
 fips140/lib/crypto/aesgcm.c                       | 1 +
 fips140/lib/crypto/gf128mul.c                     | 1 +
 fips140/lib/crypto/memneq.c                       | 1 +
 fips140/lib/crypto/sha256.c                       | 1 +
 fips140/lib/crypto/sha512.c                       | 1 +
 fips140/lib/crypto/utils.c                        | 1 +
 96 files changed, 96 insertions(+)
 create mode 120000 fips140/crypto/aead.c
 create mode 120000 fips140/crypto/aes_generic.c
 create mode 120000 fips140/crypto/ahash.c
 create mode 120000 fips140/crypto/akcipher.c
 create mode 120000 fips140/crypto/algapi.c
 create mode 120000 fips140/crypto/algboss.c
 create mode 120000 fips140/crypto/api.c
 create mode 120000 fips140/crypto/asymmetric_keys/asymmetric_keys.h
 create mode 120000 fips140/crypto/asymmetric_keys/asymmetric_type.c
 create mode 120000 fips140/crypto/asymmetric_keys/mscode_parser.c
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7.asn1
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7_key_type.c
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7_parser.c
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7_parser.h
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7_trust.c
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs7_verify.c
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs8.asn1
 create mode 120000 fips140/crypto/asymmetric_keys/pkcs8_parser.c
 create mode 120000 fips140/crypto/asymmetric_keys/public_key.c
 create mode 120000 fips140/crypto/asymmetric_keys/restrict.c
 create mode 120000 fips140/crypto/asymmetric_keys/selftest.c
 create mode 120000 fips140/crypto/asymmetric_keys/selftest.h
 create mode 120000 fips140/crypto/asymmetric_keys/selftest_ecdsa.c
 create mode 120000 fips140/crypto/asymmetric_keys/selftest_rsa.c
 create mode 120000 fips140/crypto/asymmetric_keys/signature.c
 create mode 120000 fips140/crypto/asymmetric_keys/verify_pefile.c
 create mode 120000 fips140/crypto/asymmetric_keys/verify_pefile.h
 create mode 120000 fips140/crypto/asymmetric_keys/x509.asn1
 create mode 120000 fips140/crypto/asymmetric_keys/x509_akid.asn1
 create mode 120000 fips140/crypto/asymmetric_keys/x509_cert_parser.c
 create mode 120000 fips140/crypto/asymmetric_keys/x509_loader.c
 create mode 120000 fips140/crypto/asymmetric_keys/x509_parser.h
 create mode 120000 fips140/crypto/asymmetric_keys/x509_public_key.c
 create mode 120000 fips140/crypto/authenc.c
 create mode 120000 fips140/crypto/authencesn.c
 create mode 120000 fips140/crypto/cbc.c
 create mode 120000 fips140/crypto/ccm.c
 create mode 120000 fips140/crypto/cipher.c
 create mode 120000 fips140/crypto/cmac.c
 create mode 120000 fips140/crypto/cryptd.c
 create mode 120000 fips140/crypto/ctr.c
 create mode 120000 fips140/crypto/dh.c
 create mode 120000 fips140/crypto/dh_helper.c
 create mode 120000 fips140/crypto/drbg.c
 create mode 120000 fips140/crypto/ecb.c
 create mode 120000 fips140/crypto/ecc.c
 create mode 120000 fips140/crypto/ecc_curve_defs.h
 create mode 120000 fips140/crypto/ecdh.c
 create mode 120000 fips140/crypto/ecdh_helper.c
 create mode 120000 fips140/crypto/ecdsa-p1363.c
 create mode 120000 fips140/crypto/ecdsa-x962.c
 create mode 120000 fips140/crypto/ecdsa.c
 create mode 120000 fips140/crypto/ecdsasignature.asn1
 create mode 120000 fips140/crypto/echainiv.c
 create mode 120000 fips140/crypto/essiv.c
 create mode 120000 fips140/crypto/gcm.c
 create mode 120000 fips140/crypto/geniv.c
 create mode 120000 fips140/crypto/ghash-generic.c
 create mode 120000 fips140/crypto/hash.h
 create mode 120000 fips140/crypto/hmac.c
 create mode 120000 fips140/crypto/internal.h
 create mode 120000 fips140/crypto/jitterentropy-kcapi.c
 create mode 120000 fips140/crypto/jitterentropy.c
 create mode 120000 fips140/crypto/jitterentropy.h
 create mode 120000 fips140/crypto/kpp.c
 create mode 120000 fips140/crypto/lskcipher.c
 create mode 120000 fips140/crypto/pcrypt.c
 create mode 120000 fips140/crypto/proc.c
 create mode 120000 fips140/crypto/rng.c
 create mode 120000 fips140/crypto/rsa-pkcs1pad.c
 create mode 120000 fips140/crypto/rsa.c
 create mode 120000 fips140/crypto/rsa_helper.c
 create mode 120000 fips140/crypto/rsaprivkey.asn1
 create mode 120000 fips140/crypto/rsapubkey.asn1
 create mode 120000 fips140/crypto/rsassa-pkcs1.c
 create mode 120000 fips140/crypto/seqiv.c
 create mode 120000 fips140/crypto/sha256.c
 create mode 120000 fips140/crypto/sha3_generic.c
 create mode 120000 fips140/crypto/sha512.c
 create mode 120000 fips140/crypto/shash.c
 create mode 120000 fips140/crypto/sig.c
 create mode 120000 fips140/crypto/simd.c
 create mode 120000 fips140/crypto/skcipher.c
 create mode 120000 fips140/crypto/skcipher.h
 create mode 120000 fips140/crypto/tcrypt.c
 create mode 120000 fips140/crypto/tcrypt.h
 create mode 120000 fips140/crypto/testmgr.c
 create mode 120000 fips140/crypto/testmgr.h
 create mode 120000 fips140/crypto/xts.c
 create mode 120000 fips140/lib/crypto/aes.c
 create mode 120000 fips140/lib/crypto/aesgcm.c
 create mode 120000 fips140/lib/crypto/gf128mul.c
 create mode 120000 fips140/lib/crypto/memneq.c
 create mode 120000 fips140/lib/crypto/sha256.c
 create mode 120000 fips140/lib/crypto/sha512.c
 create mode 120000 fips140/lib/crypto/utils.c

diff --git a/fips140/crypto/aead.c b/fips140/crypto/aead.c
new file mode 120000
index 000000000000..212e18356521
--- /dev/null
+++ b/fips140/crypto/aead.c
@@ -0,0 +1 @@
+../../crypto/aead.c
\ No newline at end of file
diff --git a/fips140/crypto/aes_generic.c b/fips140/crypto/aes_generic.c
new file mode 120000
index 000000000000..98deccd59067
--- /dev/null
+++ b/fips140/crypto/aes_generic.c
@@ -0,0 +1 @@
+../../crypto/aes_generic.c
\ No newline at end of file
diff --git a/fips140/crypto/ahash.c b/fips140/crypto/ahash.c
new file mode 120000
index 000000000000..81e1d69b51b3
--- /dev/null
+++ b/fips140/crypto/ahash.c
@@ -0,0 +1 @@
+../../crypto/ahash.c
\ No newline at end of file
diff --git a/fips140/crypto/akcipher.c b/fips140/crypto/akcipher.c
new file mode 120000
index 000000000000..66a618824b92
--- /dev/null
+++ b/fips140/crypto/akcipher.c
@@ -0,0 +1 @@
+../../crypto/akcipher.c
\ No newline at end of file
diff --git a/fips140/crypto/algapi.c b/fips140/crypto/algapi.c
new file mode 120000
index 000000000000..31fc6b4fb765
--- /dev/null
+++ b/fips140/crypto/algapi.c
@@ -0,0 +1 @@
+../../crypto/algapi.c
\ No newline at end of file
diff --git a/fips140/crypto/algboss.c b/fips140/crypto/algboss.c
new file mode 120000
index 000000000000..e27142d777f7
--- /dev/null
+++ b/fips140/crypto/algboss.c
@@ -0,0 +1 @@
+../../crypto/algboss.c
\ No newline at end of file
diff --git a/fips140/crypto/api.c b/fips140/crypto/api.c
new file mode 120000
index 000000000000..7c60a1d33673
--- /dev/null
+++ b/fips140/crypto/api.c
@@ -0,0 +1 @@
+../../crypto/api.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/asymmetric_keys.h b/fips140/crypto/asymmetric_keys/asymmetric_keys.h
new file mode 120000
index 000000000000..16867d35838f
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/asymmetric_keys.h
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/asymmetric_keys.h
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/asymmetric_type.c b/fips140/crypto/asymmetric_keys/asymmetric_type.c
new file mode 120000
index 000000000000..9f9119a13078
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/asymmetric_type.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/asymmetric_type.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/mscode_parser.c b/fips140/crypto/asymmetric_keys/mscode_parser.c
new file mode 120000
index 000000000000..fc2e5ba2b6ba
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/mscode_parser.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/mscode_parser.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7.asn1 b/fips140/crypto/asymmetric_keys/pkcs7.asn1
new file mode 120000
index 000000000000..c05196a6916d
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7.asn1
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7.asn1
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7_key_type.c b/fips140/crypto/asymmetric_keys/pkcs7_key_type.c
new file mode 120000
index 000000000000..1483042a2f94
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7_key_type.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7_parser.c b/fips140/crypto/asymmetric_keys/pkcs7_parser.c
new file mode 120000
index 000000000000..fadba19812d9
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7_parser.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7_parser.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7_parser.h b/fips140/crypto/asymmetric_keys/pkcs7_parser.h
new file mode 120000
index 000000000000..a002feec14a9
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7_parser.h
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7_parser.h
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7_trust.c b/fips140/crypto/asymmetric_keys/pkcs7_trust.c
new file mode 120000
index 000000000000..bc319e2fa53f
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7_trust.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7_trust.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs7_verify.c b/fips140/crypto/asymmetric_keys/pkcs7_verify.c
new file mode 120000
index 000000000000..e973804a9fd5
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs7_verify.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs7_verify.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs8.asn1 b/fips140/crypto/asymmetric_keys/pkcs8.asn1
new file mode 120000
index 000000000000..c8696cd8abc9
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs8.asn1
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs8.asn1
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/pkcs8_parser.c b/fips140/crypto/asymmetric_keys/pkcs8_parser.c
new file mode 120000
index 000000000000..4549c6abdca6
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/pkcs8_parser.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/pkcs8_parser.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/public_key.c b/fips140/crypto/asymmetric_keys/public_key.c
new file mode 120000
index 000000000000..8095065156ab
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/public_key.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/public_key.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/restrict.c b/fips140/crypto/asymmetric_keys/restrict.c
new file mode 120000
index 000000000000..78d8775f18c6
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/restrict.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/restrict.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/selftest.c b/fips140/crypto/asymmetric_keys/selftest.c
new file mode 120000
index 000000000000..634ea04a70ac
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/selftest.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/selftest.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/selftest.h b/fips140/crypto/asymmetric_keys/selftest.h
new file mode 120000
index 000000000000..3a769362b7ca
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/selftest.h
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/selftest.h
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/selftest_ecdsa.c b/fips140/crypto/asymmetric_keys/selftest_ecdsa.c
new file mode 120000
index 000000000000..efaeb42740a9
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/selftest_ecdsa.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/selftest_ecdsa.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/selftest_rsa.c b/fips140/crypto/asymmetric_keys/selftest_rsa.c
new file mode 120000
index 000000000000..d6418f82a81b
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/selftest_rsa.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/selftest_rsa.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/signature.c b/fips140/crypto/asymmetric_keys/signature.c
new file mode 120000
index 000000000000..415c34d1e33b
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/signature.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/signature.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/verify_pefile.c b/fips140/crypto/asymmetric_keys/verify_pefile.c
new file mode 120000
index 000000000000..9b7153555f36
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/verify_pefile.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/verify_pefile.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/verify_pefile.h b/fips140/crypto/asymmetric_keys/verify_pefile.h
new file mode 120000
index 000000000000..62483171759e
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/verify_pefile.h
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/verify_pefile.h
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509.asn1 b/fips140/crypto/asymmetric_keys/x509.asn1
new file mode 120000
index 000000000000..1aa8edbc2ec4
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509.asn1
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509.asn1
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509_akid.asn1 b/fips140/crypto/asymmetric_keys/x509_akid.asn1
new file mode 120000
index 000000000000..f952c11063f3
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509_akid.asn1
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509_akid.asn1
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509_cert_parser.c b/fips140/crypto/asymmetric_keys/x509_cert_parser.c
new file mode 120000
index 000000000000..a86d71968d3f
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509_cert_parser.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509_cert_parser.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509_loader.c b/fips140/crypto/asymmetric_keys/x509_loader.c
new file mode 120000
index 000000000000..efa9c866d065
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509_loader.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509_loader.c
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509_parser.h b/fips140/crypto/asymmetric_keys/x509_parser.h
new file mode 120000
index 000000000000..cbf61d79a344
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509_parser.h
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509_parser.h
\ No newline at end of file
diff --git a/fips140/crypto/asymmetric_keys/x509_public_key.c b/fips140/crypto/asymmetric_keys/x509_public_key.c
new file mode 120000
index 000000000000..000f40135e91
--- /dev/null
+++ b/fips140/crypto/asymmetric_keys/x509_public_key.c
@@ -0,0 +1 @@
+../../../crypto/asymmetric_keys/x509_public_key.c
\ No newline at end of file
diff --git a/fips140/crypto/authenc.c b/fips140/crypto/authenc.c
new file mode 120000
index 000000000000..21e091ad0815
--- /dev/null
+++ b/fips140/crypto/authenc.c
@@ -0,0 +1 @@
+../../crypto/authenc.c
\ No newline at end of file
diff --git a/fips140/crypto/authencesn.c b/fips140/crypto/authencesn.c
new file mode 120000
index 000000000000..00bb54b7be3f
--- /dev/null
+++ b/fips140/crypto/authencesn.c
@@ -0,0 +1 @@
+../../crypto/authencesn.c
\ No newline at end of file
diff --git a/fips140/crypto/cbc.c b/fips140/crypto/cbc.c
new file mode 120000
index 000000000000..aa1f6fb840c0
--- /dev/null
+++ b/fips140/crypto/cbc.c
@@ -0,0 +1 @@
+../../crypto/cbc.c
\ No newline at end of file
diff --git a/fips140/crypto/ccm.c b/fips140/crypto/ccm.c
new file mode 120000
index 000000000000..879bd39b8843
--- /dev/null
+++ b/fips140/crypto/ccm.c
@@ -0,0 +1 @@
+../../crypto/ccm.c
\ No newline at end of file
diff --git a/fips140/crypto/cipher.c b/fips140/crypto/cipher.c
new file mode 120000
index 000000000000..53fd49f62385
--- /dev/null
+++ b/fips140/crypto/cipher.c
@@ -0,0 +1 @@
+../../crypto/cipher.c
\ No newline at end of file
diff --git a/fips140/crypto/cmac.c b/fips140/crypto/cmac.c
new file mode 120000
index 000000000000..da6195375be2
--- /dev/null
+++ b/fips140/crypto/cmac.c
@@ -0,0 +1 @@
+../../crypto/cmac.c
\ No newline at end of file
diff --git a/fips140/crypto/cryptd.c b/fips140/crypto/cryptd.c
new file mode 120000
index 000000000000..b18b260ec57d
--- /dev/null
+++ b/fips140/crypto/cryptd.c
@@ -0,0 +1 @@
+../../crypto/cryptd.c
\ No newline at end of file
diff --git a/fips140/crypto/ctr.c b/fips140/crypto/ctr.c
new file mode 120000
index 000000000000..3fe3cc809347
--- /dev/null
+++ b/fips140/crypto/ctr.c
@@ -0,0 +1 @@
+../../crypto/ctr.c
\ No newline at end of file
diff --git a/fips140/crypto/dh.c b/fips140/crypto/dh.c
new file mode 120000
index 000000000000..2052a9ead300
--- /dev/null
+++ b/fips140/crypto/dh.c
@@ -0,0 +1 @@
+../../crypto/dh.c
\ No newline at end of file
diff --git a/fips140/crypto/dh_helper.c b/fips140/crypto/dh_helper.c
new file mode 120000
index 000000000000..c14488c38829
--- /dev/null
+++ b/fips140/crypto/dh_helper.c
@@ -0,0 +1 @@
+../../crypto/dh_helper.c
\ No newline at end of file
diff --git a/fips140/crypto/drbg.c b/fips140/crypto/drbg.c
new file mode 120000
index 000000000000..7f59714d2569
--- /dev/null
+++ b/fips140/crypto/drbg.c
@@ -0,0 +1 @@
+../../crypto/drbg.c
\ No newline at end of file
diff --git a/fips140/crypto/ecb.c b/fips140/crypto/ecb.c
new file mode 120000
index 000000000000..3fc2a39f7569
--- /dev/null
+++ b/fips140/crypto/ecb.c
@@ -0,0 +1 @@
+../../crypto/ecb.c
\ No newline at end of file
diff --git a/fips140/crypto/ecc.c b/fips140/crypto/ecc.c
new file mode 120000
index 000000000000..45a59d048f04
--- /dev/null
+++ b/fips140/crypto/ecc.c
@@ -0,0 +1 @@
+../../crypto/ecc.c
\ No newline at end of file
diff --git a/fips140/crypto/ecc_curve_defs.h b/fips140/crypto/ecc_curve_defs.h
new file mode 120000
index 000000000000..7a065529702f
--- /dev/null
+++ b/fips140/crypto/ecc_curve_defs.h
@@ -0,0 +1 @@
+../../crypto/ecc_curve_defs.h
\ No newline at end of file
diff --git a/fips140/crypto/ecdh.c b/fips140/crypto/ecdh.c
new file mode 120000
index 000000000000..c82cae9a6272
--- /dev/null
+++ b/fips140/crypto/ecdh.c
@@ -0,0 +1 @@
+../../crypto/ecdh.c
\ No newline at end of file
diff --git a/fips140/crypto/ecdh_helper.c b/fips140/crypto/ecdh_helper.c
new file mode 120000
index 000000000000..a37954e0aa04
--- /dev/null
+++ b/fips140/crypto/ecdh_helper.c
@@ -0,0 +1 @@
+../../crypto/ecdh_helper.c
\ No newline at end of file
diff --git a/fips140/crypto/ecdsa-p1363.c b/fips140/crypto/ecdsa-p1363.c
new file mode 120000
index 000000000000..5795bc88ebaf
--- /dev/null
+++ b/fips140/crypto/ecdsa-p1363.c
@@ -0,0 +1 @@
+../../crypto/ecdsa-p1363.c
\ No newline at end of file
diff --git a/fips140/crypto/ecdsa-x962.c b/fips140/crypto/ecdsa-x962.c
new file mode 120000
index 000000000000..e0cf7c741683
--- /dev/null
+++ b/fips140/crypto/ecdsa-x962.c
@@ -0,0 +1 @@
+../../crypto/ecdsa-x962.c
\ No newline at end of file
diff --git a/fips140/crypto/ecdsa.c b/fips140/crypto/ecdsa.c
new file mode 120000
index 000000000000..b9bf37d37397
--- /dev/null
+++ b/fips140/crypto/ecdsa.c
@@ -0,0 +1 @@
+../../crypto/ecdsa.c
\ No newline at end of file
diff --git a/fips140/crypto/ecdsasignature.asn1 b/fips140/crypto/ecdsasignature.asn1
new file mode 120000
index 000000000000..7fa5850233fc
--- /dev/null
+++ b/fips140/crypto/ecdsasignature.asn1
@@ -0,0 +1 @@
+../../crypto/ecdsasignature.asn1
\ No newline at end of file
diff --git a/fips140/crypto/echainiv.c b/fips140/crypto/echainiv.c
new file mode 120000
index 000000000000..fee662c9a8d0
--- /dev/null
+++ b/fips140/crypto/echainiv.c
@@ -0,0 +1 @@
+../../crypto/echainiv.c
\ No newline at end of file
diff --git a/fips140/crypto/essiv.c b/fips140/crypto/essiv.c
new file mode 120000
index 000000000000..6554857abd79
--- /dev/null
+++ b/fips140/crypto/essiv.c
@@ -0,0 +1 @@
+../../crypto/essiv.c
\ No newline at end of file
diff --git a/fips140/crypto/gcm.c b/fips140/crypto/gcm.c
new file mode 120000
index 000000000000..b8ef945a7444
--- /dev/null
+++ b/fips140/crypto/gcm.c
@@ -0,0 +1 @@
+../../crypto/gcm.c
\ No newline at end of file
diff --git a/fips140/crypto/geniv.c b/fips140/crypto/geniv.c
new file mode 120000
index 000000000000..059afe3c124c
--- /dev/null
+++ b/fips140/crypto/geniv.c
@@ -0,0 +1 @@
+../../crypto/geniv.c
\ No newline at end of file
diff --git a/fips140/crypto/ghash-generic.c b/fips140/crypto/ghash-generic.c
new file mode 120000
index 000000000000..ebb7c8aee335
--- /dev/null
+++ b/fips140/crypto/ghash-generic.c
@@ -0,0 +1 @@
+../../crypto/ghash-generic.c
\ No newline at end of file
diff --git a/fips140/crypto/hash.h b/fips140/crypto/hash.h
new file mode 120000
index 000000000000..41ba73037bc9
--- /dev/null
+++ b/fips140/crypto/hash.h
@@ -0,0 +1 @@
+../../crypto/hash.h
\ No newline at end of file
diff --git a/fips140/crypto/hmac.c b/fips140/crypto/hmac.c
new file mode 120000
index 000000000000..162f4c205f1b
--- /dev/null
+++ b/fips140/crypto/hmac.c
@@ -0,0 +1 @@
+../../crypto/hmac.c
\ No newline at end of file
diff --git a/fips140/crypto/internal.h b/fips140/crypto/internal.h
new file mode 120000
index 000000000000..670e77b6a0d6
--- /dev/null
+++ b/fips140/crypto/internal.h
@@ -0,0 +1 @@
+../../crypto/internal.h
\ No newline at end of file
diff --git a/fips140/crypto/jitterentropy-kcapi.c b/fips140/crypto/jitterentropy-kcapi.c
new file mode 120000
index 000000000000..30e13bbd6099
--- /dev/null
+++ b/fips140/crypto/jitterentropy-kcapi.c
@@ -0,0 +1 @@
+../../crypto/jitterentropy-kcapi.c
\ No newline at end of file
diff --git a/fips140/crypto/jitterentropy.c b/fips140/crypto/jitterentropy.c
new file mode 120000
index 000000000000..cb9a117048af
--- /dev/null
+++ b/fips140/crypto/jitterentropy.c
@@ -0,0 +1 @@
+../../crypto/jitterentropy.c
\ No newline at end of file
diff --git a/fips140/crypto/jitterentropy.h b/fips140/crypto/jitterentropy.h
new file mode 120000
index 000000000000..991e4585e6e0
--- /dev/null
+++ b/fips140/crypto/jitterentropy.h
@@ -0,0 +1 @@
+../../crypto/jitterentropy.h
\ No newline at end of file
diff --git a/fips140/crypto/kpp.c b/fips140/crypto/kpp.c
new file mode 120000
index 000000000000..8fbd20de20df
--- /dev/null
+++ b/fips140/crypto/kpp.c
@@ -0,0 +1 @@
+../../crypto/kpp.c
\ No newline at end of file
diff --git a/fips140/crypto/lskcipher.c b/fips140/crypto/lskcipher.c
new file mode 120000
index 000000000000..997c2c0eafb4
--- /dev/null
+++ b/fips140/crypto/lskcipher.c
@@ -0,0 +1 @@
+../../crypto/lskcipher.c
\ No newline at end of file
diff --git a/fips140/crypto/pcrypt.c b/fips140/crypto/pcrypt.c
new file mode 120000
index 000000000000..9ef1ba4b9f66
--- /dev/null
+++ b/fips140/crypto/pcrypt.c
@@ -0,0 +1 @@
+../../crypto/pcrypt.c
\ No newline at end of file
diff --git a/fips140/crypto/proc.c b/fips140/crypto/proc.c
new file mode 120000
index 000000000000..5dfad57a688c
--- /dev/null
+++ b/fips140/crypto/proc.c
@@ -0,0 +1 @@
+../../crypto/proc.c
\ No newline at end of file
diff --git a/fips140/crypto/rng.c b/fips140/crypto/rng.c
new file mode 120000
index 000000000000..2ac107582b56
--- /dev/null
+++ b/fips140/crypto/rng.c
@@ -0,0 +1 @@
+../../crypto/rng.c
\ No newline at end of file
diff --git a/fips140/crypto/rsa-pkcs1pad.c b/fips140/crypto/rsa-pkcs1pad.c
new file mode 120000
index 000000000000..e81ca29bc1c0
--- /dev/null
+++ b/fips140/crypto/rsa-pkcs1pad.c
@@ -0,0 +1 @@
+../../crypto/rsa-pkcs1pad.c
\ No newline at end of file
diff --git a/fips140/crypto/rsa.c b/fips140/crypto/rsa.c
new file mode 120000
index 000000000000..05903a691c9f
--- /dev/null
+++ b/fips140/crypto/rsa.c
@@ -0,0 +1 @@
+../../crypto/rsa.c
\ No newline at end of file
diff --git a/fips140/crypto/rsa_helper.c b/fips140/crypto/rsa_helper.c
new file mode 120000
index 000000000000..ae17e923013c
--- /dev/null
+++ b/fips140/crypto/rsa_helper.c
@@ -0,0 +1 @@
+../../crypto/rsa_helper.c
\ No newline at end of file
diff --git a/fips140/crypto/rsaprivkey.asn1 b/fips140/crypto/rsaprivkey.asn1
new file mode 120000
index 000000000000..c798dadccde5
--- /dev/null
+++ b/fips140/crypto/rsaprivkey.asn1
@@ -0,0 +1 @@
+../../crypto/rsaprivkey.asn1
\ No newline at end of file
diff --git a/fips140/crypto/rsapubkey.asn1 b/fips140/crypto/rsapubkey.asn1
new file mode 120000
index 000000000000..e3bbdd50e4a1
--- /dev/null
+++ b/fips140/crypto/rsapubkey.asn1
@@ -0,0 +1 @@
+../../crypto/rsapubkey.asn1
\ No newline at end of file
diff --git a/fips140/crypto/rsassa-pkcs1.c b/fips140/crypto/rsassa-pkcs1.c
new file mode 120000
index 000000000000..8cb36646c148
--- /dev/null
+++ b/fips140/crypto/rsassa-pkcs1.c
@@ -0,0 +1 @@
+../../crypto/rsassa-pkcs1.c
\ No newline at end of file
diff --git a/fips140/crypto/seqiv.c b/fips140/crypto/seqiv.c
new file mode 120000
index 000000000000..dc7e9c533d2c
--- /dev/null
+++ b/fips140/crypto/seqiv.c
@@ -0,0 +1 @@
+../../crypto/seqiv.c
\ No newline at end of file
diff --git a/fips140/crypto/sha256.c b/fips140/crypto/sha256.c
new file mode 120000
index 000000000000..487d843d4d82
--- /dev/null
+++ b/fips140/crypto/sha256.c
@@ -0,0 +1 @@
+../../crypto/sha256.c
\ No newline at end of file
diff --git a/fips140/crypto/sha3_generic.c b/fips140/crypto/sha3_generic.c
new file mode 120000
index 000000000000..3719d7f58f4a
--- /dev/null
+++ b/fips140/crypto/sha3_generic.c
@@ -0,0 +1 @@
+../../crypto/sha3_generic.c
\ No newline at end of file
diff --git a/fips140/crypto/sha512.c b/fips140/crypto/sha512.c
new file mode 120000
index 000000000000..8639124175e2
--- /dev/null
+++ b/fips140/crypto/sha512.c
@@ -0,0 +1 @@
+../../crypto/sha512.c
\ No newline at end of file
diff --git a/fips140/crypto/shash.c b/fips140/crypto/shash.c
new file mode 120000
index 000000000000..ffb09e16c542
--- /dev/null
+++ b/fips140/crypto/shash.c
@@ -0,0 +1 @@
+../../crypto/shash.c
\ No newline at end of file
diff --git a/fips140/crypto/sig.c b/fips140/crypto/sig.c
new file mode 120000
index 000000000000..742f337b3cd5
--- /dev/null
+++ b/fips140/crypto/sig.c
@@ -0,0 +1 @@
+../../crypto/sig.c
\ No newline at end of file
diff --git a/fips140/crypto/simd.c b/fips140/crypto/simd.c
new file mode 120000
index 000000000000..72398481d19d
--- /dev/null
+++ b/fips140/crypto/simd.c
@@ -0,0 +1 @@
+../../crypto/simd.c
\ No newline at end of file
diff --git a/fips140/crypto/skcipher.c b/fips140/crypto/skcipher.c
new file mode 120000
index 000000000000..225d8cb56748
--- /dev/null
+++ b/fips140/crypto/skcipher.c
@@ -0,0 +1 @@
+../../crypto/skcipher.c
\ No newline at end of file
diff --git a/fips140/crypto/skcipher.h b/fips140/crypto/skcipher.h
new file mode 120000
index 000000000000..d93f94a9127e
--- /dev/null
+++ b/fips140/crypto/skcipher.h
@@ -0,0 +1 @@
+../../crypto/skcipher.h
\ No newline at end of file
diff --git a/fips140/crypto/tcrypt.c b/fips140/crypto/tcrypt.c
new file mode 120000
index 000000000000..5c59dd1d6109
--- /dev/null
+++ b/fips140/crypto/tcrypt.c
@@ -0,0 +1 @@
+../../crypto/tcrypt.c
\ No newline at end of file
diff --git a/fips140/crypto/tcrypt.h b/fips140/crypto/tcrypt.h
new file mode 120000
index 000000000000..d643316fd181
--- /dev/null
+++ b/fips140/crypto/tcrypt.h
@@ -0,0 +1 @@
+../../crypto/tcrypt.h
\ No newline at end of file
diff --git a/fips140/crypto/testmgr.c b/fips140/crypto/testmgr.c
new file mode 120000
index 000000000000..0b105587d3d8
--- /dev/null
+++ b/fips140/crypto/testmgr.c
@@ -0,0 +1 @@
+../../crypto/testmgr.c
\ No newline at end of file
diff --git a/fips140/crypto/testmgr.h b/fips140/crypto/testmgr.h
new file mode 120000
index 000000000000..486e31b584a5
--- /dev/null
+++ b/fips140/crypto/testmgr.h
@@ -0,0 +1 @@
+../../crypto/testmgr.h
\ No newline at end of file
diff --git a/fips140/crypto/xts.c b/fips140/crypto/xts.c
new file mode 120000
index 000000000000..2ee6ce8b2c43
--- /dev/null
+++ b/fips140/crypto/xts.c
@@ -0,0 +1 @@
+../../crypto/xts.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/aes.c b/fips140/lib/crypto/aes.c
new file mode 120000
index 000000000000..752e48faca8f
--- /dev/null
+++ b/fips140/lib/crypto/aes.c
@@ -0,0 +1 @@
+../../../lib/crypto/aes.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/aesgcm.c b/fips140/lib/crypto/aesgcm.c
new file mode 120000
index 000000000000..d36e6b666511
--- /dev/null
+++ b/fips140/lib/crypto/aesgcm.c
@@ -0,0 +1 @@
+../../../lib/crypto/aesgcm.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/gf128mul.c b/fips140/lib/crypto/gf128mul.c
new file mode 120000
index 000000000000..ad4f4a232bb0
--- /dev/null
+++ b/fips140/lib/crypto/gf128mul.c
@@ -0,0 +1 @@
+../../../lib/crypto/gf128mul.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/memneq.c b/fips140/lib/crypto/memneq.c
new file mode 120000
index 000000000000..3c73a12c9f71
--- /dev/null
+++ b/fips140/lib/crypto/memneq.c
@@ -0,0 +1 @@
+../../../lib/crypto/memneq.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/sha256.c b/fips140/lib/crypto/sha256.c
new file mode 120000
index 000000000000..d36c2b0f3b4f
--- /dev/null
+++ b/fips140/lib/crypto/sha256.c
@@ -0,0 +1 @@
+../../../lib/crypto/sha256.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/sha512.c b/fips140/lib/crypto/sha512.c
new file mode 120000
index 000000000000..94712c686209
--- /dev/null
+++ b/fips140/lib/crypto/sha512.c
@@ -0,0 +1 @@
+../../../lib/crypto/sha512.c
\ No newline at end of file
diff --git a/fips140/lib/crypto/utils.c b/fips140/lib/crypto/utils.c
new file mode 120000
index 000000000000..543c49b255de
--- /dev/null
+++ b/fips140/lib/crypto/utils.c
@@ -0,0 +1 @@
+../../../lib/crypto/utils.c
\ No newline at end of file
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 101/104] crypto: fips140: add FIPS 140 module loader
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum,
	Saeed Mirzamohammadi
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Add a mechanism for loading a FIPS module from a byte array compiled
into vmlinux.

fips140-module.o and fips140-digest.o are files generated during the build
of the FIPS cryptographic module; fips140-module.o provides the following
symbols:

 - _binary_fips140_ko_start
 - _binary_fips140_ko_end

while fips140-digest.o provides the following symbol:

 - _binary_fips140_hmac_start

fips140-loader.c then uses the _binary_fips140_ko_start/_end byte array
with load_module_mem() in arch_initcall_sync call to load the
precompiled FIPS 140 module.

This code is partly based on the existing crypto/fips.c code and partly on
the Android FIPS 140 module [1].

[1]: https://android.googlesource.com/kernel/common/+/1ca1130ec62d/crypto/fips140-module.c

Only arm64 and x86-64 are explicitly supported for now.

Co-developed-by: Saeed Mirzamohammadi <saeed.mirzamohammadi@oracle.com>
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 arch/arm64/kernel/vmlinux.lds.S   |  1 +
 crypto/Makefile                   | 24 ++++++++
 crypto/fips140-loader.c           | 96 +++++++++++++++++++++++++++++++
 include/asm-generic/vmlinux.lds.h | 37 +++++++++++-
 include/linux/fips.h              | 17 ++++++
 5 files changed, 174 insertions(+), 1 deletion(-)
 create mode 100644 crypto/fips140-loader.c

diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ad6133b89e7a..58a99b2de237 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -271,6 +271,7 @@ SECTIONS
 		INIT_RAM_FS
 		*(.init.altinstructions .init.bss)	/* from the EFI stub */
 	}
+	FIPS140
 	.exit.data : {
 		EXIT_DATA
 	}
diff --git a/crypto/Makefile b/crypto/Makefile
index 6c5d59369dac..e07e93b189fe 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -7,7 +7,9 @@ obj-$(CONFIG_CRYPTO) += crypto.o
 crypto-y := api.o cipher.o
 
 obj-$(CONFIG_CRYPTO_ENGINE) += crypto_engine.o
+ifneq ($(CONFIG_CRYPTO_FIPS140_EXTMOD),y)
 obj-$(CONFIG_CRYPTO_FIPS) += fips.o
+endif
 
 crypto_algapi-$(CONFIG_PROC_FS) += proc.o
 crypto_algapi-y := algapi.o scatterwalk.o $(crypto_algapi-y)
@@ -211,3 +213,25 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
 obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
 
 obj-$(CONFIG_CRYPTO_KRB5) += krb5/
+
+#
+# Loader for standalone FIPS 140 module
+#
+
+obj-$(CONFIG_CRYPTO_FIPS140_EXTMOD) += fips140-loader.o
+
+#
+# Standalone FIPS 140 module
+#
+
+quiet_cmd_ld_bin = LD      $@
+      cmd_ld_bin = (cd "$(dir $<)" && \
+                    $(LD) -r -b binary -o $(abspath $@) $(notdir $<) && \
+                    $(OBJCOPY) --rename-section .data=$(2) $(abspath $@))
+
+$(obj)/fips140-module.o: $(src)/fips140.ko FORCE
+	$(call if_changed,ld_bin,__fips140_module)
+$(obj)/fips140-digest.o: $(src)/fips140.hmac FORCE
+	$(call if_changed,ld_bin,__fips140_digest)
+
+obj-$(CONFIG_CRYPTO_FIPS140_EXTMOD) += fips140-module.o fips140-digest.o fips140-api.o
diff --git a/crypto/fips140-loader.c b/crypto/fips140-loader.c
new file mode 100644
index 000000000000..865d45d46786
--- /dev/null
+++ b/crypto/fips140-loader.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * FIPS 140-3 module loader.
+ *
+ * Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com>
+ * Copyright 2021 Google LLC
+ * Copyright (c) 2025, Oracle and/or its affiliates.
+ */
+
+#include <linux/fips.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/panic.h>
+#include <linux/printk.h>
+#include <linux/string.h>
+
+#include <crypto/api.h>
+#include <crypto/hash.h>
+
+int fips_enabled;
+EXPORT_SYMBOL_GPL(fips_enabled);
+
+ATOMIC_NOTIFIER_HEAD(fips_fail_notif_chain);
+EXPORT_SYMBOL_GPL(fips_fail_notif_chain);
+
+void fips_fail_notify(void)
+{
+	if (fips_enabled)
+		atomic_notifier_call_chain(&fips_fail_notif_chain, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(fips_fail_notify);
+
+/* defined in crypto/fips140-{module,digest}.o -OR- vmlinux.lds */
+EXPORT_SYMBOL_GPL(_binary_fips140_ko_start);
+EXPORT_SYMBOL_GPL(_binary_fips140_ko_end);
+EXPORT_SYMBOL_GPL(_binary_fips140_hmac_start);
+
+/* Process kernel command-line parameter at boot time. fips=0 or fips=1 */
+static int fips_enable(char *str)
+{
+	fips_enabled = !!simple_strtol(str, NULL, 0);
+	if (!fips_enabled)
+		pr_info("FIPS 140-3 module: disabled\n");
+
+	return 1;
+}
+
+__setup("fips=", fips_enable);
+
+static struct ctl_table crypto_sysctl_table[] = {
+	{
+		.procname	= "fips_enabled",
+		.data		= &fips_enabled,
+		.maxlen		= sizeof(int),
+		.mode		= 0444,
+		.proc_handler	= proc_dointvec,
+	},
+};
+
+static int __init fips_loader_init(void)
+{
+	void *ko_mem;
+	int err;
+	struct ctl_table_header *crypto_sysctls;
+
+	if (!fips_enabled) {
+		/* Add crypto sysctl for nonfips mode */
+		crypto_sysctls = register_sysctl("crypto", crypto_sysctl_table);
+		if (!crypto_sysctls)
+			pr_err("fips 140: failed to register sysctl for nonfips mode");
+
+		return 0;
+	}
+
+	/*
+	 * Duplicate the memory as the kernel module loader will
+	 * modify it and mess up the integrity check.
+	 */
+	ko_mem = kvmemdup(_binary_fips140_ko_start, _binary_fips140_ko_size, GFP_KERNEL);
+	if (!ko_mem) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = load_module_mem(ko_mem, _binary_fips140_ko_size);
+	if (err)
+		goto out;
+
+	kvfree(ko_mem);
+
+out:
+	if (err)
+		panic("FIPS 140-3 module: loading error\n");
+	return err;
+}
+arch_initcall_sync(fips_loader_init);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 1881d9b6b3ae..b4aee570223c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -454,6 +454,40 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 #endif
 #endif
 
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+/*
+ * We have an external module; include it and its digest in their own
+ * named sections so they are easy to extract from the vmlinux ELF file
+ * after the kernel has been built.
+ */
+#define FIPS140 \
+	. = ALIGN(PAGE_SIZE); \
+	__fips140_module : AT(ADDR(__fips140_module) - LOAD_OFFSET) {	\
+		*(__fips140_module)					\
+	}								\
+	. = ALIGN(PAGE_SIZE);						\
+	__fips140_digest : AT(ADDR(__fips140_digest) - LOAD_OFFSET) {	\
+		*(__fips140_digest)					\
+	}
+#else
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+/*
+ * We don't have an external module (yet) but the kernel has been built
+ * with the loader, so this just defines an empty byte array where the
+ * module will go eventually.
+ */
+#define FIPS140 \
+	_binary_fips140_ko_start = .; \
+	_binary_fips140_ko_end = .; \
+	_binary_fips140_hmac_start = .; \
+	_binary_fips140_hmac_end = .;
+#else
+#define FIPS140
+#endif
+#endif
+
+
+
 /*
  * Read only Data
  */
@@ -1145,7 +1179,8 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 		INIT_CALLS						\
 		CON_INITCALL						\
 		INIT_RAM_FS						\
-	}
+	}								\
+	FIPS140
 
 #define BSS_SECTION(sbss_align, bss_align, stop_align)			\
 	. = ALIGN(sbss_align);						\
diff --git a/include/linux/fips.h b/include/linux/fips.h
index c6961e932fef..81560dfc6cef 100644
--- a/include/linux/fips.h
+++ b/include/linux/fips.h
@@ -2,12 +2,29 @@
 #ifndef _FIPS_H
 #define _FIPS_H
 
+#include <linux/init.h>
+
+#include <crypto/sha2.h> /* SHA256_DIGEST_SIZE */
+
 #ifdef CONFIG_CRYPTO_FIPS
+/*
+ * fips_enabled = FIPS mode was requested on the command line
+ * fips_operational = FIPS module has run self-tests etc. and is operational
+ */
 extern int fips_enabled;
+extern int fips_operational;
+
 extern struct atomic_notifier_head fips_fail_notif_chain;
 
 void fips_fail_notify(void);
 
+/* FIPS-certified module blob and digest */
+extern const u8 __initconst _binary_fips140_ko_start[];
+extern const u8 __initconst _binary_fips140_ko_end[];
+extern const u8 __initconst _binary_fips140_hmac_start[SHA256_DIGEST_SIZE];
+
+#define _binary_fips140_ko_size (_binary_fips140_ko_end - _binary_fips140_ko_start)
+
 #else
 #define fips_enabled 0
 
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 098/104] crypto: fips140: manual fixups for lib/crypto/sha512.c
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Don't build arch-specific SHA512 code yet when building the FIPS 140
standalone module.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 lib/crypto/sha512.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/crypto/sha512.c b/lib/crypto/sha512.c
index 9a170bf1a48c..a6a3e102c6a8 100644
--- a/lib/crypto/sha512.c
+++ b/lib/crypto/sha512.c
@@ -132,7 +132,7 @@ sha512_blocks_generic(struct sha512_block_state *state,
 	} while (--nblocks);
 }
 
-#ifdef CONFIG_CRYPTO_LIB_SHA512_ARCH
+#if defined(CONFIG_CRYPTO_LIB_SHA512_ARCH) && !defined(FIPS_MODULE)
 #include "sha512.h" /* $(SRCARCH)/sha512.h */
 #else
 #define sha512_blocks sha512_blocks_generic
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 097/104] crypto: fips140: manual fixups for lib/crypto/sha256.c
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Don't build arch-specific SHA256 code yet when building the FIPS 140
standalone module.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 lib/crypto/sha256.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/crypto/sha256.c b/lib/crypto/sha256.c
index 36a9f2bf77e2..bc20cdb9eb94 100644
--- a/lib/crypto/sha256.c
+++ b/lib/crypto/sha256.c
@@ -148,7 +148,7 @@ sha256_blocks_generic(struct sha256_block_state *state,
 	memzero_explicit(W, sizeof(W));
 }
 
-#if defined(CONFIG_CRYPTO_LIB_SHA256_ARCH) && !defined(__DISABLE_EXPORTS)
+#if defined(CONFIG_CRYPTO_LIB_SHA256_ARCH) && !defined(__DISABLE_EXPORTS) && !defined(FIPS_MODULE)
 #include "sha256.h" /* $(SRCARCH)/sha256.h */
 #else
 #define sha256_blocks sha256_blocks_generic
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 096/104] crypto: fips140: manual fixups for include/crypto/aes.h
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Define fips_/nonfips_ variants of crypto_aes_*sbox when the kernel is
configured to use a standalone FIPS module.

Vegard Nossum <vegard.nossum@oracle.com>
---
 include/crypto/aes.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 77f5515c49c9..fc84ffcd00a7 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -101,6 +101,16 @@ DECLARE_CRYPTO_API(aes_decrypt, void,
 	(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in),
 	(ctx, out, in));
 
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+#ifdef FIPS_MODULE
+#define crypto_aes_sbox fips_crypto_aes_sbox
+#define crypto_aes_inv_sbox fips_crypto_aes_inv_sbox
+#else
+#define crypto_aes_sbox nonfips_crypto_aes_sbox
+#define crypto_aes_inv_sbox nonfips_crypto_aes_inv_sbox
+#endif
+#endif
+
 extern const u8 crypto_aes_sbox[];
 extern const u8 crypto_aes_inv_sbox[];
 
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 095/104] crypto: fips140: manual fixups for include/crypto/internal/rsa.h
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Define fips_/nonfips_ variants of rsa_pkcs1pad_tmpl and
rsassa_pkcs1_tmpl when the kernel is configured to use a standalone
FIPS module.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 include/crypto/internal/rsa.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h
index 1265aa81f6fe..9028a184d06e 100644
--- a/include/crypto/internal/rsa.h
+++ b/include/crypto/internal/rsa.h
@@ -12,6 +12,16 @@
 #include <linux/types.h>
 #include <crypto/akcipher.h>
 
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+#ifdef FIPS_MODULE
+#define rsa_pkcs1pad_tmpl fips_rsa_pkcs1pad_tmpl
+#define rsassa_pkcs1_tmpl fips_rsassa_pkcs1_tmpl
+#else
+#define rsa_pkcs1pad_tmpl nonfips_rsa_pkcs1pad_tmpl
+#define rsassa_pkcs1_tmpl nonfips_rsassa_pkcs1_tmpl
+#endif
+#endif
+
 /**
  * rsa_key - RSA key structure
  * @n           : RSA modulus raw byte stream
-- 
2.39.3


^ permalink raw reply related

* [PATCH RFC 093/104] crypto: fips140: manual fixups for crypto/internal.h
From: Vegard Nossum @ 2025-09-04 15:52 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto, Luis Chamberlain,
	Petr Pavlu, Daniel Gomez
  Cc: Ard Biesheuvel, Eric Biggers, Jason A . Donenfeld,
	Greg Kroah-Hartman, Wang, Jay, Nicolai Stange, Vladis Dronov,
	Stephan Mueller, Sami Tolvanen, linux-modules, Vegard Nossum
In-Reply-To: <20250904155216.460962-1-vegard.nossum@oracle.com>

Define fips_/nonfips_ variants of cryoto_{alg_list,alg_sem,chain} when
the kernel is configured to use a standalone FIPS module.

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
---
 crypto/internal.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/crypto/internal.h b/crypto/internal.h
index f4b12863d922..08f2f04b010d 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -62,6 +62,18 @@ enum {
 /* Maximum number of (rtattr) parameters for each template. */
 #define CRYPTO_MAX_ATTRS 32
 
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+#ifdef FIPS_MODULE
+#define crypto_alg_list fips_crypto_alg_list
+#define crypto_alg_sem fips_crypto_alg_sem
+#define crypto_chain fips_crypto_chain
+#else
+#define crypto_alg_list nonfips_crypto_alg_list
+#define crypto_alg_sem nonfips_crypto_alg_sem
+#define crypto_chain nonfips_crypto_chain
+#endif
+#endif
+
 extern struct list_head crypto_alg_list;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct blocking_notifier_head crypto_chain;
-- 
2.39.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox