lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 28 Oct 2020 11:03:05 -0700
From:   Erdem Aktas <erdemaktas@...gle.com>
To:     Joerg Roedel <jroedel@...e.de>
Cc:     linux-kernel@...r.kernel.org,
        "Lendacky, Thomas" <Thomas.Lendacky@....com>,
        linux-tip-commits@...r.kernel.org, Borislav Petkov <bp@...e.de>,
        x86 <x86@...nel.org>
Subject: Re: [tip: x86/seves] x86/kvm: Add KVM-specific VMMCALL handling under SEV-ES

I might be missing something here but I think what you say is only
correct for the kvm_hypercall4 cases. All other functions use a
smaller number of registers. #VC blindly assumes that all those
registers are used in the vmcall and exposes them. Here are some
examples:

For example in the kvm_hypercall2 only rax, rbx, and rcx should be
exposed. apic_id address is leaked with rdx when this hypercall is
used in kvm_kick_cpu function. RSI is never used. I am not sure what
value will be exposed to VMM in this case:

 54 static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
 55                                   unsigned long p2)
 56 {
 57         long ret;
 58         asm volatile(KVM_HYPERCALL
 59                      : "=a"(ret)
 60                      : "a"(nr), "b"(p1), "c"(p2)
 61                      : "memory");
 62         return ret;
 63 }
And this function is called in :

820 static void kvm_kick_cpu(int cpu)
821 {
822         int apicid;
823         unsigned long flags = 0;
824
825         apicid = per_cpu(x86_cpu_to_apicid, cpu);
826         kvm_hypercall2(KVM_HC_KICK_CPU, flags, apicid);
827 }

looking to what it is compiled in my machine :

151215 ffffffff8105def0 <kvm_kick_cpu>:
 151216 {
 151217 ffffffff8105def0:       e8 fb 9e ff ff          callq
ffffffff81057df0 <__fentry__>
 151218         apicid = per_cpu(x86_cpu_to_apicid, cpu);
 151219 ffffffff8105def5:       48 63 ff                movslq %edi,%rdi
 151220 {
 151221 ffffffff8105def8:       53                      push   %rbx
 151222         apicid = per_cpu(x86_cpu_to_apicid, cpu);
 151223 ffffffff8105def9:       48 c7 c0 58 16 01 00    mov    $0x11658,%rax
 151224
 151225 static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
 151226                                   unsigned long p2)
 151227 {
 151228         long ret;
 151229         asm volatile(KVM_HYPERCALL
 151230 ffffffff8105df00:       31 db                   xor    %ebx,%ebx
 151231 ffffffff8105df02:       48 8b 14 fd 00 19 cb    mov
-0x7e34e700(,%rdi,8),%rdx
 151232 ffffffff8105df09:       81
 151233         kvm_hypercall2(KVM_HC_KICK_CPU, flags, apicid);
 151234 ffffffff8105df0a:       0f b7 0c 02             movzwl
(%rdx,%rax,1),%ecx
 151235 ffffffff8105df0e:       b8 05 00 00 00          mov    $0x5,%eax
 151236 ffffffff8105df13:       0f 01 c1                vmcall
 151237 }
 151238 ffffffff8105df16:       5b                      pop    %rbx
 151239 ffffffff8105df17:       c3                      retq


Similarly kvm_hypercall1 only need 2 registers to expose:

 44 static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
 45 {
 46         long ret;
 47         asm volatile(KVM_HYPERCALL
 48                      : "=a"(ret)
 49                      : "a"(nr), "b"(p1)
 50                      : "memory");
 51         return ret;
 52 }

And an example where it is used:

562 static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
563 {
564         int cpu;
565
566         native_send_call_func_ipi(mask);
567
568         /* Make sure other vCPUs get a chance to run if they need to. */
569         for_each_cpu(cpu, mask) {
570                 if (vcpu_is_preempted(cpu)) {
571                         kvm_hypercall1(KVM_HC_SCHED_YIELD,
per_cpu(x86_cpu_to_apicid, cpu));
572                         break;
573                 }
574         }
575 }

If we look at the function decompiled in my platform, here
x86_cpu_to_apicid address is leaked in rdx. RSI also leaks some
information from kvm_smp_send_call_function_ipi function. RCX is not
used so it might include something from a higher caller.

 151243 ffffffff8105df20 <kvm_smp_send_call_func_ipi>:
 151244 {
 151245 ffffffff8105df20:       e8 cb 9e ff ff          callq
ffffffff81057df0 <__fentry__>
 151246 ffffffff8105df25:       53                      push   %rbx
 151247 ffffffff8105df26:       48 89 fb                mov    %rdi,%rbx
 151248         native_send_call_func_ipi(mask);
 151249 ffffffff8105df29:       e8 a2 45 ff ff          callq
ffffffff810524d0 <native_send_call_func_ipi>
 151250         for_each_cpu(cpu, mask) {
 151251 ffffffff8105df2e:       41 b8 ff ff ff ff       mov    $0xffffffff,%r8d
 151252 ffffffff8105df34:       eb 0e                   jmp
ffffffff8105df44 <kvm_smp_send_call_func_ipi+0x24>
 151253         return PVOP_CALLEE1(bool, lock.vcpu_is_preempted, cpu);
 151254 ffffffff8105df36:       49 63 f8                movslq %r8d,%rdi
 151255 ffffffff8105df39:       ff 14 25 90 93 02 82    callq
*0xffffffff82029390
 151256                 if (vcpu_is_preempted(cpu)) {
 151257 ffffffff8105df40:       84 c0                   test   %al,%al
 151258 ffffffff8105df42:       75 18                   jne
ffffffff8105df5c <kvm_smp_send_call_func_ipi+0x3c>
 151259         for_each_cpu(cpu, mask) {
 151260 ffffffff8105df44:       44 89 c7                mov    %r8d,%edi
 151261 ffffffff8105df47:       48 89 de                mov    %rbx,%rsi
 151262 ffffffff8105df4a:       e8 61 44 39 00          callq
ffffffff813f23b0 <cpumask_next>
 151263 ffffffff8105df4f:       3b 05 2f 7e 12 01       cmp
0x1127e2f(%rip),%eax        # ffffffff82185d84 <nr_cpu_ids>
 151264 ffffffff8105df55:       41 89 c0                mov    %eax,%r8d
 151265 ffffffff8105df58:       72 dc                   jb
ffffffff8105df36 <kvm_smp_send_call_func_ipi+0x16>
 151266 }
 151267 ffffffff8105df5a:       5b                      pop    %rbx
 151268 ffffffff8105df5b:       c3                      retq
 151269                         kvm_hypercall1(KVM_HC_SCHED_YIELD,
per_cpu(x86_cpu_to_apicid, cpu));
 151270 ffffffff8105df5c:       48 8b 14 fd 00 19 cb    mov
-0x7e34e700(,%rdi,8),%rdx
 151271 ffffffff8105df63:       81
 151272 ffffffff8105df64:       48 c7 c0 58 16 01 00    mov    $0x11658,%rax
 151273 ffffffff8105df6b:       0f b7 1c 02             movzwl
(%rdx,%rax,1),%ebx
 151274         asm volatile(KVM_HYPERCALL
 151275 ffffffff8105df6f:       b8 0b 00 00 00          mov    $0xb,%eax
 151276 ffffffff8105df74:       0f 01 c1                vmcall
 151277 }

I am not sure how those leaked registers can be used, but depending on
which function call hypercall[0-3], there will be some leak.

-Erdem



On Wed, Oct 28, 2020 at 2:49 AM Joerg Roedel <jroedel@...e.de> wrote:
>
> On Tue, Oct 27, 2020 at 04:14:15PM -0700, Erdem Aktas wrote:
> > It seems to me that the kvm_sev_es_hcall_prepare is leaking more
> > information than it is needed. Is this an expected behavior?
>
> What exactly is leaked? The kvm hypercall uses RAX, RBX, RCX, RDX and
> RSI for parameters.
>
> Regards,
>
>         Joerg

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ