CVE-2021-47128
bpf, lockdown, audit: Fix buggy SELinux lockdown permission checks
Severity Score
Exploit Likelihood
Affected Versions
Public Exploits
0Exploited in Wild
-Decision
Descriptions
In the Linux kernel, the following vulnerability has been resolved:
bpf, lockdown, audit: Fix buggy SELinux lockdown permission checks
Commit 59438b46471a ("security,lockdown,selinux: implement SELinux lockdown")
added an implementation of the locked_down LSM hook to SELinux, with the aim
to restrict which domains are allowed to perform operations that would breach
lockdown. This is indirectly also getting audit subsystem involved to report
events. The latter is problematic, as reported by Ondrej and Serhei, since it
can bring down the whole system via audit:
1) The audit events that are triggered due to calls to security_locked_down()
can OOM kill a machine, see below details [0].
2) It also seems to be causing a deadlock via avc_has_perm()/slow_avc_audit()
when trying to wake up kauditd, for example, when using trace_sched_switch()
tracepoint, see details in [1]. Triggering this was not via some hypothetical
corner case, but with existing tools like runqlat & runqslower from bcc, for
example, which make use of this tracepoint. Rough call sequence goes like:
rq_lock(rq) -> -------------------------+
trace_sched_switch() -> |
bpf_prog_xyz() -> +-> deadlock
selinux_lockdown() -> |
audit_log_end() -> |
wake_up_interruptible() -> |
try_to_wake_up() -> |
rq_lock(rq) --------------+
What's worse is that the intention of 59438b46471a to further restrict lockdown
settings for specific applications in respect to the global lockdown policy is
completely broken for BPF. The SELinux policy rule for the current lockdown check
looks something like this:
allow <who> <who> : lockdown { <reason> };
However, this doesn't match with the 'current' task where the security_locked_down()
is executed, example: httpd does a syscall. There is a tracing program attached
to the syscall which triggers a BPF program to run, which ends up doing a
bpf_probe_read_kernel{,_str}() helper call. The selinux_lockdown() hook does
the permission check against 'current', that is, httpd in this example. httpd
has literally zero relation to this tracing program, and it would be nonsensical
having to write an SELinux policy rule against httpd to let the tracing helper
pass. The policy in this case needs to be against the entity that is installing
the BPF program. For example, if bpftrace would generate a histogram of syscall
counts by user space application:
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
bpftrace would then go and generate a BPF program from this internally. One way
of doing it [for the sake of the example] could be to call bpf_get_current_task()
helper and then access current->comm via one of bpf_probe_read_kernel{,_str}()
helpers. So the program itself has nothing to do with httpd or any other random
app doing a syscall here. The BPF program _explicitly initiated_ the lockdown
check. The allow/deny policy belongs in the context of bpftrace: meaning, you
want to grant bpftrace access to use these helpers, but other tracers on the
system like my_random_tracer _not_.
Therefore fix all three issues at the same time by taking a completely different
approach for the security_locked_down() hook, that is, move the check into the
program verification phase where we actually retrieve the BPF func proto. This
also reliably gets the task (current) that is trying to install the BPF tracing
program, e.g. bpftrace/bcc/perf/systemtap/etc, and it also fixes the OOM since
we're moving this out of the BPF helper's fast-path which can be called several
millions of times per second.
The check is then also in line with other security_locked_down() hooks in the
system where the enforcement is performed at open/load time, for example,
open_kcore() for /proc/kcore access or module_sig_check() for module signatures
just to pick f
---truncated---
En el kernel de Linux, se resolvió la siguiente vulnerabilidad: bpf, bloqueo, auditoría: se corrigieron las comprobaciones de permisos de bloqueo de SELinux con errores. El commit 59438b46471a ("seguridad, bloqueo, selinux: implementar bloqueo de SELinux") agregó una implementación del gancho LSM lock_down a SELinux. con el objetivo de restringir qué dominios pueden realizar operaciones que violarían el bloqueo. Indirectamente, esto también implica involucrar al subsistema de auditoría para informar eventos. Esto último es problemático, como informaron Ondrej y Serhei, ya que puede hacer caer todo el sistema a través de una auditoría: 1) Los eventos de auditoría que se activan debido a llamadas a security_locked_down() pueden OOM matar una máquina, vea los detalles a continuación [0] . 2) También parece estar causando un punto muerto a través de avc_has_perm()/slow_avc_audit() cuando se intenta activar kauditd, por ejemplo, cuando se usa el punto de seguimiento trace_sched_switch(), consulte los detalles en [1]. Esto no se activó a través de algún caso hipotético de esquina, sino con herramientas existentes como runqlat y runqslower de bcc, por ejemplo, que hacen uso de este punto de seguimiento. La secuencia de llamada aproximada es así: rq_lock(rq) -> -------------------------+ trace_sched_switch() -> | bpf_prog_xyz() -> +-> punto muerto selinux_lockdown() -> | audit_log_end() -> | wake_up_interruptible() -> | try_to_wake_up() -> | rq_lock(rq) --------------+ Lo que es peor es que la intención de 59438b46471a de restringir aún más la configuración de bloqueo para aplicaciones específicas con respecto a la política de bloqueo global no es válida para BPF. La regla de política de SELinux para la verificación de bloqueo actual se parece a esto: permitir : bloqueo { }; Sin embargo, esto no coincide con la tarea 'actual' donde se ejecuta security_locked_down(), ejemplo: httpd realiza una llamada al sistema. Hay un programa de seguimiento adjunto a la llamada al sistema que activa la ejecución de un programa BPF, que termina realizando una llamada de ayuda bpf_probe_read_kernel{,_str}(). El gancho selinux_lockdown() realiza la verificación de permisos con respecto a 'actual', es decir, httpd en este ejemplo. httpd tiene literalmente cero relación con este programa de rastreo, y no tendría sentido tener que escribir una regla de política SELinux contra httpd para permitir que pase el asistente de rastreo. La política en este caso debe ser contra la entidad que está instalando el programa BPF. Por ejemplo, si bpftrace generara un histograma de recuentos de llamadas al sistema por aplicación de espacio de usuario: bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' bpftrace luego generaría un programa BPF a partir de esto internamente. Una forma de hacerlo [por el bien del ejemplo] podría ser llamar al asistente bpf_get_current_task() y luego acceder a current->comm a través de uno de los asistentes bpf_probe_read_kernel{,_str}(). Entonces, el programa en sí no tiene nada que ver con httpd o cualquier otra aplicación aleatoria que realice una llamada al sistema aquí. El programa BPF _inició explícitamente_ la verificación del bloqueo. La política de permitir/denegar pertenece al contexto de bpftrace: es decir, desea otorgar acceso a bpftrace para usar estos asistentes, pero otros rastreadores en el sistema como my_random_tracer _no_. Por lo tanto, solucione los tres problemas al mismo tiempo adoptando un enfoque completamente diferente para el enlace security_locked_down(), es decir, mueva la verificación a la fase de verificación del programa donde realmente recuperamos el protocolo de función BPF. Esto también obtiene de manera confiable la tarea (actual) que está intentando instalar el programa de rastreo de BPF, por ejemplo, bpftrace/bcc/perf/systemtap/etc,---truncado---
CVSS Scores
SSVC
- Decision:Track
Timeline
- 2024-03-04 CVE Reserved
- 2024-03-15 CVE Published
- 2024-03-16 EPSS Updated
- 2024-12-19 CVE Updated
- ---------- Exploited in Wild
- ---------- KEV Due Date
- ---------- First Exploit
CWE
CAPEC
References (4)
URL | Tag | Source |
---|---|---|
https://git.kernel.org/stable/c/59438b46471ae6cdfb761afc8c9beaf1e428a331 | Vuln. Introduced |
URL | Date | SRC |
---|
URL | Date | SRC |
---|
Affected Vendors, Products, and Versions
Vendor | Product | Version | Other | Status | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Vendor | Product | Version | Other | Status | <-- --> | Vendor | Product | Version | Other | Status |
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.6 < 5.10.43 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.6 < 5.10.43" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.6 < 5.12.10 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.6 < 5.12.10" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.6 < 5.13 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.6 < 5.13" | en |
Affected
|