systemdにはコンテナやハイパーバイザの検出用関数detect_virtualization
が存在する。v230現在では、まずコンテナを判別するdetect_container
を実行して、判別できなければ仮想化環境を判別するdetect_vm
を実行する。
detect_container
OpenVZ, LXC, LXC (libvirt), Docker, RKT, systemd nspawnを判別できる。
- OpenVZ
-
/proc/vz
が存在して、/proc/bc
が存在しない- ルートコンテキストには両方存在する
-
- それ以外
- 自分がPID=1であれば、
container
という環境変数を調べる - PID!=1であれば、
/run/systemd/container
の中を調べる- PID=1のsystemdプロセスが当該ファイルを生成する
- それもなければ、PID=1のプロセスの
container
環境変数を調べる
- 自分がPID=1であれば、
detect_vm
KVM, QEMU, Bochs, Xen, UML, VMware, VirtualBox, Microsoft Azure, IBM z/VM, Parallels Desktopを判別できる。
systemdは仮想化環境を判別する方法をいくつか持っており、それらを順次実行していく。
detect_vm_dmi
DMIはDesktop Management Interfaceのことで、シリアル番号やBIOSのリビジョンといったハードウェア情報を取得するためのインタフェースである。Linuxでは、sysfsで以下のような情報が手に入る。
$ ls /sys/class/dmi/id/
bios_date board_asset_tag board_vendor chassis_serial chassis_version product_name product_version uevent
bios_vendor board_name board_version chassis_type modalias product_serial subsystem
bios_version board_serial chassis_asset_tag chassis_vendor power product_uuid sys_vendor
systemdは以下のDMIを順番に調べる。
/sys/class/dmi/id/product_name
/sys/class/dmi/id/sys_vendor
/sys/class/dmi/id/board_vendor
/sys/class/dmi/id/bios_vendor
最近のVMMだと、これらのファイルのいずれかに識別のための文字列が入っている。
- KVM
- QEMU
- VMware, VMW
- innotek GmbH (VirtualBox)
- Xen
- Bochs
- Parallels
detect_vm_cpuid
CPUIDの調べ方は後述するが、これもDMIと同様に設定されている文字列を元に仮想化環境を判別する。
- XenVMMXenVMM
- KVMKVMKVM
- VMwareVMware
- Microsoft Hv
detect_vm_xen
/proc/xen/capabilities
が存在しているかチェックする。とりあえず、ここでXenであると判別するが、後でDom0のチェックを行なう(後述)。
detect_vm_hypervisor
/sys/hypervisor/type
を調べてxen
と書かれていればXenと判別する。
detect_vm_device_tree
ARM, AArch64, PPC, PPC64の場合はデバイスツリーを調べる。
-
/proc/device-tree/hypervisor/compatible
が存在する場合-
linux,kvm
と書かれていればKVMと判別する -
xen
と書かれていればXenと判別する
-
- 存在しない場合
-
/proc/device-tree
のディレクトリを調べて、fw-cfg
というファイルが存在すればQEMUと判別する
-
detect_vm_uml
/proc/cpuinfo
に\nvendor_id\t: User Mode Linux\n
という文字列が含まれていればUMLと判別する。
detect_vm_zvm
s390の場合、/proc/sysinfo
のVM00 Control Program
というエントリを調べる。
-
z/VM
と書かれていればz/VMと判別する - そうでなければKVMと判別する
detect_vm_xen_dom0
もしこの段階でXenと判別されていた場合Dom0か否かを調べる。
/proc/xen/capabilities
の機能リストにcontrol_d
が存在していれば、Dom0だと判断し、仮想化環境ではないと判別する。
CPUIDの調べ方
ハイパーバイザ用のCPUIDについては、CPUID usage for interaction between Hypervisors and Linux. [LWN.net]に詳しい説明が書かれている。CPUID命令は、EAXレジスタに欲しい情報のIDを入れてCPUID命令を呼び出すと、情報毎に決められた特定のレジスタに情報が設定される (CPUID - Wikipedia, the free encyclopedia)。EAX=1がプロセッサ情報に対応し、EAXにプロセッサモデルやファミリ、EDXとECXにプロセッサの個々の機能が設定される。ECXの31ビット目はハイパーバイザ向けに予約されており、ハイパーバイザは1にセットして返すことになっている。ハイパーバイザが存在することがわかると、今度はEAX=0x40000000を入れてCPUID命令を呼ぶことで、ハイパーバイザ用ベンダIDを取得することができる。