Re: [PATCH 1/2] VMware detection support for x86 and x86-64

Alok kataria
2008-09-25T02:28:48Z

Sorry for joining the discussion this late. But i only noticed this
after somebody pointed me to it.

On Mon, Sep 8, 2008 at 7:04 AM, Ingo Molnar <mingo@elte.hu> wrote:
>
> * Yan Li <elliot.li.tech@gmail.com> wrote:
>
>> +/* Backdoor def from open-vm-tools/lib/include/backdoor_def.h */
>> +#define BDOOR_MAGIC 0x564D5868
>> +/* Low-bandwidth backdoor port. --hpreg */
>> +#define BDOOR_PORT 0x5658
>> +#define BDOOR_CMD_GETVERSION 10
>> +#define VERSION_MAGIC 0x6
>> +
>> +/*
>> + * getVersion - Read VM version & product code through backdoor
>> + */
>> +void getVersion(u32 *version)
>> +{
>> + u32 eax, ebx, ecx, edx;
>> +
>> + asm volatile("inl (%%dx)" :
>> + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :
>> + "0"(BDOOR_MAGIC), "1"(BDOOR_CMD_GETVERSION),
>> + "2"(BDOOR_PORT) : "memory");
>
> hm, i know it's not your fault as you just took this vmware code, but
> this is really not an acceptable method of detection. The above is
> totally unsafe to do on native hardware - we dont know whether there's
> anything on that port.

Even if there is anything on that port on native hardware it would
work perfectly well and is _safe_.
First let me post the code to access this backdoor port (the way it
should really be done )
-------------------------------------------------------------------------------
#define VMWARE_BDOOR_MAGIC 0x564D5868
#define VMWARE_BDOOR_PORT 0x5658

#define VMWARE_BDOOR_CMD_GETVERSION 10
#define VMWARE_BDOOR_CMD_GETHZ 45
#define VMWARE_BDOOR_CMD_LAZYTIMEREMULATION 49

#define VMWARE_BDOOR(cmd, eax, ebx, ecx, edx) \
__asm__("inl (%%dx)" : \
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
"0"(VMWARE_BDOOR_MAGIC), "1"(VMWARE_BDOOR_CMD_##cmd), \
"2"(VMWARE_BDOOR_PORT), "3"(0) : \
"memory");

static inline int vmware_platform(void)
{
uint32_t eax, ebx, ecx, edx;
VMWARE_BDOOR(GETVERSION, eax, ebx, ecx, edx);
return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC;
}
------------------------------------------------------------------------------------------------------

So whenever we query port 0x5658 , with the GETVERSION command (which
is the first thing we do with this port), we expect that eax !=
0xFFFFFFFF and ebx has a VMWARE specific MAGIC value. Please note
that ebx has been initialized to zero in the code above.

Now consider the 2 possible cases on Native hardware
1. Nothing on port 0x5658
In this case the hardware will write a value == 0xFFFFFFFF which will
result in vmware_platform returning zero.
2. Device on port 0x5658
In this case the hardware may return a legitimate value in register
eax, but won't update register ebx. Whereas we check for a MAGIC value
in ebx for this port access. The result is vmware_platform returning
zero.

Also note that, only broken hardware behaves differently when queried
with IN during _initialization_, or all device driver probing would be
fundamentally broken. (Initialized hardware might break due to races,
but during kernel start-up the hardware isn't initialized.)

Maybe the ebx write was overlooked here which resulted in all the
confusion, but its not unsafe for native hardware.

>
> vmware could have used one of the following methods to communicate to
> the guest kernel:
>
> - a CPUID and an MSR range - like a good virtual CPU should. That way
> even bootloaders could detect the presence of vmware.
> - or a PCI ID and a PCI driver like KVM does
> - or a system call hypercall gateway like Xen and KVM does
> - or it could even have used a DMI signature of some sort
>
> but no, vmware had to use 30 year old unsafe ISA port magic...

I agree that the backdoor port may not be the perfect way to
communicate to the hypervisor, but IMO its not unsafe/broken with this
implementation.

We too are using CPUID to detect VMware, but that is available only in
newer products.
>
>
> is there really no vmware PCI ID to query? Could you post the lspci -v
> output of your vmware guest? We could add an early-quirk for one of the
> core vmware PCI devices (in case there are any - i bet there are).

Using PCI id or DMI is not the right way to go further, since that (
pci id or dmi string) can change in future, apart from that it also
puts unnecessary dependency of detecting VMware only after
initializing PCI or the DMI tables.

Please note that this is not the only usecase where we would want to
know if we are running on a hypervisor, there can be other use cases
too. So i would want to generalize this rather than solve it for a
particular case.

To summarize I don't see the backdoor port approach generating any
false positives and it should work perfectly well in all conditions,
having said that I do agree cpuid is the right way further for all the
hypervisors to communicate with any guest OS. So i will send a patch
out soon (am waiting for some legal signoffs on the patches and
should be done in a day or 2) which will help both the newer and older
VMware products, and try to be as generic as possible.

Thanks,
Alok
>
> Ingo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>