How To Secure the Linux Kernel
How To Secure the Linux Kernel
With the support of the open-source community behind it and a strict privilege system embedded in its architecture, Linux has security built into its design. That being said, gone are the days that Linux system administrators could get away with subpar security practices. Cyber criminals have come to view Linux as a viable attack target due to its growing popularity, the valuable devices it powers worldwide, and an array of dangerous new Linux malware variants that have emerged in recent years.
It has become apparent that the majority of attacks on Linux systems can be attributed to misconfigurations and poor administration - and failure to properly secure the Linux kernel is often at least partially to blame. Kernel security is a key determinant of overall system security, as the Linux kernel is the foundation of the Linux OS and the core interface between a computer’s hardware and its processes.
Luckily, the Linux kernel possesses an assortment of effective built-in security defenses - namely, firewalls that use packet filters built into the kernel, Secure Boot, Linux Kernel Lockdown and SELinux or AppArmor - that administrators should take full advantage of. This article will examine the importance of robust kernel security and explore various measures that administrators can take to secure the Linux kernel and protect their systems from malware and other exploits.
How Secure Is the Linux Kernel?
Kernel security is an ongoing concern for Linux system administrators, and securing the kernel is one of the most complex aspects of securing a Linux system. Despite the fact that the Linux kernel undergoes constant scrutiny for security bugs by the “many eyes” of the vibrant, global open-source community, kernel vulnerabilities remain a persistent and serious threat. Flaws are inevitable in any OS, and a large portion of Linux kernel bugs present potential security issues, often resulting in privilege escalation or denial-of -service (DoS) attacks. Critical kernel vulnerabilities can often be exploited by remote attackers - without requiring that any actions be taken by the victim. Some of the most notorious Linux kernel security bugs discovered and fixed in recent years include:
- CVE-2017-18017: This critical vulnerability, which resides in the netfilter tcpmss_mangle_packet function, is highly dangerous due to the central role that it plays in filtering network communications by defining the maximum segment size that is allowed for accepting TCP headers. Without these controls in place, users are susceptible to overflow issues and DoS attacks. The flaw impacts kernel versions prior to 4.11.
- CVE-2016-10229: This udp.c bug, which also affects kernel versions before 4.5, allows a remote attacker to execute arbitrary code via UDP traffic, triggering an unsafe second checksum during the execution of a recv system call with the MSG_PEEK flag.
- CVE-2016-10150: This use-after-free vulnerability, which impacts kernel versions prior to 4.8.13, could be exploited by hackers to gain privileges and launch DoS attacks.
- CVE-2015-8812: This severe vulnerability impacting kernel versions prior to 4.5, which was discovered in the drivers of the Linux kernel, enables a remote attacker to execute arbitrary code or cause a DoS (use-after-free) attack via crafted packets.
- CVE-2014-2523: This serious netfilter vulnerability, which impacts kernel versions through 3.13.6, is attributed to the incorrect use of a DCCP header pointer. The flaw allows a remote attacker to cause a DoS (system crash) attack or to execute arbitrary code via a DCCP packet that triggers a call to either the dccp_new, dccp_packet, or dccp_error function.
Tracking advisories is critical in protecting against kernel vulnerabilities and maintaining a secure, updated system. Subscribing to our weekly Linux Advisory Watch newsletter is an easy, convenient way to stay up-to-date on the latest advisories and updates issues by your Linux distribution.
What is Kernel Self-Protection and Why Is It Important?
Linux kernel-self protection, or the design and implementation of systems and structures within the Linux kernel to protect against security flaws in the kernel itself, is an excellent way of adding another layer of security to the Linux kernel. It includes defense methods such as attack surface reduction, memory integrity, probabilistic defenses and the prevention of information exposure. Let’s examine some tips and best practices for securing the Linux kernel by implementing these defense methods to protect your users, your systems and your data.
Top Tips & Advice for Securing the Linux Kernel
Apply Kernel Security Patches
The Linux kernel is patched frequently to mitigate the latest security vulnerabilities that have been discovered and, albeit monotonous, staying on top of kernel security updates is imperative to maintaining a secure Linux system. The most straightforward method of updating the Linux kernel is tracking distribution security advisories and applying the latest updates available directly from your Linux distribution. There are three other methods for updating the kernel: on the command line, with kexec, or with a rebootless live kernel patching tool. Updating the kernel from the command line is the method that is most likely to be covered in your distribution’s documentation. However, a major disadvantage of patching the kernel on the command line is that you will need to suffer the downtime of a system reboot. Administrators can quicken rebooting process by using the kexec system call. However, this method is risky, as it can cause data loss and corruption. The third method - updating the kernel automatically using a rebootless live kernel patching tool such as Livepatch, Ksplice, Kpatch, Kgraft or KernelCare - is generally administrators’ method of choice, but is not a replacement for full kernel upgrades, as it only applies patches for security vulnerabilities or critical bug fixes.
Enable Secure Boot in “Full” or “Thorough” Mode
UEFI Secure Boot is a verification mechanism for ensuring that code launched by a device's UEFI firmware is trusted. The feature is designed to prevent malicious code from being loaded and executed before the OS has been loaded. By enabling UEFI Secure Boot in “full” or “thorough” mode, administrators can decrease the attack surface on x86-64 systems. UEFI Secure Boot requires cryptographically signed firmware and kernels. Thus, no unsigned drivers can be loaded for hardware on systems with UEFI Secure Boot enabled in “full” or “thorough” mode. This makes it far more difficult for an attacker to insert a malicious kernel module into a system and for unsigned rootkits to remain persistent after reboot.
However, administrators should be aware that enabling Secure Boot comes with some potential drawbacks. For instance, it requires manual intervention any time a kernel or module is upgraded. Using Secure Boot also activates "lockdown" mode, which disables various features that can be used to modify the kernel. We will cover this in more depth in the following section.
Learn more about UEFI Secure Boot and how to install a Linux system with Secure Boot enabled in this Linux.org tutorial.
Use Linux Kernel Lockdown
Linux Kernel Lockdown is a kernel configuration option developed to provide a policy to prevent the root account from modifying the kernel code by strengthening the divide between userland processes and kernel code. Thus, in the event that a root account is compromised, having Lockdown mode enabled will make it far more difficult for the compromised account to compromise the rest of the OS. Although Lockdown was not introduced until the release of kernel version 5.4, work on this feature began over a decade ago, and was spearheaded by Google engineer Matthew Garrett.
Lockdown support can be activated with the lockdown= kernel parameter. The module has two modes: “integrity” mode and “confidentiality” mode. It is generally advised to use the “integrity” mode, and to only use the “confidentiality” mode for special systems that contain sensitive information that even root shouldn't be permitted to see, such as the EVM signing key which can be used to prevent offline file modification. Using confidentiality mode blocks access to all kernel memory, preventing administrators from being able to inspect and probe the kernel for purposes such as troubleshooting, development and testing and verifying security measures. Setting lockdown=integrity will block kernel features that allow user-space to modify the running kernel, while setting lockdown=confidentiality will block user-space from extracting sensitive information from the running kernel. Administrators have the option of permanently enforcing either the integrity or the confidentiality lockdown mode via SECURITY_LOCKDOWN_LSM_EARLY. All of these configurations are controlled through the Kconfig SECURITY_LOCKDOWN_LSM option for enabling the module.
Administrators should be aware that using Lockdown prevents various features and modules that can be used to modify the kernel from loading. For instance, Lockdown disables:
- Loading kernel modules that are not signed by a trusted key, such as out-of-tree modules including DKMS-managed drivers.
- Using kexec to start an unsigned kernel image.
- Hibernation and resume from hibernation.
- User-space access to physical memory and I/O ports.
- Module parameters used to set memory and I/O port addresses.
- Writing to MSRs through /dev/cpu/*/msr.
- The use of custom ACPI methods and tables.
- ACPI APEI error injection.
Enable Kernel Module Signing & Module Loading Rules
The Linux kernel supports digital signatures on loadable kernel modules, ensuring that only known and valid modules can be loaded and decreasing a system’s attack surface with this requirement. Kernel module signing must be enabled in the kernel with settings in CONFIG_MODULE_SIG. Administrators can configure the kernel to require valid signatures, enable automatic module signing during the kernel build phase and specify which hash algorithm to use. Local or remote keys can also be used.
In addition, limited module support can be enabled by default using the sysctl kernel.modules_disabled=1 command. Sysctl is a way for administrators to communicate directly with the kernel to control how it functions. These functions can also be configured in the /etc/sysctl.conf file. We explain how administrators can harden this file in the following section.
Disabling modules completely can drastically reduce a system’s attack surface, but is only practical in special use cases.
Harden the Sysctl.conf File
The sysctl.conf file is the main kernel parameter configuration point for a Linux system. By using secure defaults, your whole system will benefit from a more secure foundation.
With /etc/sysctl.conf you can configure various Linux network and system settings to improve security by:
- Limiting network-transmitted configuration for IPv4
- Limiting network-transmitted configuration for IPv6
- Turning on execshield protection
- Protecting against syn flood attacks
- Turning on source IP address verification
- Securing a server’s IP address against spoofing attacks
- Logging suspicious packets such as spoofed packets, source-routed packets and redirects
Learn how to harden the sysctl.conf file in this nixCraft tutorial.
Enable SELinux or AppArmor
Modern Linux systems include the Mandatory Access Control (MAC) security enhancement systems AppArmor or SELinux (depending on the distribution) installed by default to protect against threats such as server misconfigurations, software vulnerabilities and zero-day exploits - which could potentially compromise an entire system without these controls in place. SELinux is installed and enabled by default on CentOS and RedHat Enterprise Linux OSes, while AppArmor is installed and enabled by default on Ubuntu and SuSE Linux Enterprise systems. These security enhancement systems allow for granular access control with security policies, providing an additional layer of security throughout a system.
SELinux defines access controls for the applications, processes, and files on a system, using security policies to enforce these access controls. When an application or process - known as a “subject” - makes a request to access an “object” such as a file, SELinux checks with an access vector cache (AVC), where permissions are cached for subjects and objects. If SELinux is unable to make a decision about access based on the cached permissions, the request is forwarded to the security server, which checks for the security context of the subject and object from the SELinux policy database. Permission is then either granted or denied. If permission is denied, an "avc: denied" message will be available in /var/log.messages.
For typical use cases, we recommend that administrators set SELinux to permissive mode. By operating in permissive mode, policy is not enforced and the system remains operational. In other words, SELinux does not deny any operations, but only logs AVC messages, which administrators can then use for troubleshooting, debugging, and policy improvements.
Like SELinux, Apparmor isolates applications and processes from each other with per-program profiles built into the kernel, as well as any profiles that an administrator has generated. AppArmor can be set to either enforce these profiles or to complain when profile rules are violated. AppArmor is less complex than SELinux, but in turn offers less control
over how processes are isolated.
It is unfortunately quite common for administrators to disable SELinux or AppArmor when they encounter an issue as opposed to learning how to fix the issue with these services enabled. This is a poor administration and security practice, and can detract significantly from a system’s overall security posture by leaving the system susceptible to the very attacks that SELinux or AppArmor are designed to prevent.
Implement Strict Permissions
When all kernel memory is writable, it’s easy for attacks to redirect execution flow - making it imperative that kernel memory is protected with a tight set of permissions. Permissions should be as strict as is practical in a given environment.
Administrators should begin by ensuring that executive code and read-only data is not writable. The CONFIG_STRICT_KERNEL_RWX and CONFIG_STRICT_MODULE_RWX configurations, which seek to make sure that code is not writable, data is not executable, and read-only data is neither writable nor executable, are the default options for the majority of Linux architectures. In the event that these settings are user selectable, an administrator can select ARCH_OPTIONAL_KERNEL_RWX to enable a Kconfig prompt. CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT determines the default setting when ARCH_OPTIONAL_KERNEL_RWX is enabled.
It is critical that function pointers and sensitive variables, which are looked up by the kernel and used to continue execution, are read-only - not writable. Many such variables can be made read-only by setting them “const” so that they reside in the .rodata section instead of the .data section of the kernel.
Permissions should always be configured to enforce the segregation of kernel memory from userspace memory. These rules can be enforced either via hardware-based restrictions or via emulation. By blocking userspace memory, attacks are forced to operate entirely in kernel memory.
Use AuditD for Ongoing System Monitoring
Carefully monitoring the Linux kernel enables administrators to discover security bugs, breaches or policy violations, allowing them to mitigate potential damage caused by these threats and verify the security of their systems. Using the Linux Auditing System (AuditD) is a popular and effective method of monitoring the events that occur on a system. AuditD is a native feature to the Linux kernel, which is installed by default in most distributions and runs automatically, that collects information on system activity such as file permissions modifications, services being enabled or disabled and network events, to facilitate the investigation of potential security incidents. It logs information according to its \rules as well as any custom rules that an administrator has added. The kernel is uniquely suited to perform these functions because only the kernel has direct access to all of a system’s devices and memory.
Here’s an example of the type of information provided by the AuditD audit daemon. It shows users running specific commands like /usr/bin/sudo and ssh generating a new session key
type=USER_CMD msg=audit(1611763205.568:1621017): pid=1829220 uid=991 auid=4294967295 ses=4294967295 msg='cwd="/" cmd=2F7573722F6C6962363 exe="/usr/bin/sudo" terminal=? res=success'UID="nrpe" AUID="unset"
type=CRYPTO_KEY_USER msg=audit(1611762843.231:1620894): pid=1825289 uid=0 auid=0 ses=49526 msg='op=destroy kind=server fp=SHA256:d7:c2:5a7 direction=? spid=1825289 suid=0 exe="/usr/sbin/sshd" hostname=? addr=? terminal=? res=success' UID="root" AUID="root" SUID="root"
Here’s an example of “aureport” being used to generate a summary report of events that have occurred on the system.
[root@myhost ~]# aureport
Range of time in logs: 01/23/2021 04:54:03.379 - 01/27/2021 11:36:05.388
Selected time for report: 01/23/2021 04:54:03 - 01/27/2021 11:36:05.388
Number of changes in configuration: 67
Number of changes to accounts, groups, or roles: 0
Number of logins: 1457
Number of failed logins: 6249
Number of authentications: 1461
Number of failed authentications: 178
Number of users: 4
Number of terminals: 7
Number of host names: 661
Number of executables: 7
Number of commands: 1
Number of files: 0
Number of AVC's: 0
Number of MAC events: 65
Number of failed syscalls: 0
Number of anomaly events: 0
Number of responses to anomaly events: 0
Number of crypto events: 45395
Number of integrity events: 0
Number of virt events: 0
Number of keys: 0
Number of process IDs: 25064
Number of events: 136817
[root@myhost ~]# aureport -x --summary
Executable Summary Report
In order to ensure optimal security and effectiveness, AuditD must be properly configured and hardened. Administrators should check that AuditD’s configuration is immutable using the control option “-e 2” and confirm that logs are stored in a centralized, secure location - ideally a server dedicated to accepting remote syslog events.
AuditD does have some weaknesses that should be considered - namely, bugginess, excessive overhead, lack of granularity, missing container support and onerous output;
Learn how to install and configure AuditD, create rules and view the AuditD log in this TechRepublic tutorial.
Linux is becoming an increasingly attractive target among cyber criminals due to its growing popularity and the high-value devices it powers worldwide. Effective security is contingent upon defense in depth, and kernel security is a key element of overall system security that cannot be overlooked. After all, the kernel is the foundation of a system, and if the kernel is not secure, then nothing on the system is secure. Thus, it is of critical importance that Linux system administrators prioritize kernel security and remain vigilant about implementing the tips and best practices discussed in this article to protect against security vulnerabilities and prevent exploits.
Do you have questions about securing the Linux kernel or want to discuss the topic in more depth? Let’s chat!
Connect with us on social media: