-- This configuration file is licensed under the CC0 license.
-- Do whatever you want with it.
--
-- This is an example of how to use autokernel's capabilites for a hardening module.
-- It is designed to harden many aspects of the kernel based on choices
-- taken from several projects:
--
-- - [KSSP](https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project/Recommended_Settings)
-- - [CLIP OS](https://docs.clip-os.org/clipos/kernel.html#configuration)
-- - [kconfig-hardened-check](https://github.com/a13xp0p0v/kconfig-hardened-check)
--
-- After including this module be sure to set MODULE_SIG_KEY "path/to/sigining_key.pem".
-- In practice, this module should be modularized further.

local cmdline = ""
local function add_cmdline(opt)
	cmdline = cmdline .. " " .. opt
end

-- This unlocks extra configuration options we need
EXPERT "y"

-- Required for several options. At best place outside of this module.
PCI "y"
PCI_MSI "y"
NET "y"
INET "y"

-- Don't allow direct access to physical memory.
-- The /dev/mem device should not be required by any user application nowadays.
DEVMEM "n"

if MODULES:is "y" then
	-- Enforce strict memory mappings permissions for loadable kernel modules.
	if kernel_version >= ver("4.11") then
		STRICT_MODULE_RWX "y"
	else
		DEBUG_SET_MODULE_RONX "y"
	end

	-- But if MODULES is enabled, at least they should be signed with a per-build key.
	MODULE_SIG "y"
	MODULE_SIG_ALL "y"
	-- Set signature to SHA512
	MODULE_SIG_SHA512 "y"
	-- Require signed modules
	MODULE_SIG_FORCE "y"
end

-- Dangerous; enabling this allows direct physical memory writing.
ACPI_CUSTOM_METHOD "n"

-- Dangerous; enabling this disables brk ASLR.
COMPAT_BRK "n"

-- Dangerous; enabling this allows direct kernel memory writing.
if kernel_version <= ver("5.12") then
	DEVKMEM "n"
end

-- Dangerous; exposes kernel text image layout.
PROC_KCORE "n"

-- Dangerous; enabling this disables VDSO ASLR.
COMPAT_VDSO "n"

-- Dangerous; Disable the kexec() system call to prevent an already-root
-- attacker from rebooting on an untrusted kernel.
KEXEC "n"
KEXEC_FILE "n"

-- Dangerous; enabling this allows replacement of running kernel.
HIBERNATION "n"

-- We do not want our kernel to support miscellaneous binary classes.
-- ELF binaries and interpreted scripts starting with a shebang are enough
-- Also easily confused by misconfigured userspace, keep off.
BINFMT_MISC "n"
-- Also disable a.out/ECOFF format. (This is unrelated to a.out files
-- generated by gcc and alike, which are ELF files)
BINFMT_AOUT "n"

-- Use the modern PTY interface (devpts) only.
LEGACY_PTYS "n"

-- The userfaultfd() system call adds attack surface and can make heap sprays easier.
-- Note that the vm.unprivileged_userfaultfd sysctl can also be used to restrict the
-- use of this system call to privileged users.
if kernel_version >= ver("4.3") then
	USERFAULTFD "n"
end
-- Disable the uselib system call, which is not needed on systems with a modern libc
USELIB "n"

-- The /dev/port device should not be used anymore by userspace,
-- and it could increase the kernel attack surface.
DEVPORT "n"

-- Enabling this feature can make cache side-channel attacks such
-- as FLUSH+RELOAD much easier to carry out.
KSM "n"

-- Disable kprobes (allow callbacks on any kernel function)
KPROBES "n"

-- Symbols are only useful for debug and attack purposes.
KALLSYMS "n"

-- User namespaces can be useful for some use cases but even more
-- to an attacker. Optional because required by systemd.
--USER_NS "n"

-- Do not export ZSMALLOC statistics
ZSMALLOC_STAT "n"

-- Do not track page owners.
PAGE_OWNER "n"

-- Disable exporting crashed kernel images through /proc/vmcore
PROC_VMCORE "n"

-- Disable debug_fs
DEBUG_FS "n"

-- Disable kernel live-patching
LIVEPATCH "n"

-- Do not automatically load any line discipline that is in a kernel module
-- when an unprivileged user asks for it.
if kernel_version >= ver("5.1") then
	LDISC_AUTOLOAD "n"
end

-- Disable exporting pagetable layout to prevent information leak.
if kernel_version >= ver("5.6") then
	PTDUMP_DEBUGFS "n"
else
	X86_PTDUMP "n"
end

-- Prevent potential further exploitation of a bug by immediately panicking the kernel.
PANIC_ON_OOPS "y"

-- Report BUG() conditions and kill the offending process.
BUG "y"

if kernel_version >= ver("4.19") then
	-- Do not credit entropy generated by the CPU manufacturer’s HWRNG
	-- nor provided by the bootloader, and included in Linux’s entropy pool.
	-- Fast and robust initialization of Linux’s CSPRNG is instead achieved
	-- thanks to the TPM’s HWRNG (see documentation of HW_RANDOM_TPM and the
	-- rng_core.default_quality command line parameter).
	RANDOM_TRUST_CPU "n"
	RANDOM_TRUST_BOOTLOADER "n"
end

-- Enable hardware random
HW_RANDOM "y"
HW_RANDOM_INTEL "y"
HW_RANDOM_AMD "y"

-- Enable Expose the TPM’s Random Number Generator (RNG) as a Hardware RNG (HWRNG) and
-- expose the TPM’s Random Number Generator (RNG) as a Hardware RNG (HWRNG)
-- device, allowing the kernel to collect randomness from it. See documentation
-- of RANDOM_TRUST_CPU and the rng_core.default_quality command line parameter
-- for supplementary information.
TCG_TPM "y"
HW_RANDOM_TPM "y"
-- Increase trust in the TPM’s HWRNG to robustly and fastly initialize Linux’s CSPRNG
-- by crediting half of the entropy it provides.
add_cmdline "rng_core.default_quality=512"

-- Enable the auditing infrastructure.
AUDIT "y"

-- Make sure kernel page tables have safe permissions.
if kernel_version < ver("4.11") then
	DEBUG_RODATA "y"
end
-- This is useful even in a production kernel to enable further configuration options
-- that have security benefits.
DEBUG_KERNEL "y"
-- Enable sanity checks in virtual to page code.
DEBUG_VIRTUAL "y"
-- Ensure kernel page tables have strict permissions.
if kernel_version >= ver("4.11") and ARCH_OPTIONAL_KERNEL_RWX:is "y" then
	STRICT_KERNEL_RWX "y"
end
-- Check and report any dangerous memory mapping permissions, i.e., both writable and
-- executable kernel pages.
if kernel_version >= ver("4.4") then
	DEBUG_WX "y"
end

-- Use strong stack protector for best stack canary coverage.
if kernel_version >= ver("4.18") then
	STACKPROTECTOR "y"
	STACKPROTECTOR_STRONG "y"
else
	CC_STACKPROTECTOR_STRONG "y"
end

-- If you must have DEVMEM, at least enable STRICT mode
if DEVMEM:is "y" then
	STRICT_DEVMEM "y"
	if kernel_version >= ver("4.5") then
		IO_STRICT_DEVMEM "y"
	end
end

-- Provides some protections against SYN flooding.
SYN_COOKIES "y"

-- Perform additional validation of various commonly targeted structures.
DEBUG_CREDENTIALS "y"
DEBUG_NOTIFIERS "y"
DEBUG_LIST "y"
DEBUG_SG "y"
if kernel_version >= ver("4.10") then
	BUG_ON_DATA_CORRUPTION "y"
end
SCHED_STACK_END_CHECK "y"

-- Provide userspace with seccomp BPF API for syscall attack surface reduction.
SECCOMP "y"

-- Enable us to choose different security modules.
SECURITY "y"
-- -- Enable SELinux for hosts that intend to leverage it in their security model.
-- SECURITY_SELINUX "y"
-- -- We do not need SELinux to be disableable by a boot parameter.
-- SECURITY_SELINUX_BOOTPARAM "n"
-- -- We do not want SELinux to be disabled. In addition, keeping this option off makes
-- -- LSM structures such as security hooks read-only.
-- SECURITY_SELINUX_DISABLE "n"
-- -- For now, but should eventually be set to n.
-- SECURITY_SELINUX_DEVELOP "y"

-- Enables ptrace scope restrictions.
SECURITY_YAMA "y"

-- Perform usercopy bounds checking. (And disable fallback to gain full whitelist enforcement.)
if kernel_version >= ver("4.8") then
	-- Harden data copies between kernel and user spaces, preventing classes
	-- of heap overflow exploits and information leaks.
	HARDENED_USERCOPY "y"
	if kernel_version <= ver("5.18") then
		HARDENED_USERCOPY_PAGESPAN "n"
		-- Use strict whitelisting mode, i.e., do not WARN().
		if kernel_version >= ver("4.16") then
			HARDENED_USERCOPY_FALLBACK "n"
		end
	end
end

-- Merging SLAB pages can make heap exploitation easier
if kernel_version >= ver("4.13") then
	SLAB_MERGE_DEFAULT "n"
end
-- Randomize allocator freelists.
if kernel_version >= ver("4.7") then
	SLAB_FREELIST_RANDOM "y"
end
-- Harden slab metadata.
if kernel_version >= ver("4.14") then
	SLAB_FREELIST_HARDENED "y"
end

-- Randomize high-order page allocation freelist.
-- Page allocator randomization is primarily a performance improvement for direct-mapped
-- memory-side-cache utilization, but it does reduce the predictability of page allocations
-- and thus complements SLAB_FREELIST_RANDOM. The page_alloc.shuffle=1 parameter needs to
-- be added to the kernel command line.
if kernel_version >= ver("5.2") then
	SHUFFLE_PAGE_ALLOCATOR "y"
	add_cmdline "page_alloc.shuffle=1"
end

if kernel_version >= ver("5.3") then
	-- Wipe slab and page allocations
	-- This replaces "slub_debug=P" and "page_poison=1" and can control all types
	-- of memory allocation and wiping now. The init_on_free is only needed if there
	-- is concern about minimizing stale data lifetime.
	INIT_ON_ALLOC_DEFAULT_ON "y"
	INIT_ON_FREE_DEFAULT_ON "y"
else
	if kernel_version < ver("5.3") then
		-- Allow and enable allocator validation checking.
		SLUB_DEBUG "y"
		add_cmdline "slub_debug=P"
	end

	if kernel_version >= ver("4.6") then
		-- Wipe higher-level memory allocations when they are freed (needs "page_poison=1").
		PAGE_POISONING "y"
		-- Enable buddy allocator free poisoning.
		add_cmdline "page_poison=1"
		-- If you can't afford even more performance penalty, set PAGE_POISONING_NO_SANITY=y
		-- This only works if HIBERNATION is disabled, as it selects PAGE_POISONING_NO_SANITY.
		if HIBERNATION:is "n" then
			PAGE_POISONING_NO_SANITY "n"
		end
		PAGE_POISONING_ZERO "y"
	end
end

-- Initialize all stack variables on function entry, with
if kernel_version >= ver("5.9") then
	if CC_HAS_AUTO_VAR_INIT_PATTERN:is "y" then
		INIT_STACK_ALL_PATTERN "y"
	else
		INIT_STACK_ALL_ZERO "y"
	end
elseif kernel_version >= ver("5.2") then
	if CC_HAS_AUTO_VAR_INIT:is "y" then
		INIT_STACK_ALL "y"
	end
elseif kernel_version >= ver("5.2") and HAVE_GCC_PLUGINS:is "y" then
	-- Force all structures to be initialized before they are passed to other functions.
	-- When building with GCC:
	GCC_PLUGIN_STRUCTLEAK_BYREF_ALL "y"
end

-- Virtually-mapped stacks benefit from guard pages,
-- thus making kernel stack overflows harder to exploit.
if kernel_version >= ver("4.9") then
	VMAP_STACK "y"
end

-- Perform extensive checks on reference counting. (Unconditionally enabled since 5.5)
if kernel_version >= ver("4.13") and kernel_version < ver("5.5") then
	REFCOUNT_FULL "y"
end

-- Check for memory copies that might overflow a structure in str*() and
-- mem*() functions both at build-time and run-time.
if kernel_version >= ver("4.13") then
	FORTIFY_SOURCE "y"
end

if kernel_version >= ver("4.8") and HAVE_GCC_PLUGINS:is "y" then
	-- Gather additional entropy at boot time for systems that may not have
	-- appropriate entropy sources.
	if kernel_version >= ver("4.9") then
		GCC_PLUGIN_LATENT_ENTROPY "y"
	end

	-- Wipe stack contents on syscall exit (reduces stale data lifetime in stack)
	if kernel_version >= ver("5.2") then
		GCC_PLUGIN_STACKLEAK "y"
		STACKLEAK_METRICS "n"
		STACKLEAK_RUNTIME_DISABLE "n"
	end
end

-- Needed to benefit from microcode updates and thus security fixes
-- (e.g., additional Intel pseudo-MSRs to be used by the kernel as a
-- mitigation for various speculative execution vulnerabilities).
MICROCODE "y"
-- Retpolines are needed to protect against Spectre v2.
if kernel_version >= ver("4.15") then
	RETPOLINE "y"
end
-- Always enable spectre_v2 mitigation, even on CPUs that report they are
-- not affected. This implies spectre_v2_user=on, which enables the mitigation
-- against user space to user space task attacks (namely IBPB and STIBP when
-- available and relevant).
add_cmdline "spectre_v2=on"
-- Always enable spectre_v4 mitigation
add_cmdline "spec_store_bypass_disable=seccomp"

-- Mitigations for the Microarchitectural Data Sampling (MDS) vulnerability
-- on intel processors, and optionally allow disabling SMT (Simultaneous multithreading)
-- to do so.
add_cmdline "mds=full"
-- If you want to disable hyperthreading, use this line instead.
--add_cmdline "mds=full,nosmt"

-- The IOMMU allows for protecting the system’s main memory from arbitrary
-- accesses from devices (e.g., DMA attacks). Note that this is related to
-- hardware features.
IOMMU_SUPPORT "y"
INTEL_IOMMU "y"
if kernel_version >= ver("4.4") then
	INTEL_IOMMU_SVM "y"
end
INTEL_IOMMU_DEFAULT_ON "y"
AMD_IOMMU "y"
AMD_IOMMU_V2 "y"
-- Always enable iommu
add_cmdline "iommu=force"

-- Prevent unprivileged users from gathering information from the kernel log
-- buffer via dmesg(8). Note that this still can be overridden through the
-- kernel.dmesg_restrict sysctl.
SECURITY_DMESG_RESTRICT "y"
if kernel_version >= ver("4.11") then
	-- This makes the kernel route all usermode helper calls to a single binary
	-- that cannot have its name changed. Without this, the kernel can be tricked
	-- into calling an attacker-controlled binary (e.g. to bypass SMAP, cf.
	-- exploitation of CVE-2016-8655).
	STATIC_USERMODEHELPER "y"
	-- Currently, we have no need for usermode helpers therefore we simply disable them.
	-- If you need them, this path will need to be set to a custom trusted binary in charge
	-- of filtering and choosing what real helpers should then be called.
	STATIC_USERMODEHELPER_PATH ""
end

-- In order to work properly, this mitigation requires userspace support
-- that is not commonly configured. You can enable this yourself if you want
-- provide the support on your system.
if kernel_version >= ver("4.14") then
	RESET_ATTACK_MITIGATION "n"
end
-- This restricts loading modules from one file system only. Must be enabled via cmdline
-- or SECURITY_LOADPIN_ENFORCE=y, which could be used if there is no initramfs.
if kernel_version >= ver("4.7") then
	SECURITY_LOADPIN "y"
end

if kernel_version >= ver("5.4") then
	-- Basically, the lockdown LSM tries to strengthen the boundary between
	-- the superuser and the kernel.  The integrity mode thus restricts access
	-- to features that would allow userland to modify the running kernel, and
	-- the confidentiality mode extends these restrictions to features that would
	-- allow userland to extract confidential information held inside the kernel.
	SECURITY_LOCKDOWN_LSM "y"
	SECURITY_LOCKDOWN_LSM_EARLY "y"
	LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY "y"
end

-- Use maximum number of randomized bits for the mmap base address on x86_64.
if kernel_version >= ver("4.5") then
	ARCH_MMAP_RND_BITS(32)
end

-- The list of security modules to enable, in load order.
if kernel_version >= ver("5.1") then
	LSM "lockdown,yama,loadpin,selinux"
end

if X86:is "y" then
	-- Disallow allocating the first 64k of memory. This should in particular
	-- be non-zero to prevent the exploitation of kernel NULL pointer bugs.
	DEFAULT_MMAP_MIN_ADDR(0x10000)

	if kernel_version >= ver("4.15") then
		-- Enable Kernel Page Table Isolation to remove an entire class of
		-- cache timing side-channels.
		PAGE_TABLE_ISOLATION "y"
		-- This force-enables KPTI even on CPUs claiming to be safe from Meltdown.
		add_cmdline "pti=on"
	end
	-- Don't allow for 16-bit program emulation and associated LDT tricks.
	if kernel_version >= ver("4.3") then
		MODIFY_LDT_SYSCALL "n"
	end

	-- Enable the RDRAND instruction to benefit from a secure hardware RNG if
	-- supported. See also RANDOM_TRUST_CPU.
	ARCH_RANDOM "y"
	-- Randomize position of kernel (requires UEFI RNG or bootloader support
	-- for /chosen/kaslr-seed DT property).
	RANDOMIZE_BASE "y"

	-- Machine Check Exceptions can report suspicious hardware errors, some of
	-- which may for instance, on systems with ECC memory, reveal an ongoing
	-- Rowhammer attack.
	X86_MCE "y"
	X86_MCE_INTEL "y"
	X86_MCE_AMD "y"
	-- Make the kernel panic on uncorrected Machine Check Errors.
	-- This could prevent an ongoing Rowhammer attack.
	add_cmdline "mce=0"

	-- Disable TSX to mitigate the TSX Asynchronous Abort (TAA) Intel CPU
	-- vulnerability. Same as commandline tsx=off.
	X86_INTEL_TSX_MODE_OFF "y"

	-- Disable /dev/cpu/*/{msr,cpuid} which would only present userspace
	-- with more attack surface.
	X86_MSR "n"
	X86_CPUID "n"

	-- Page Attribute Tables are the modern equivalents of MTRRs
	-- (Memory Type Range Registers) which can make speculative execution
	-- bugs a bit harder to exploit.
	X86_PAT "y"

	if kernel_version <= ver("5.18") then
		-- Enable Supervisor Mode Access Prevention to prevent
		-- ret2usr exploitation techniques.
		X86_SMAP "y"
	end
	-- Enable User Mode Instruction Prevention to prevent some instructions
	-- that unnecessarily expose information about the hardware state from
	-- being executed in user mode.
	if kernel_version >= ver("5.5") then
		X86_UMIP "y"
	elseif kernel_version >= ver("4.15") then
		X86_INTEL_UMIP "y"
	end
end

if X86_64:is "y" then
	if kernel_version >= ver("4.8") then
		RANDOMIZE_MEMORY "y"
	end
	-- The vsyscall table is not required anymore by libc and is a fixed-position
	-- potential source of ROP gadgets.
	if kernel_version >= ver("4.4") then
		LEGACY_VSYSCALL_NONE "y"
	end
	X86_VSYSCALL_EMULATION "n"
	-- Remove additional attack surface, unless you really need them.
	IA32_EMULATION "n"
	-- Disable native x32 ABI
	if kernel_version >= ver("5.18") then
		X86_X32_ABI "n"
	else
		X86_X32 "n"
	end
elseif X86:is "y" then
	-- On 32-bit kernels, require PAE for NX bit support.
	M486 "n"
	HIGHMEM4G "n"
	HIGHMEM64G "y"
	X86_PAE "y"
elseif os.getenv("ARCH") == "arm64" then
	-- Disallow allocating the first 32k of memory (cannot be 64k due to ARM loader).
	DEFAULT_MMAP_MIN_ADDR(0x8000)
	-- Make sure PAN emulation is enabled.
	if kernel_version >= ver("4.10") then
		ARM64_SW_TTBR0_PAN "y"
	end
	-- Enable Kernel Page Table Isolation to remove an entire class of cache timing side-channels.
	if kernel_version >= ver("4.16") then
		UNMAP_KERNEL_AT_EL0 "y"
	end
elseif os.getenv("ARCH") == "arm" then
	-- Disallow allocating the first 32k of memory (cannot be 64k due to ARM loader).
	DEFAULT_MMAP_MIN_ADDR(0x8000)
	-- For maximal userspace memory area (and maximum ASLR).
	VMSPLIT_3G "y"
	-- If building an old out-of-tree Qualcomm kernel, this is similar to STRICT_KERNEL_RWX.
	STRICT_MEMORY_RWX "y"
	-- Make sure PXN/PAN emulation is enabled.
	if kernel_version >= ver("4.3") then
		CPU_SW_DOMAIN_PAN "y"
	end
	-- Dangerous; old interfaces and needless additional attack surface.
	OABI_COMPAT "n"
end

-- set cmdline (in practice better return the cmdline and set this in your own config,
-- so you can add more if required)
CMDLINE(cmdline)
