Qualys Inc.

07/20/2021 | News release | Distributed by Public on 07/20/2021 07:11

Sequoia: A Local Privilege Escalation Vulnerability in Linux’s Filesystem Layer (CVE-2021-33909)

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.

About Linux Filesystem

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.

Impact

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.

Disclosure Timeline

  • 2021-06-09: The Qualys Research Team (QRT) sent advisories for CVE-2021-33909 and CVE-2021-33910 to Red Hat Product Security (the two vulnerabilities are closely related, and the systemd-security mailing list is hosted by Red Hat).
  • 2021-07-06: QRT sent advisories, and Red Hat sent the patches they wrote, to the [email protected] mailing list.
  • 2021-07-13: QRT sent advisory for CVE-2021-33909, and Red Hat sent the patch they wrote, to the [email protected] mailing list.
  • 2021-07-20: Coordinated Release Date (12:00 PM UTC).

Proof of Concept Video

Technical Details

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:

  • in seq_read_iter(), a 2GB buffer is vmalloc()ated (line 242), and show_mountinfo() is called (line 227);
  • in show_mountinfo(), seq_dentry() is called with the empty 2GB buffer (line 150);
  • in seq_dentry(), dentry_path() is called with a 2GB size (line 530);
  • in dentry_path(), the int buflen is therefore negative (INT_MIN, -2GB), p points to an offset of -2GB below the vmalloc()ated buffer (line 386), and prepend() is called (line 387);
  • in prepend(), *buflen is decreased by 10 bytes and becomes a large but positive int (line 13), *buffer is decreased by 10 bytes and points to an offset of -2GB-10B below the vmalloc()ated buffer (line 16), and the 10-byte string '//deleted' is written out of bounds (line 17).

Solution

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 Coverage

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
375710 Linux Kernel Local Privilege Escalation Vulnerability (Sequoia) VULNSIGS-2.5.237-3 / lx_manifest-2.5.237.3-2

Discover Vulnerable Linux Servers Using Qualys VMDR

Identify Assets Running Linux Kernel

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.

Prioritize Based on RTIs

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

Detect Impacted Assets with Threat Protection

VMDR also enables you to automatically map assets vulnerable to these vulnerabilities using Threat Protection.

Dashboard

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:

Vendor References

https://www.qualys.com/2021/07/20/cve-2021-33909/sequoia-local-privilege-escalation-linux.txt

Frequently Asked Questions (FAQs)

What versions are vulnerable?

All Linux kernel versions from 2014 onwards are vulnerable.

Will the Qualys Research Team publish exploit code for this vulnerability?

A PoC is attached with the advisory and available at https://www.qualys.com/research/security-advisories/.

Are there any mitigations for this vulnerability?

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.

  • Set /proc/sys/kernel/unprivileged_userns_clone to 0, to prevent an attacker from mounting a long directory in a user namespace. However, the attacker may mount a long directory via FUSE instead; we have not fully explored this possibility, because we accidentally stumbled upon CVE-2021-33910 in systemd: if an attacker FUSE-mounts a long directory (longer than 8MB), then systemd exhausts its stack, crashes, and therefore crashes the entire operating system (a kernel panic).
  • Set /proc/sys/kernel/unprivileged_bpf_disabled to 1, to prevent an attacker from loading an eBPF program into the kernel. However, the attacker may corrupt other vmalloc()ated objects instead (for example, thread stacks), but we have not investigated this possibility.

Why is the vulnerability named 'Sequoia'?

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.

Related