The Qualys Research Team has discovered a size_t-to-int type conversion vulnerability in the Linux Kernel’s filesystem layer affecting most Linux operating systems. Any unprivileged user can gain root privileges on a vulnerable host by exploiting this vulnerability in a default configuration.
A file system is an organization of data and metadata on a storage device. It controls how the data is stored and retrieved, and its most important function is to manage user data. The Linux file system interface is implemented as a layered architecture, separating the user interface layer from the file system implementation and from the drivers that manipulate the storage devices. It is the most important function of any operating system and is ubiquitous on all major Linux operating systems.
Successful exploitation of this vulnerability allows any unprivileged user to gain root privileges on the vulnerable host. Qualys security researchers have been able to independently verify the vulnerability, develop an exploit, and obtain full root privileges on default installations of Ubuntu 20.04, Ubuntu 20.10, Ubuntu 21.04, Debian 11, and Fedora 34 Workstation. Other Linux distributions are likely vulnerable and probably exploitable.
As soon as the Qualys research team confirmed the vulnerability, Qualys engaged in responsible vulnerability disclosure and coordinated with vendor and open-source distributions to announce the vulnerability.
The Linux kernel's seq_file interface produces virtual files that contain sequences of records (for example, many files in /proc are seq_files, and records are usually lines). Each record must fit into a seq_file buffer, which is therefore enlarged as needed, by doubling its size at line 242 (seq_buf_alloc() is a simple wrapper around kvmalloc()):
------------------------------------------------------------------------
168 ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
169 {
170 struct seq_file _m = iocb->ki_filp->private_data; _
_… _
_205 /_ grab buffer if we didn't have one */
206 if (!m->buf) {
207 m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
…
210 }
…
220 // get a non-empty record in the buffer
…
223 while (1) {
…
227 err = m->op->show(m, p);
…
236 if (!seq_has_overflowed(m)) // got it
237 goto Fill;
238 // need a bigger buffer
…
240 kvfree(m->buf);
…
242 m->buf = seq_buf_alloc(m->size <<= 1);
…
246 }
------------------------------------------------------------------------
This size multiplication is not a vulnerability in itself, because m->size is a size_t (an unsigned 64-bit integer, on x86_64), and the system would run out of memory long before this multiplication overflows the integer m->size. Unfortunately, this size_t is also passed to functions whose size argument is an int (a signed 32-bit integer), not a size_t. For example, the show_mountinfo() function (which is called at line 227 to format the records in /proc/self/mountinfo) calls seq_dentry() (at line 150), which calls dentry_path() (at line 530), which calls prepend() (at line 387):
------------------------------------------------------------------------
135 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
136 {
…
150 seq_dentry(m, mnt->mnt_root, " \t\n\");
------------------------------------------------------------------------
523 int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
524 {
525 char *buf;
526 size_t size = seq_get_buf(m, &buf);
…
529 if (size) {
530 char *p = dentry_path(dentry, buf, size);
------------------------------------------------------------------------
380 char *dentry_path(struct dentry *dentry, char *buf, int buflen)
381 {
382 char *p = NULL;
…
385 if (d_unlinked(dentry)) {
386 p = buf + buflen;
387 if (prepend(&p, &buflen, "//deleted", 10) != 0)
------------------------------------------------------------------------
11 static int prepend(char **buffer, int *buflen, const char *str, int namelen)
12 {
13 *buflen -= namelen;
14 if (*buflen < 0)
15 return -ENAMETOOLONG;
16 *buffer -= namelen;
17 memcpy(*buffer, str, namelen);
------------------------------------------------------------------------
As a result, if an unprivileged local attacker creates, mounts, and deletes a deep directory structure whose total path length exceeds 1GB, and if the attacker open()s and read()s /proc/self/mountinfo, then:
Given the breadth of the attack surface for this vulnerability, Qualys recommends users apply patches for this vulnerability immediately.
Qualys customers can search the vulnerability knowledgebase for CVE-2021-33909 to identify all the QIDs and assets vulnerable for this vulnerability.
If you are not a customer, start your free Qualys VMDR trial to get full access to the QIDs (detections) for CVE-2021-33909, so you can identify your vulnerable assets.
Qualys is releasing the QIDs in the table below as they become available starting with vulnsigs version VULNSIGS-2.5.237-3 and in Linux Cloud Agent manifest version lx_manifest-2.5.237.3-2
QID | Title | VulnSigs Version |
---|---|---|
750847 | OpenSUSE Security Update for the Linux Kernel (openSUSE-SU-2021:2409-1) | VULNSIGS-2.5.237-3 / lx_manifest-2.5.237.3-2 |
750844 | SUSE Enterprise Linux Security Update for kernel (SUSE-SU-2021:2407-1) | VULNSIGS-2.5.237-3 / lx_manifest-2.5.237.3-2 |
178710 | Debian Security Update for linux (DSA 4941-1) | VULNSIGS-2.5.237-3 / lx_manifest-2.5.237.3-2 |
375710 | Linux Kernel Local Privilege Escalation Vulnerability (Sequoia) | VULNSIGS-2.5.237-3 / lx_manifest-2.5.237.3-2 |
The first step in managing these critical vulnerabilities and reducing risk is identification of assets running Linux OS. Qualys VMDR makes it easy to identify such assets.
Query: operatingSystem.category1:Linux
Once the hosts are identified, they can be grouped together with a ‘dynamic tag’, let’s say – “Linux Servers”. This helps in automatically grouping existing hosts with the above vulnerabilities as well as any new Linux assets that spin up in your environment. Tagging makes these grouped assets available for querying, reporting and management throughout the Qualys Cloud Platform.
Using Qualys VMDR, the vulnerabilities can be prioritized using the following real-time threat indicators (RTIs):
Predicted_High_Risk
Privilege_Escalation
Easy_Exploit
High_Lateral_Movement
VMDR also enables you to automatically map assets vulnerable to these vulnerabilities using Threat Protection.
With VMDR Unified Dashboard, you can track this vulnerability, their impacted hosts, their status and overall management in real time. With trending enabled for dashboard widgets, you can keep track of these vulnerabilities trends in your environment using the “Sequoia” Dashboard.
View and download the "Sequoia" dashboard:
<https://www.qualys.com/2021/07/20/cve-2021-33909/sequoia-local-privilege-escalation-linux.txt>
All Linux kernel versions from 2014 onwards are vulnerable.
A PoC is attached with the advisory and available at <https://www.qualys.com/research/security-advisories/>.
The following mitigations prevent only our specific exploit from working (but other exploitation techniques may exist); to completely fix this vulnerability, the kernel must be patched.
The bug is in Linux's seq_file interface, and "Sequoia sempervirens" is a tree that has wide-spreading roots: a pun on the bug's deep directory tree that yields root privileges.