ASA-2020-00051 – Linux kernel: Reference counter underflow na página da vsyscall


For the English version of this alert, click here.

Allele Security Alert

ASA-2020-00051

Identificador(es)

ASA-2020-00051, CVE-2020-25221, CID-9fa2dd946743

Título

Reference counter underflow na página da vsyscall

Fabricante(s)

Linux foundation

Produto(s)

Linux kernel

Versão(ões) afetada(s)

Linux kernel versão 5.7
Linux kernel 5.8.x versões anteriores a 5.8.7

Versões do kernel Linux desde o seguinte commit:

mm/gup: track FOLL_PIN pages
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3faa52c03f440d1b9ddef18c4f189f4790d52d7e

Versão(ões) corrigida(s)

Linux kernel versão 5.8.7

Versões do kernel Linux com o seguinte commit aplicado:

mm: fix pin vs. gup mismatch with gate pages
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9fa2dd946743ae6f30dc4830da19147bf100a7f2

Prova de Conceito

Sim

Descrição

O Linux 5.7 e 5.8 tem um bug no reference counter da struct page que dá suporte à página da vsyscall. O resultado é um underflow do reference counter. Isso pode ser acionado por qualquer processo de 64 bits que tenha permissão para usar ptrace() ou process_vm_readv().

Detalhes técnicos

Gate pages foram perdidas ao converter de get para pin_user_pages(). Isso pode levar a desequilíbrios na contagem. Isso é reproduzível de forma confiável e rápida executando os autotestes do x86 quando vsyscall=emulate está ativado (o padrão). A correção é feita usando try_grab_page() com flags apropriadas passadas.

Hoje, pin_user_pages() e get_user_pages() são interfaces semelhantes para manipular reference counters de página. No entanto, “pins” usam um valor “bias” e manipulam a contagem de referência real em 1024 em vez de 1 usado por “gets” simples.

Isso significa que pin_user_page() deve ser combinado com unpin_user_pages() e não pode ser misturado com put_user_pages() ou put_page().

Entra as gate pages, como a página da vsyscall. São páginas geralmente na imagem do kernel, mas que são mapeadas para o espaço do usuário. O espaço do usuário tem acesso permitido a elas, incluindo interfaces usando get/pin_user_pages(). O reference counter dessas páginas do kernel é manipulado como um página de um usuário normal no lado get/pin para que o lado put/unpin possa funcionar da mesma forma para páginas normais de usuário ou gate pages.

get_gate_page() usa try_get_page() que apenas aumenta o reference counter em 1, não 1024, mesmo se chamado no caminho pin_user_pages(). Se alguém fixa uma gate pate, isso acontece:

pin_user_pages()
get_gate_page()
try_get_page() // bump refcount +1
... algum tempo depois
unpin_user_pages()
page_ref_sub_and_test(page, 1024))

Isso resulta em um reference counter errado por 1023. Isso é confiável e rapidamente reproduzível executando os autotestes do x86 quando inicializado com vsyscall=emulate (o padrão).

Para corrigir, simplesmente usa try_grab_page() ao invés de try_get_page(), e passe ‘gup_flags’ para que FOLL_PIN possa ser respeitado.

Créditos

Peter Zijlstra

Referência(s)

oss-security – CVE Request: Linux kernel vsyscall page refcounting error
https://www.openwall.com/lists/oss-security/2020/09/08/4

test_vsyscall.c
https://github.com/torvalds/linux/blob/master/tools/testing/selftests/x86/test_vsyscall.c

mm: fix pin vs. gup mismatch with gate pages
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9fa2dd946743ae6f30dc4830da19147bf100a7f2

mm: fix pin vs. gup mismatch with gate pages
https://github.com/torvalds/linux/commit/9fa2dd946743ae6f30dc4830da19147bf100a7f2

mm/gup: track FOLL_PIN pages
https://github.com/torvalds/linux/commit/3faa52c03f440d1b9ddef18c4f189f4790d52d7e

mm/gup: track FOLL_PIN pages
https://github.com/torvalds/linux/commit/3faa52c03f440d1b9ddef18c4f189f4790d52d7e

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

CVE-2020-25221
https://access.redhat.com/security/cve/CVE-2020-25221

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

CVE-2020-25221 | SUSE
https://www.suse.com/security/cve/CVE-2020-25221

CVE-2020-25221
https://security-tracker.debian.org/tracker/CVE-2020-25221

CVE-XXXX-XXXXX
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-XXXX-XXXXX

CVE-XXXX-XXXXX
https://nvd.nist.gov/vuln/detail/CVE-XXXX-XXXXX

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

Última modificação: 16 setembro 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.