ASA-2019-00654 – Linux kernel: Corrupção de memória devido ao uso de fpu_fpregs_owner_ctx em cache


For the English version of this alert, click here.

Allele Security Alert

ASA-2019-00654

Identificador(es)

ASA-2019-00654, CVE-2019-19602, CID-59c4bd853abc

Título

Corrupção de memória devido ao uso de fpu_fpregs_owner_ctx em cache

Fabricante(s)

Linux foundation

Produto(s)

Linux kernel

Versão(ões) afetada(s)

Linux kernel versões 5.4.x anteriores a 5.4.2
Linux kernel versões 5.3.x anteriores a 5.3.15

Linux kernel versões com o seguinte commit aplicado:

x86/fpu: Defer FPU state load until return to userspace
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5f409e20b794565e2d60ad333e79334630a6c798

Versão(ões) corrigida(s)

Linux kernel versão 5.4.2
Linux kernel versão 5.3.15

Linux kernel versões com o seguinte commit aplicado:

x86/fpu: Don’t cache access to fpu_fpregs_owner_ctx
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=59c4bd853abcea95eccc167a7d7fd5f1a5f47b98

Prova de Conceito

Desconhecido

Descrição

fpregs_state_valid em arch/x86/include/asm/fpu/internal.h no kernel do Linux, quando o GCC 9 é usado, permite que atacantes dependentes de contexto causem uma negação de serviço (corrupção de memória) ou possivelmente tenham outro impacto não especificado devido ao incorreto armazenamento de fpu_fpregs_owner_ctx em cache, conforme demonstrado pelo manuseio incorreto da preempção não cooperativa baseada em sinal no Go 1.14 prereleases no amd64.

Detalhes técnicos

O estado/proprietário da FPU é salvo em fpu_fpregs_owner_ctx apontando para o contexto que está carregado no momento. Ele nunca muda durante a vida útil de uma tarefa – permaneceu estável/constante.

Depois que foi implementado o carregamento adiado dos registradores da FPU até o retorno para userland, o conteúdo de fpu_fpregs_owner_ctx pode mudar durante a preempção e não deve ser armazenado em cache.

Isso passou despercebido por algum tempo e agora foi percebido, principalmente porque o gcc 9 está armazenando em cache esse carregamento em copy_fpstate_to_sigframe() e reutilizando-o no loop de nova tentativa:

copy_fpstate_to_sigframe()
load fpu_fpregs_owner_ctx and save on stack
fpregs_lock()
copy_fpregs_to_sigframe() /* failed */
fpregs_unlock()
*** PREEMPTION, another uses FPU, changes fpu_fpregs_owner_ctx ***

fault_in_pages_writeable() /* succeed, retry */

fpregs_lock()
__fpregs_load_activate()
fpregs_state_valid() /* uses fpu_fpregs_owner_ctx from stack */
copy_fpregs_to_sigframe() /* succeeds, random FPU content */

Esta é uma comparação do assembly produzido pelo gcc 9, sem e com este patch:

| # arch/x86/kernel/fpu/signal.c:173: if (!access_ok(buf, size))
| cmpq %rdx, %rax # tmp183, _4
| jb .L190 #,
|-# arch/x86/include/asm/fpu/internal.h:512: return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|-#APP
|-# 512 "arch/x86/include/asm/fpu/internal.h" 1
|- movq %gs:fpu_fpregs_owner_ctx,%rax #, pfo_ret__
|-# 0 "" 2
|-#NO_APP
|- movq %rax, -88(%rbp) # pfo_ret__, %sfp
…
|-# arch/x86/include/asm/fpu/internal.h:512: return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|- movq -88(%rbp), %rcx # %sfp, pfo_ret__
|- cmpq %rcx, -64(%rbp) # pfo_ret__, %sfp
|+# arch/x86/include/asm/fpu/internal.h:512: return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|+#APP
|+# 512 "arch/x86/include/asm/fpu/internal.h" 1
|+ movq %gs:fpu_fpregs_owner_ctx(%rip),%rax # fpu_fpregs_owner_ctx, pfo_ret__
|+# 0 "" 2
|+# arch/x86/include/asm/fpu/internal.h:512: return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|+#NO_APP
|+ cmpq %rax, -64(%rbp) # pfo_ret__, %sfp

Créditos

The Go Team

Referência(s)

AVX register corruption from signal delivery
https://bugzilla.kernel.org/show_bug.cgi?id=205663

x86/fpu: Don’t cache access to fpu_fpregs_owner_ctx
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=59c4bd853abcea95eccc167a7d7fd5f1a5f47b98

x86/fpu: Don’t cache access to fpu_fpregs_owner_ctx
https://github.com/torvalds/linux/commit/59c4bd853abcea95eccc167a7d7fd5f1a5f47b98

x86/fpu: Defer FPU state load until return to userspace
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5f409e20b794565e2d60ad333e79334630a6c798

x86/fpu: Defer FPU state load until return to userspace
https://github.com/torvalds/commit/5f409e20b794565e2d60ad333e79334630a6c798

runtime: memory corruption on Linux 5.2+ #35777
https://github.com/golang/go/issues/35777

AVX register corruption from signal delivery
https://lore.kernel.org/lkml/c87e93c3-5f30-f242-74b7-6c7ccc91158a@google.com/

Linux 5.4.2
https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.4.2

Linux 5.3.15
https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.3.15

CVE-2019-19602
https://access.redhat.com/security/cve/CVE-2019-19602

CVE-2019-19602
https://security-tracker.debian.org/tracker/CVE-2019-19602

CVE-2019-19602 | SUSE
https://www.suse.com/security/cve/CVE-2019-19602

CVE-2019-19602 in Ubuntu
https://people.canonical.com/~ubuntu-security/cve/CVE-2019-19602.html

CVE-2019-19602
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-19602

CVE-2019-19602
https://nvd.nist.gov/vuln/detail/CVE-2019-19602

Se encontrou algum erro neste alerta ou deseja uma análise compreensiva, entre em contato.

Última modificação: 11 fevereiro 2020

Não somos responsáveis por qualquer perda de dados, corrupção de dispositivos ou qualquer outro tipo de problema devido ao uso de qualquer informação mencionada em nossos alertas de segurança.