For the English version of this alert, click here.
Allele Security Alert
ASA-2019-00084
Identificador(es)
ASA-2019-00084, CVE-2019-7221
Título
Use-after-free usando temporizador de preempção vmx emulado
Fabricante(s)
The Linux foundation
Produto(s)
Linux
Versão(ões) afetada(s)
Desconhecido
Versão(ões) corrigida(s)
Linux kernel com o seguinte commit:
KVM: nVMX: unconditionally cancel preemption timer in free_nested (CVE-2019-7221)
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ecec76885bcfe3294685dc363fd1273df0d5d65f
Linux kernel 4.20.8
Linux kernel 4.19.21
Linux kernel 4.14.99
Linux kernel 4.9.156
Prova de conceito
Desconhecido
Descrição
Uma vulnerabilidade de use-after-free foi encontrada na maneira como o hypervisor KVM do kernel do Linux emula um temporizador de preempção para convidados L2 quando a virtualização aninhada (=1) é ativada. Este timer de alta resolução (hrtimer) é executado quando um convidado L2 está ativo. Após a saída da VM, o objeto do cronômetro sync_vmcs12() é interrompido. O use-after-free ocorre se o objeto timer for liberado antes de chamar a rotina sync_vmcs12(). Um usuário convidado/processo poderia usar essa falha para travar o kernel do host, resultando em uma negação de serviço ou, potencialmente, obter acesso privilegiado a um sistema.
Detalhes técnicos
O KVM emula temporizadores de preempção de VMX para convidados de L2 usando um timer de alta resolução chamado preemption_timer. O temporizador é armazenado na estrutura nested_vmx que é um membro de vcpu_vmx.
Se um hypervisor L1 usar esse recurso para um convidado L2, o timer será iniciado logo antes de entrar no convidado L2 em nested_vmx_run->enter_vmx_non_root_mode->prepare_vmcs02->vmx_start_preemption_timer:
static void vmx_start_preemption_timer(struct kvm_vcpu *vcpu) { u64 preemption_timeout = get_vmcs12(vcpu)->vmx_preemption_timer_value; struct vcpu_vmx *vmx = to_vmx(vcpu); … preemption_timeout <<= VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE; preemption_timeout *= 1000000; do_div(preemption_timeout, vcpu->arch.virtual_tsc_khz); hrtimer_start(&vmx->nested.preemption_timer, ns_to_ktime(preemption_timeout), HRTIMER_MODE_REL); }
Para garantir que o timer seja executado somente enquanto L2 estiver ativo, o KVM chamará hrtimer_cancel em sync_vmc12, que é chamado após uma saída da VM L2:
static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { ... if (nested_cpu_has_preemption_timer(vmcs12)) { if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER) vmcs12->vmx_preemption_timer_value = vmx_get_preemption_timer_value(vcpu); hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer); }
Não há locking no local para garantir que a estrutura kvm_vcpu, que armazena preemption_timer, não seja liberada enquanto o cronômetro estiver ativo. Isso significa que um atacante que pode fazer uma chamada para vmx_free_vcpu sem chamar sync_vmcs12 pode acionar um altamente explorável use-after-free (ponteiro de função controlada + primeiro argumento apontando para dados controlados pelo atacante).
Acredito que há várias maneiras de fazer isso, mas uma abordagem possível é acionar uma falha na entrada da VM em enter_vmx_non_root_mode após a chamada para o timer vmx_start_preemption:
O KVM reimplementa a maioria das verificações de entrada de VM no software e as chama antes de enter_vmx_non_root_mode. No entanto, falhas de entrada devido a um endereço de carregamento MSR inválido acontecem depois que prepare_vmcs02 invoca vmx_start_preemption_timer:
if (prepare_vmcs02(vcpu, vmcs12, from_vmentry ? exit_qual : &dummy_exit_qual)) goto fail; if (from_vmentry) { nested_get_vmcs12_pages(vcpu); r = EXIT_REASON_MSR_LOAD_FAIL; *exit_qual = nested_vmx_load_msr(vcpu, vmcs12->vm_entry_msr_load_addr, vmcs12->vm_entry_msr_load_count); if (*exit_qual) goto fail;
Créditos
Felix Wilhelm (Google Project Zero)
Referência(s)
Issue 1760: KVM: use-after-free using emulated vmx preemption timer
https://bugs.chromium.org/p/project-zero/issues/detail?id=1760
Bug 1671904 (CVE-2019-7221) – CVE-2019-7221 Kernel: KVM: nVMX: use-after-free of the hrtimer for emulation of the preemption timer
https://bugzilla.redhat.com/show_bug.cgi?id=1671904
KVM: nVMX: unconditionally cancel preemption timer in free_nested (CVE-2019-7221)
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ecec76885bcfe3294685dc363fd1273df0d5d65f
ChangeLog-4.20.8
https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.20.8
ChangeLog-4.19.21
https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.19.21
ChangeLog-4.14.99
https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.14.99
ChangeLog-4.9.156
https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.9.156
CVE-2019-7221
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-7221
CVE-2019-7221
https://nvd.nist.gov/vuln/detail/CVE-2019-7221
Se encontrou algum erro neste alerta ou deseja uma análise compreensiva, entre em contato.
Última modificação: 19 fevereiro 2019