如何判断 Linux 是否运行在虚拟机上

在 WebHostingTalk 论坛上有些国外奸商会把虚拟机当作独立服务器卖,去年7月份的时候就有一位中国同胞上当受骗,并在 WHT 上发帖声讨,证据确凿,甚至连服务商自己也承认,回帖达355篇。这家独立服务器/VPS 提供商 HostATree.com 居然大胆的把 OpenVZ VPS 这种一看就知道是虚拟机的虚拟机当作独立服务器卖,晕,至少也要弄个 VMWare/KVM/Xen HVM 吧(更难发现是虚拟机),用 OpenVZ 这种容器也太欺负人了:)昨天恰好收到网友一封邮件问到了如何判断自己买的是独立服务器还是虚拟机的问题。这里 VPSee 简单介绍一下市面上常用虚拟技术(包括容器技术)的判别小技巧。

判断 OpenVZ/Xen PV/UML

判断 OpenVZ/Xen PV/UML 是最容易的,直接检查 /proc 下的相关目录和文件就可以知道,比如 OpenVZ VPS 上会有 /proc/vz 这个文件;Xen PV 虚拟机上会有 /proc/xen/ 这个目录,并且目录下有一些东西;UML 上打印 /proc/cpuinfo 会找到 UML 标志。写了一个简单的 Python 脚本来检测:

#!/usr/bin/python
# check if a linux system running on a virtual machine (openvz/xen pv/uml)
# written by http://www.vpsee.com

import sys, os

def main():
    if os.getuid() != 0:
        print "must be run as root"
        sys.exit(0)

    # check OpenVZ/Virtuozzo
    if os.path.exists("/proc/vz"):
        if not os.path.exists("/proc/bc"):
            print "openvz container"
        else:
            print "openvz node"

    # check Xen
    if os.path.exists("/proc/xen/capabilities"):
        if (os.path.getsize("/proc/xen/capabilities") > 0):
            print "xen dom0"
        else:
            print "xen domU"

    # check User Mode Linux (UML)
    f = open("/proc/cpuinfo", "r"); t = f.read(); f.close()
    if (t.find("UML") > 0):
        print "uml"

if __name__=="__main__":
    main()

判断 VMware/Xen HVM/KVM

如果使用的是 VMware/Xen HVM/KVM 这样的全虚拟就更难判断一些,最准确的办法是读取 CPUID 来判断,Xen 源代码下面有一段检测是否是 Xen 的 C 语言代码 tools/misc/xen-detect.c,这段代码提供了一个很好的例子,VPSee 重写了代码,用宏替代了函数,增加了对 VMware 和 KVM 的识别,用 gcc 编译后就可以运行:

/*
 * check if a linux system running on a virtual machine (vmware/xen hvm/kvm)
 * written by http://www.vpsee.com
 */
#include <stdio.h>
#include <string.h>

#define HYPERVISOR_INFO 0x40000000

#define CPUID(idx, eax, ebx, ecx, edx) \
    asm volatile ( \
        "test %1,%1 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid" \
        : "=b" (*ebx), "=a" (*eax), "=c" (*ecx), "=d" (*edx) \
        : "0" (idx) );

int main(void)
{
        unsigned int eax, ebx, ecx, edx;
        char string[13];

        CPUID(HYPERVISOR_INFO, &eax, &ebx, &ecx, &edx);
        *(unsigned int *)(string+0) = ebx;
        *(unsigned int *)(string+4) = ecx;
        *(unsigned int *)(string+8) = edx;

        string[12] = 0;
        if (strncmp(string, "XenVMMXenVMM", 12) == 0) {
                printf("xen hvm\n");
        } else if (strncmp(string, "VMwareVMware", 12) == 0) {
                printf("vmware\n");
        } else if (strncmp(string, "KVMKVMKVM", 12) == 0) {
                printf("kvm\n");
        } else
                printf("bare hardware\n");

        return 0;
}

判断 VirtualBox/Virtual PC

什么?这种家用桌面虚拟机自己装的还会不知道?!如果不知道的话也有办法,在 Linux 下运行 dmidecode 工具然后查找 Manufacturer: innotek GmbH, Manufacturer: Microsoft Corporation 关键字就能对应上 VirtualBox 和 Virtual PC.

评论 (20 Comments)

  1. 不错,收藏了。

  2. [email protected] 发 email 被拒了。新浪微博你也没回。只好在此留言。

    我觉得你的技术不错,服务也不错,有个机会(给个老外设置 linode vps)看你有没有兴趣。
    如果你的英文水平好,可以直接跟老外沟通,就最好。
    盼复 [email protected] 。谢谢。

  3. 我有个方法也可以监测虚拟机,就是hwclock
    如果可以写硬件,就说明不是虚拟机。

  4. @rog
    好方法:)

  5. 判断UML需要装Python吧.
    另外,判断 VMware/Xen HVM/KVM也需要装GCC吧.
    感觉要是能有更方便的办法就好了.
    或者统一用Python,判断所有VPS…..

  6. 你水平越来越高了。我都想用你的VPS了。

  7. @Meteor
    用 ls 和 cat 就可以通过查看 /proc 来判断 openvz/xen pv/uml 啊,vmware/xen hvm/kvm 只能通过汇编去 CPUID 读值来判断。

  8. 我的linode xen服务器没有/proc/xen这个目录啊,操作系统是ubuntu 10.10,为啥呢?

  9. 如果简单的查看可以使用virt-what这个东西,安装很简单,安装完运行virt-what命令可以看一下输出,如果是虚拟机会输出虚拟机具体类型,如果是独服就不会输出内容。准确率可能没有vpsee的方法高。

  10. 剛試HYPERVISOR_INFO CPUID,在VMWare Workstation 6.5.1和QEMU 0.13.50 git spanshot 非 KVM 下沒有效,特此通知。

  11. s/spanshot/snapshot/;
    天氣冷了手不太靈活,抱歉。

  12. 测试了一下vmware的判断c程序,怎么报 Illegal instruction 错误啊,经检查 是CPUID(HYPERVISOR_INFO, &eax, &ebx, &ecx, &edx);这句的问题,请问是什么原因?环境 Red Hat Enterprise Linux AS release 4 (Nahant Update 6) vmware workstation 6.0

  13. 测试了下xen的结果报bare hardware…

  14. @rog
    hwclock 不好用啊,虚拟机也可以的,我在vm8上的RHEL6.2试过,不行。

  15. 在softlayer上gcc编译执行a.out之后提示
    Illegal instruction (core dumped)

  16. 有lspci 能看出来 的

  17. HVM 比较难判断 vpsee 提供的 C 程序不错,不过在 Debian / Ubuntu 上编译会报错,包含头文件要 #include 这样才行。在 Xen PV VPS 上报 HVM (可能 123Systems 的 Xen PV 不是完全 PV 的吧),在 Digital Ocean KVM 上直接 Illegal instruction (core dumped) 吐核了。还有改进的空间,欢迎 fork -> https://gist.github.com/terrywang/9031215

  18. @wang
    lspci一眼就看出来,赞

  19. 哪个C 代码 前面的两个include 作者少加了 吧 亲
    from linuxchina.net

  20. lscpu,咔嚓一眼就看到kvm了呀

发表评论