Linux kernel selftests are small tests used to execute individual code paths in the Linux kernel. KVM selftests are a crucial subset of these used to verify KVM virtualization features. They interact with the KVM API directly and QEMU isn’t required to create a VM.

In addition to the default KVM selftests under the “tools/testing/selftests/kvm” directory, a user may utilize the APIs from KVM selftests to create extra customized tests that can be used to simulate and reproduce KVM bugs, i.e. KVM SMM issue, and kvmclock drift during vCPU hotplug.

By default, KVM selftests are built as dynamic binaries which rely on external libraries to be loaded into memory at runtime. In this blog article, we demonstrate how to build KVM selftests as static binaries on Oracle Linux 8, on a VM in Oracle Cloud Infrastructure (OCI). We demonstrate how this static binary which is built with one version of glibc can still execute in environments containing an older glibc version.

Step 1. Create OCI VMs

For the purposes of this article we are using an Oracle Linux 8 instance in OCI with the VM.Standard2.4 shape.

Step 2. Configure yum and install packages

Once your instance is created, enable the yum repository ol8_codeready_builder to install the prerequisite packages.

$ sudo yum-config-manager --enable ol8_codeready_builder

$ cat /etc/yum.repos.d/oracle-linux-ol8.repo
... ...
[ol8_codeready_builder]
name=Oracle Linux 8 CodeReady Builder ($basearch) - Unsupported
baseurl=https://yum$ociregion.$ocidomain/repo/OracleLinux/OL8/codeready/builder/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1
... ...

Next install the required packages.

$ sudo yum install -y patch glibc-static gcc-toolset-11

Step 3. Configure gcc

In order to use gcc-11 we need to enable the gcc-toolset-11 software collection:

$ scl enable gcc-toolset-11 bash

Double check that the gcc version is 11.5.0.

$ gcc -v
... ...
gcc version 11.5.0 20240719 (Red Hat 11.5.0-2.0.1) (GCC)

To ensure this software collection is enabled permanently across logins, add the above scl command to /etc/profile.

Step 4. Download source code

We use linux-6.4 in this article. Download and extract.

$ wget https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.4.tar.xz

$ tar xvf linux-6.4.tar.xz

Step 5: Add “-static” CFLAGS

Apply the following patch to add CFLAGS “-static” in tools/testing/selftests/kvm/Makefile.

$ cat kvmselftest.patch
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 4761b768b..2474e65fb 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -203,7 +203,7 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
    -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \
    -I$(LINUX_TOOL_ARCH_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude \
    -I$(<D) -Iinclude/$(ARCH_DIR) -I ../rseq -I.. $(EXTRA_CFLAGS) \
-   $(KHDR_INCLUDES)
+   $(KHDR_INCLUDES) -static
 ifeq ($(ARCH),s390)
    CFLAGS += -march=z10
 endif


$ cd linux-6.4
$ patch -p1 < ../kvmselftest.patch

Step 6. Build KVM selftests

$ cd linux-6.4
$ make headers
$ cd tools/testing/selftests/kvm
$ make

We use kvm_page_table_test as an example in this article.

$ ls -l kvm_page_table_test
-rwxrwxr-x. 1 opc opc 3803272 Mar 18 23:01 kvm_page_table_test

$ ldd kvm_page_table_test
    not a dynamic executable

Step 7. Test

Copy kvm_page_table_test to an older Oracle Linux 7 environment, note how it executes successfully.

ol7$ ./kvm_page_table_test
Testing guest mode: PA-bits:ANY, VA-bits:48,  4K pages
Testing memory backing src type: anonymous
Testing memory backing src granularity: 0x1000
Testing memory size(aligned): 0x40000000
Guest physical test memory offset: 0x3fffbffff000
Host  virtual  test memory offset: 0x7f4d229be000
Number of testing vCPUs: 1
Started all vCPUs successfully
KVM_CREATE_MAPPINGS: total execution time: 1409.087522349s

KVM_UPDATE_MAPPINGS: total execution time: 1408.532079123s

KVM_ADJUST_MAPPINGS: total execution time: 1408.479546540s

If we skip Step 5 and don’t add the -static CFLAG, you will notice kvm_page_table_test fails to execute.

ol7$ ./kvm_page_table_test
./kvm_page_table_test: /lib64/libc.so.6: version `GLIBC_2.27' not found (required by ./kvm_page_table_test)

Summary

In this article we demonstrate how to build KVM selftests as a static binary on Oracle Linux 8 and how it can then be executed on older environments.