ASA-2019-00082 – Linux: Binder use-after-free via otimização fdget()


For the English version of this alert, click here.

Allele Security Alert

ASA-2019-00082

Identificador(es)

ASA-2019-00082, A-120025789, CVE-2019-2000

Título

Binder use-after-free via otimização fdget()

Fabricante(s)

The Linux foundation
Google

Produto(s)

Linux
Android

Versão(ões) afetada(s)

Linux kernel desde commit:

binder: use standard functions to allocate fds
https://github.com/torvalds/linux/commit/44d8047f1d87adc2fd7eccc88533794f6d88c15e

Android Security Patch Levels anteriores a February 2019

Versão(ões) corrigida(s)

Linux kernel com o seguinte commit:

binder: fix use-after-free due to ksys_close() during fdget()
https://github.com/torvalds/linux/commit/80cd795630d6526ba729a089a435bf74a57af927

Android Security Patch Level February 2019

Prova de conceito

Sim

Descrição

O kernel do Linux contém um use-after-free no mecanismo de IPC Binder via otimização fdget().

Detalhes técnicos

No kernel do Linux, normalmente, quando uma `struct file *` é lido da tabela de descritores de arquivos, o contador de referência do `struct file` é incrementado para considerar a referência extra; isso acontece em fget(). Posteriormente, se a referência extra não for mais necessária, o contador de referência será decrementado por meio de fput(). Um efeito negativo disso é que, se o `struct file` é acessado freqüentemente, a cacheline contendo o contador de referência está constantemente suja; e se o `struct file` é usado por várias tarefas em paralelo, ocorre cache line bouncing.

O Linux fornece os helpers fdget() e fdput() para evitar essa sobrecarga. fdget() verifica se o contador de referência da tabela do descritor de arquivos é 1, implicando que a tarefa atual possui propriedade exclusiva da tabela do descritor de arquivos e que nenhuma modificação concorrente da tabela do descritor de arquivo pode ocorrer. Se esta verificação for bem-sucedida, fdget() então omite o incremento do contador de referência no `struct file`. fdget() define uma flag em seu valor de retorno que sinaliza para fdput() se um contador de referência foi tomado. Se assim for, fdput() usa a lógica normal fput(); se não, fdput() não faz nada.

Essa otimização depende de algumas regras, incluindo:

A) Uma referência feita via fdget() deve ser descartada com fdput() antes do final da syscall.
B) A referência de uma tarefa à sua tabela de descritores de arquivos só pode ser duplicada para escrita se essa tarefa for conhecida não estar entre fdget() e fdput().
C) Uma tarefa que pode estar entre um fdget() e fdput() elididos não deve usar ksys_close() no mesmo número de descritor de arquivo usado para fdget().

O código upstream atual viola a regra C. A seqüência de eventos a seguir pode fazer com que fput() deixe cair o contador de referência em uso de um arquivo binder para zero:

A tarefa A e a tarefa B estão conectadas via binder; A tarefa A tem /dev/binder aberto no descritor de arquivo número X. Ambas as tarefas são de thread única.

– a tarefa B envia uma mensagem binder com um array de descritor de arquivo (BINDER_TYPE_FDA) contendo um descritor de arquivo para a tarefa A
– a tarefa A lê a mensagem binder com o descritor de arquivo traduzido número Y
– A tarefa A usa dup2(X, Y) para sobrescrever o descritor de arquivo Y com o arquivo /dev/binder
– tarefa A desmapeia o mapeamento de memória do binder do espaço do usuário; o contador de referência na tarefa A /dev/binder é agora 2
– A tarefa A fecha o descritor de arquivo X; o contador de referência na tarefa A /dev/binder é agora 1
– A tarefa A chama o comando BC_FREE_BUFFER no descritor de arquivo X para liberar a mensagem de entrada do binder
– fdget() elimina o incremento do contador de referência, já que a tabela descritora de arquivos não é compartilhada – o manipulador BC_FREE_BUFFER remove a entrada da tabela descritor de arquivos para X e decrementa o contador de referência do arquivo /dev/binder da tarefa A para zero

Como o fput() usa o mecanismo de trabalho da tarefa para liberar o arquivo, isso não causa imediatamente um use-after-free que o KASAN possa detectar; para isso, a seguinte sequência de eventos funciona:

– A tarefa A fecha o descritor de arquivo X; o contador de referência na tarefa A /dev/binder é agora 1
– tarefa A cria uma nova tarefa, tarefa C, duplicando a tabela do descritor de arquivos; o contador de referência na tarefa A /dev/binder é agora 2
– A tarefa A chama o comando BC_FREE_BUFFER no descritor de arquivo X para liberar a mensagem binder de entrada
– fdget() em ksys_ioctl() elimina o incremento do contador de referência, já que a tabela de descritores de arquivos não é compartilhada
– o manipulador BC_FREE_BUFFER remove a entrada da tabela do descritor de arquivo para X e decrementa o contador de referência do arquivo /dev/binder da tarefa A para 1
– a tarefa C chama close(X), o que reduz o contador de referência da tarefa A /dev/binder para 0 e a libera
– a tarefa A continua o processamento do ioctl e acessa alguma propriedade de, por exemplo, o binder_proc => UAF detectável no KASAN

Créditos

Jann Horn (Google Project Zero)

Referência(s)

1719 – Android: binder use-after-free via fdget() optimization –  project-zero – Monorail
https://bugs.chromium.org/p/project-zero/issues/detail?id=1719

Android Security Bulletin — February 2019
https://source.android.com/security/bulletin/2019-02-01.html

binder: fix proc->files use-after-free
https://github.com/torvalds/linux/commit/7f3dc0088b98

binder: fix use-after-free due to ksys_close() during fdget()
https://github.com/torvalds/linux/commit/80cd795630d6526ba729a089a435bf74a57af927

binder: use standard functions to allocate fds
https://github.com/torvalds/linux/commit/44d8047f1d87adc2fd7eccc88533794f6d88c15e

FROMLIST: binder: fix proc->files use-after-free
https://android.googlesource.com/kernel/msm/+/1b652c7c29b7

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

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

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

Última modificação: 19 fevereiro 2019

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.