diff --git a/usr/share/hardened-kernel/build b/usr/share/hardened-kernel/build index f42655c..5bdbdbe 100755 --- a/usr/share/hardened-kernel/build +++ b/usr/share/hardened-kernel/build @@ -93,6 +93,7 @@ tar -xf "${source_folder}/linux-${version}.tar.xz" -C "$working_folder" ls "$extracted_linux_kernel_sources_folder" cat "${source_folder}/linux-hardened-${version}.a.patch" | patch --silent -p1 -d "$extracted_linux_kernel_sources_folder" +cat "${MYDIR}/patches/lockdown/*.patch" | patch --silent -p1 -d "$extracted_linux_kernel_sources_folder" cp "${MYDIR}/${kernel_config}" "$extracted_linux_kernel_sources_folder/.config" diff --git a/usr/share/hardened-kernel/hardened-host-kernel b/usr/share/hardened-kernel/hardened-host-kernel index 6cf2f74..0bf3a9a 100644 --- a/usr/share/hardened-kernel/hardened-host-kernel +++ b/usr/share/hardened-kernel/hardened-host-kernel @@ -6958,6 +6958,7 @@ CONFIG_FORTIFY_SOURCE=y CONFIG_PAGE_SANITIZE=y CONFIG_PAGE_SANITIZE_VERIFY=y # CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_SECURITY_LOCKDOWN=y # CONFIG_SECURITY_SELINUX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set diff --git a/usr/share/hardened-kernel/hardened-vm-kernel b/usr/share/hardened-kernel/hardened-vm-kernel index d232d58..b461616 100644 --- a/usr/share/hardened-kernel/hardened-vm-kernel +++ b/usr/share/hardened-kernel/hardened-vm-kernel @@ -4643,6 +4643,7 @@ CONFIG_FORTIFY_SOURCE=y CONFIG_PAGE_SANITIZE=y CONFIG_PAGE_SANITIZE_VERIFY=y # CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_SECURITY_LOCKDOWN=y # CONFIG_SECURITY_SELINUX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set diff --git a/usr/share/hardened-kernel/patches/lockdown/README.md b/usr/share/hardened-kernel/patches/lockdown/README.md new file mode 100644 index 0000000..2dd9430 --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/README.md @@ -0,0 +1,81 @@ +This patchset implements features of the lockdown LSM that we need as +lockdown is not available in LTS kernels. + +Features that are already mitigated by our kernel configuration are not +implemented. + +# lockdown-kconfig.patch: + +Creates the CONFIG_SECURITY_LOCKDOWN kconfig setting and boot parameter +to enable/disable kernel lockdown. + +# lockdown-efivar_ssdt_load.patch: + +Disables efivar_ssdt_load. + +Only useful for the host kernel. + +> efivar_ssdt_load allows the kernel to import arbitrary ACPI code from an +EFI variable, which gives arbitrary code execution in ring 0. Prevent +that when the kernel is locked down. + +# lockdown-pci-bar-access.patch: + +Locks down PCI BAR access. + +> Any hardware that can potentially generate DMA has to be locked down in +order to avoid it being possible for an attacker to modify kernel code, +allowing them to circumvent disabled module loading or module signing. +Default to paranoid - in future we can potentially relax this for +sufficiently IOMMU-isolated devices. + +# lockdown-perf.patch: + +Locks down perf. + +The official lockdown patchset only locks down REGS_INTR but this patch +disables perf_event_open entirely to further reduce attack surface. + +This will be dropped if perf_event_paranoid=4 support is merged into +linux-hardened. + +> Disallow the use of certain perf facilities that might allow userspace to +access kernel data. + +# lockdown-tiocsserial.patch + +Locks down TIOCSSERIAL. + +> Lock down TIOCSSERIAL as that can be used to change the ioport and irq +settings on a serial port. This only appears to be an issue for the serial +drivers that use the core serial code. All other drivers seem to either +ignore attempts to change port/irq or give an error. + +# lockdown-ioport.patch: + +Locks down IO port access (specifically, the ioperm() and iopl() syscalls). + +> IO port access would permit users to gain access to PCI configuration +registers, which in turn (on a lot of hardware) give access to MMIO +register space. This would potentially permit root to trigger arbitrary +DMA, so lock it down by default. +> +> This also implicitly locks down the KDADDIO, KDDELIO, KDENABIO and +KDDISABIO console ioctls. + +# lockdown-pcmcia.patch: + +Locks down PCMCIA. + +Only useful for the host kernel. + +> Prohibit replacement of the PCMCIA Card Information Structure when the +kernel is locked down. + +# lockdown-module-params.patch: + +Locks down module parameters. + +> Provided an annotation for module parameters that specify hardware +parameters (such as io ports, iomem addresses, irqs, dma channels, fixed +dma buffers and other types). diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-efivar_ssdt_load.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-efivar_ssdt_load.patch new file mode 100644 index 0000000..507aab2 --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-efivar_ssdt_load.patch @@ -0,0 +1,22 @@ +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index d54fca9..94b0781 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + +@@ -241,6 +242,9 @@ static void generic_ops_unregister(void) + static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; + static int __init efivar_ssdt_setup(char *str) + { ++ if (kernel_lockdown) ++ return -EPERM; ++ + if (strlen(str) < sizeof(efivar_ssdt)) + memcpy(efivar_ssdt, str, strlen(str)); + else diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-ioport.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-ioport.patch new file mode 100644 index 0000000..63320cf --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-ioport.patch @@ -0,0 +1,32 @@ +diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c +index 0fe1c87..e6a02e7 100644 +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,7 +32,8 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) + + if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) + return -EINVAL; +- if (turn_on && !capable(CAP_SYS_RAWIO)) ++ if (turn_on && (!capable(CAP_SYS_RAWIO) || ++ kernel_lockdown)) + return -EPERM; + + /* +@@ -126,7 +128,8 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) + return -EINVAL; + /* Trying to gain more privileges? */ + if (level > old) { +- if (!capable(CAP_SYS_RAWIO)) ++ if (!capable(CAP_SYS_RAWIO) || ++ kernel_lockdown) + return -EPERM; + } + regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-kconfig.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-kconfig.patch new file mode 100644 index 0000000..efed58a --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-kconfig.patch @@ -0,0 +1,86 @@ +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index 9ae9f28..6f31664 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -2186,6 +2186,12 @@ + lockd.nlm_udpport=M [NFS] Assign UDP port. + Format: + ++ lockdown= [SECURITY] ++ { on | off } ++ Enable the kernel lockdown feature. If set to on, ++ kernel lockdown will be enabled and features that ++ allow userspace to modify the kernel will be disabled. ++ + locktorture.nreaders_stress= [KNL] + Set the number of locking read-acquisition kthreads. + Defaults to being automatically set based on the +diff --git a/include/linux/security.h b/include/linux/security.h +index 75f4156..1a69db0 100644 +--- a/include/linux/security.h ++++ b/include/linux/security.h +@@ -66,6 +66,9 @@ struct audit_krule; + struct user_namespace; + struct timezone; + ++/* Kernel lockdown */ ++extern int kernel_lockdown; ++ + enum lsm_event { + LSM_POLICY_CHANGE, + }; +diff --git a/security/Kconfig b/security/Kconfig +index a921713..92b4f43 100644 +--- a/security/Kconfig ++++ b/security/Kconfig +@@ -281,6 +281,13 @@ config STATIC_USERMODEHELPER_PATH + If you wish for all usermode helper programs to be disabled, + specify an empty string here (i.e. ""). + ++config SECURITY_LOCKDOWN ++ bool "Enable kernel lockdown" ++ default y ++ help ++ Enables kernel lockdown which disables any feature that ++ userspace can abuse to compromise the kernel. ++ + source security/selinux/Kconfig + source security/smack/Kconfig + source security/tomoyo/Kconfig +diff --git a/security/Makefile b/security/Makefile +index 4d2d378..4b183ad 100644 +--- a/security/Makefile ++++ b/security/Makefile +@@ -30,3 +30,6 @@ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o + # Object integrity file lists + subdir-$(CONFIG_INTEGRITY) += integrity + obj-$(CONFIG_INTEGRITY) += integrity/ ++ ++# Kernel lockdown ++obj-y += lockdown.o +diff --git a/security/lockdown.c b/security/lockdown.c +new file mode 100644 +index 0000000..f9291b3 +--- /dev/null ++++ b/security/lockdown.c +@@ -0,0 +1,20 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++ ++int kernel_lockdown __ro_after_init = IS_ENABLED(CONFIG_SECURITY_LOCKDOWN); ++ ++static int __init enable_lockdown(char *level) ++{ ++ if (!level) ++ return -EINVAL; ++ ++ if (strcmp(level, "on") == 0) ++ kernel_lockdown = 1; ++ else if (strcmp(level, "off") == 0) ++ kernel_lockdown = 0; ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++early_param("lockdown", enable_lockdown); diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-module-params.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-module-params.patch new file mode 100644 index 0000000..5cf173b --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-module-params.patch @@ -0,0 +1,59 @@ +diff --git a/kernel/params.c b/kernel/params.c +index ce89f75..98221b8 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_SYSFS + /* Protects all built-in parameters, modules use their own param_lock */ +@@ -108,13 +109,19 @@ bool parameq(const char *a, const char *b) + return parameqn(a, b, strlen(a)+1); + } + +-static void param_check_unsafe(const struct kernel_param *kp) ++static bool param_check_unsafe(const struct kernel_param *kp) + { ++ if (kp->flags & KERNEL_PARAM_FL_HWPARAM && ++ kernel_lockdown) ++ return false; ++ + if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { + pr_notice("Setting dangerous option %s - tainting kernel\n", + kp->name); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } ++ ++ return true; + } + + static int parse_one(char *param, +@@ -144,8 +151,10 @@ static int parse_one(char *param, + pr_debug("handling %s with %p\n", param, + params[i].ops->set); + kernel_param_lock(params[i].mod); +- param_check_unsafe(¶ms[i]); +- err = params[i].ops->set(val, ¶ms[i]); ++ if (param_check_unsafe(¶ms[i])) ++ err = params[i].ops->set(val, ¶ms[i]); ++ else ++ err = -EPERM; + kernel_param_unlock(params[i].mod); + return err; + } +@@ -565,8 +574,10 @@ static ssize_t param_attr_store(struct module_attribute *mattr, + return -EPERM; + + kernel_param_lock(mk->mod); +- param_check_unsafe(attribute->param); +- err = attribute->param->ops->set(buf, attribute->param); ++ if (param_check_unsafe(attribute->param)) ++ err = attribute->param->ops->set(buf, attribute->param); ++ else ++ err = -EPERM; + kernel_param_unlock(mk->mod); + if (!err) + return len; diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-pci-bar-access.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-pci-bar-access.patch new file mode 100644 index 0000000..1f79625 --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-pci-bar-access.patch @@ -0,0 +1,98 @@ +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 1edf5a1..a529f6b 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -905,6 +905,9 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj, + loff_t init_off = off; + u8 *data = (u8 *) buf; + ++ if (kernel_lockdown) ++ return -EPERM; ++ + if (off > dev->cfg_size) + return 0; + if (off + count > dev->cfg_size) { +@@ -1167,6 +1170,9 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, + enum pci_mmap_state mmap_type; + struct resource *res = &pdev->resource[bar]; + ++ if (kernel_lockdown) ++ return -EPERM; ++ + if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) + return -EINVAL; + +@@ -1242,6 +1248,9 @@ static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) + { ++ if (kernel_lockdown) ++ return -EPERM; ++ + return pci_resource_io(filp, kobj, attr, buf, off, count, true); + } + +diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c +index 7ac035a..972702c 100644 +--- a/drivers/pci/proc.c ++++ b/drivers/pci/proc.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include "pci.h" + +@@ -117,6 +118,9 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, + int size = dev->cfg_size; + int cnt; + ++ if (kernel_lockdown) ++ return -EPERM; ++ + if (pos >= size) + return 0; + if (nbytes >= size) +@@ -196,6 +200,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, + #endif /* HAVE_PCI_MMAP */ + int ret = 0; + ++ if (kernel_lockdown) ++ return -EPERM; ++ + switch (cmd) { + case PCIIOC_CONTROLLER: + ret = pci_domain_nr(dev->bus); +@@ -237,7 +244,8 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) + struct pci_filp_private *fpriv = file->private_data; + int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM; + +- if (!capable(CAP_SYS_RAWIO)) ++ if (!capable(CAP_SYS_RAWIO) || ++ kernel_lockdown) + return -EPERM; + + if (fpriv->mmap_state == pci_mmap_io) { +diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c +index d96626c..f793681 100644 +--- a/drivers/pci/syscall.c ++++ b/drivers/pci/syscall.c +@@ -7,6 +7,7 @@ + + #include + #include ++#include + #include + #include + #include "pci.h" +@@ -90,7 +91,8 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, + u32 dword; + int err = 0; + +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_SYS_ADMIN) || ++ kernel_lockdown) + return -EPERM; + + dev = pci_get_domain_bus_and_slot(0, bus, dfn); diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-pcmcia.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-pcmcia.patch new file mode 100644 index 0000000..81198bb --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-pcmcia.patch @@ -0,0 +1,22 @@ +diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c +index ac0672b..7c89c51 100644 +--- a/drivers/pcmcia/cistpl.c ++++ b/drivers/pcmcia/cistpl.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1578,6 +1579,9 @@ static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj, + struct pcmcia_socket *s; + int error; + ++ if (kernel_lockdown) ++ return -EPERM; ++ + s = to_socket(container_of(kobj, struct device, kobj)); + + if (off) diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-perf.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-perf.patch new file mode 100644 index 0000000..b1e175e --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-perf.patch @@ -0,0 +1,14 @@ +diff --git a/kernel/events/core.c b/kernel/events/core.c +index 460d5fd..73cc6ee 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -10507,6 +10507,9 @@ SYSCALL_DEFINE5(perf_event_open, + return -EINVAL; + } + ++ if (kernel_lockdown) ++ return -EPERM; ++ + /* Only privileged users can get physical addresses */ + if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR) && + perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) diff --git a/usr/share/hardened-kernel/patches/lockdown/lockdown-tiocsserial.patch b/usr/share/hardened-kernel/patches/lockdown/lockdown-tiocsserial.patch new file mode 100644 index 0000000..17b42ea --- /dev/null +++ b/usr/share/hardened-kernel/patches/lockdown/lockdown-tiocsserial.patch @@ -0,0 +1,22 @@ +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index dc56cdd..3e96b14 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -866,6 +867,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, + goto check_and_exit; + } + ++ if (kernel_lockdown && (change_irq || change_port)) ++ goto exit; ++ + /* + * Ask the low level driver to verify the settings. + */