Security researchers from Qualys have disclosed details of two vulnerabilities affecting the Linux kernel and the system manager systemd. The kernel vulnerability (CVE-2021-33909) allows a local user to execute code with root privileges through manipulation of deeply nested directories.
The risk of the vulnerability is heightened by the fact that researchers have managed to prepare working exploits that function in Ubuntu 20.04/20.10/21.04, Debian 11, and Fedora 34 in default configurations. It is noted that other distributions have not been tested but could theoretically also be affected and attacked. The full exploit code is promised to be published after the issue is widely addressed, meanwhile, only a limited-functionality prototype is available that causes system crashes. The issue has been present since July 2014 and affects kernel releases starting from 3.16. The vulnerability fix was coordinated with the community and incorporated into the kernel on July 19. Major distributions have already formed package updates with the kernel (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch).
The vulnerability is caused by the lack of checking the result of the conversion of size_t to int before performing operations in the seq_file code, which generates files from a sequence of records. The lack of checking can lead to writing outside the buffer's boundaries when creating, mounting, and deleting directory structures with a very large depth (path size greater than 1 GB). As a result, an attacker can achieve writing a 10-byte string "//deleted" with an offset of "- 2 GB - 10 bytes" pointing to the area immediately preceding the allocated buffer.
The prepared exploit requires 5 GB of memory and 1 million free inodes to operate. The exploit works by creating a hierarchy of about a million nested directories via the mkdir() call to reach a file path size exceeding 1 GB. This directory is mounted via bind-mount in a separate user namespace, after which the rmdir() function is invoked to delete it. Simultaneously, a thread is created that loads a small eBPF program, which gets blocked after checking the eBPF pseudocode, but before its JIT compilation.
In the non-privileged user ID namespace, the file /proc/self/mountinfo is opened and a long path of the directory mounted via bind-mount is read, leading to the writing of the string "//deleted" in an area before the beginning of the buffer. The position for writing the string is chosen so that it overwrites an instruction in an already verified but not yet compiled eBPF program.
Then, at the eBPF program level, uncontrolled writes outside the buffer are transformed into a managed ability to read from and write to other kernel structures through manipulation with btf and map_push_elem structures. As a result, the exploit identifies the location of the buffer modprobe_path[] in kernel memory and overwrites it with the path "/sbin/modprobe", allowing the execution of any executable file with root privileges when the request_module() call is made, which is executed, for example, upon creating a netlink socket.
Researchers present several circumvention methods for the protection mechanisms that are effective only for specific exploits but do not eliminate the underlying issue. It is recommended to set the parameter "/proc/sys/kernel/unprivileged_userns_clone" to 0 to prevent the mounting of directories in a separate user ID namespace, as well as "/proc/sys/kernel/unprivileged_bpf_disabled" to 1 to disallow loading eBPF programs into the kernel.
Notably, while analyzing an alternative attack vector involving the use of the FUSE mechanism instead of bind-mount for mounting a large directory, researchers encountered another vulnerability (CVE-2021-33910) affecting the system manager systemd. It turned out that attempting to mount a directory with a path size exceeding 8 MB through FUSE causes stack memory exhaustion and a crash in the initialization control process (PID1), which puts the system into a "panic" state.
The issue arises because systemd monitors and parses the contents of /proc/self/mountinfo, processing each mount point in the unit_name_path_escape() function, which performs the strdupa() operation, allocating data on the stack rather than on dynamically allocated memory. Since the maximum stack size is limited by RLIMIT_STACK, handling a very large mount point path leads to a crash of the PID1 process, halting system operation. An attack can utilize a simple FUSE module combined with mounting a directory with a deep nesting level, where the path size exceeds 8 MB.
The problem manifests starting with systemd 220 (April 2015), has already been resolved in the main systemd repository, and fixed in distributions (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch). Notably, in the release of systemd 248, the exploit does not work due to a bug in the systemd code that causes a crash when processing /proc/self/mountinfo. Interestingly, in 2018 a similar situation arose, and when trying to write an exploit for the vulnerability CVE-2018-14634 in the Linux kernel, Qualys researchers stumbled upon three critical vulnerabilities in systemd.
Source: opennet.ru
