Linux (In)security: a review
fpoi.orgNote: this review is based on 14th June 2021 version of the original document.
The article is very interesting. After reading it, I performed a thorough analysis of the issues and found several inconsistencies and some errors that, in my opinion, should be fixed.
Below are the highlights with my comments.
Linux still follows this security model and as such, there is no resemblance of a strong sandboxing architecture or permission model in the standard Linux desktop — current sandboxing solutions are either nonexistent or insufficient. All applications have access to each other’s data and can snoop on your personal information.
Sandboxing. The article mentions only SElinux mainly used by Red Hat/Fedora and Android, but leaves out AppArmor (both are in the kernel mainline), developed/supported by Canonical since 2009 and default Ubuntu 8.04+ (default Debian 10+). SElinux turns out to be old as a method....
Also, the Linux kernel offers several sandboxing mechanisms in addition to the above:
a) seccomp used by systemd (Red Hat/Debian), Android, Flatpak and Firejail (mentioned in the article), Chromium, Firefox, etc.
b) cgroups used by systemd, Docker, lxc, Kubernetes and others.
c) namespaces used by Docker, lxc, Chromium and others.
So it doesn't seem to me to be a problem of the operating system/kernel, but of the applications. Developers are responsible for using the protections offered by the operating system/kernel when releasing their applications. An average user is not able to configure for example systemd by himself, but a system administrator can. The problem remains on the client side.
There is no centralized catalog/stores (fortunately) for all GNU/Linux distributions and so the comparison with "centralized operating systems" as Windows, macOS, Android, iOS is difficult/useless.
Flatpak aims to sandbox applications, but its sandboxing is very flawed. Firejail is another common sandboxing technology however, it is also insufficient.
In addition, there are also snap (closed source, centralized server, not much different from the stores above) and AppImage (a kind of universal executable). In particular, snap provides sandboxing capabilities by default with AppArmor, seccomp and cgroups.
Maybe the author could have at least mentioned it....
Another example of Flatpak's broad permissions is how it allows unfiltered access to the X11 socket, permitting easy sandbox escapes due to X11's lack of GUI isolation.
By now X11 is considered deprecated (1984-2012, in 2012 the last revision). Wayland solves its security/performance issues and now all major distributions (Debian, Ubuntu, Fedora, Red Hat, Manjaro) use it as default.
Most programs on Linux are written in memory unsafe languages, such as C or C++, which causes the majority of discovered security vulnerabilities. Other operating systems have made more progress on adopting memory safe languages, such as Windows which is leaning heavily towards Rust, a memory safe language or macOS which is adopting Swift.
Rust is the heir to C/C++ as performance with the added property of being memory safe. Swift has too much overhead and is closer to Java/Go as performance (no one would ever write a kernel/operating system, but also high performance applications with such languages...oops android (UI) and iOS (apps) :) ). Rust is coming into the Linux kernel, mostly thanks to google.
I agree, in this aspect Linux kernel is slightly behind the competition, but the way is traced.
Furthermore, modern exploit mitigations, such as Control Flow Integrity (CFI), are also not widely used on Linux. On Linux, CFI is practically nonexistent outside of Chromium...
The GCC and Clang/LLVM compilers support CFI. LLVM offers better support and less performance degradation. Android supports it since version 9 with Linux kernels 4.9 and 4.14. GNU/linux supports it with Linux kernel 5.13+ (Arm 64 bit) and Linux kenel 5.16+ (x86/x86_64) (Chromium).
In this aspect, the Linux kernel is lagging slightly behind.
Attackers often inject their shellcode into writable memory pages and then use these code reuse techniques to transition memory pages to executable (using syscalls such as mprotect or VirtualAlloc), consequently allowing it to be executed. Linux has yet to provide strong mitigations against this avenue of attacks.
Kernel Self-Protection protects memory, Integrity Measurement Architecture protects the filesystem, KASLR protects the boot phase and LKRG performs runtime integrity check and detection of security vulnerability exploits against the kernel (mentioned in another article by the author). GCC and Clang/LLVM provide buffer overflow protection mechanisms.
Windows ACG protection has been broken.
One of the most common classes of memory corruption vulnerabilities is uninitialized memory.
KASAN and KMSAN allow to find memory initialization errors in Linux kernel. GCC 12 should gain an option for automatic initialization of auto variables. On LLVM there is an open bug.
The main problem with auto initialization of stack variables is the choice of values. Much better to perform a static and memory analysis instead of choosing a (random) default value. Clang/LLVM provides StaticAnalyzer and MemorySanitizer. GCC provides StaticAnalyzer and MemorySanitizer (-fsanitize). In addition, there is also Valgrind project for memory analysis.
Windows supports Virtualization-based Security (VBS) which allows it to run the entire operating system inside of a virtual machine and is used to enforce a number of security guarantees.
LKRG provides some VBS functionality. CONFIG_STRICT_KERNEL_RWX and CONFIG_STRICT_MODULE_RWX allow protection of executable code, data, and read-only data.
I agree, Windows VBS protection is superior and the Linux kernel is behind on this point.
The Linux kernel itself is also extremely lacking in security. It is a monolithic kernel which means that it contains a colossal amount of code all within the most privileged part of the operating system and has no isolation between internal components whatsoever.
Linux is basically monolithic, but also layered and modular (LKM). However, being basic monolithic, the observation is correct. The loss in security due to the absence of component separation is compensated by the better performance.
The Linux kernel's size grows exponentially across each release...
Not true, I would say linear in the period 2004-2018, after that even less pending. Also, by measuring with cloc the Linux kernel repository (5.11), it possible to find that over 60% of the code is composed of drivers and the actual kernel is composed of "only" 150k LOC (~1-1.5%) while arch, kernel and mm (~14%). A dated, but interesting considerations.
and it can be thought of as equivalent to running all user space code as root in PID 1, if not even more dangerous.
Not true. In addition, the Linux kernel also supports lockdown.
One example of such dangerous features is eBPF. In a nutshell, eBPF is a very powerful framework within the Linux kernel that allows unprivileged user space to execute arbitrary code within the kernel in order to dynamically extend kernel functionality.
The eBPF project offers great possibilities, that's why there is also a porting for Windows by Microsoft. According to Mitre and NIST databases there are 4 serious bugs related to eBPF, we need to consider that it arrived in Linux kernel version 3.18 (2014), then subsequent enhancements with 3.19, 4.1 and 5.3 (2019).
I agree that the attack surface is high, but I don't see many alternatives at the moment (some mitigations proposed by the author of the article).
Another example of these features is user namespaces. User namespaces allow unprivileged users to interact with lots of kernel code that is normally reserved for the root user.
I agree on this.
The kernel is written entirely in a memory unsafe language and has hundreds of bugs, many being security vulnerabilities, discovered each month. In fact, there are so many bugs being found in the kernel, developers can’t keep up which results in many of the bugs staying unfixed for a long time. The kernel is decades behind in exploit mitigations and many kernel developers simply do not care enough.
As written also above, it is true that the Linux kernel should move towards memory safe languages like Rust. However, fixing vulnerabilities also depends a lot on the scarce workforce, also poorly distributed, as written by the article Linux Kernel Security Done Right (in my opinion, this is the most important problem to focus on, remember the scarcity of resources of the openSSL project in the heartbleed bug).
Other kernels, such as the Windows and macOS kernels, are somewhat similar too, in that they are also large and bloated monolithic kernels with huge attack surface, but they at least realise that these issues exist and take further steps to mitigate them.
Incorrect. NT and XNU kernels are hybrids, initially micro kernels then mostly monolithic, but also layered.
On ordinary Linux desktops, a compromised non-root user account with access to sudo is equal to full root compromise as there are an abundance of ways for an attacker to retrieve the sudo password.
The author forgot a word "is almost equal" during the copy-paste. Also, an account in the sudo group has practically unlimited as an administrator account on Windows. I don't see how it is possible to deal with such threats.
For example, the attacker can exploit the plethora of keylogging opportunities, such as Xorg’s lack of GUI isolation, the many infoleaks in the procfs filesystem, using LD_PRELOAD to hook into processes and so much more. Even if one were to mitigate every single way to log keystrokes, the attacker can simply setup their own fake sudo prompt by manipulating $PATH or shell aliases/functions to intercept the user's password, completely unbeknownst to the user.
By now X11 is deprecated in favor of wayland as written above. Most of the reported attacks are related to older versions of android <=8 (Linux kernel <=3.18, 4.4) or older versions of Linux kernel <= 3.11. The attacks are almost all side channel attacks and require getting access to the device or being able to install malware. Access to /proc/ has been reduced with the various versions of android (9, 10). The attack on wayland dates back to 2014, relies on the absence of sandboxing and is also feasible on other operating systems as indicated by the author.
While similar attacks are still possible on other operating systems due to the inherent issues in escalating privileges from an untrusted account, they are often much harder to pull off than on Linux.
Linux kernel provides LSM via KRSI. In addition, LD_PRELOAD attacks can be mitigated/eliminated in quite simple way. As described by the author the threat model assumes a compromised account and the ability to modify the LD_PRELOAD variable.
A myriad of common Linux distributions, including Debian, Ubuntu, RHEL/CentOS, among numerous others use what's known as a "stable" software release model. This involves freezing packages for a very long time and only ever backporting security fixes that have received a CVE. However, this approach misses the vast majority of security fixes. Most security fixes do not receive CVEs because either the developer simply doesn’t care or because it’s not obvious whether or not a bug is exploitable at first.
I agree, this is the biggest problem as mentioned by the article Linux Kernel Security Done Right.
Manual Hardening...
The above analysis shows that it is possible to fix most of the problems through the use of sandboxing mechanisms, wayland, memory safe languages and the implementation of protection mechanisms built into the Linux kernel.
Overall, excluding two points (Rust and VBS), I don't see any inferiority of the Linux kernel compared to other windows NT or XNU kernels as stated by the author. In my opinion, what is urgently needed is an increase in the workforce as described by the article Linux Kernel Security Done Right.