From e24ad01eac520bc84c64ee09acb7fff77b101944 Mon Sep 17 00:00:00 2001 From: Luca Di Maio Date: Fri, 18 Sep 2026 10:53:35 +0200 Subject: [PATCH 1/5] fix(build): allow local builds to bypass the sccache wrapper Signed-off-by: Luca Di Maio --- hack/build/generate-docker-script.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hack/build/generate-docker-script.py b/hack/build/generate-docker-script.py index d6f9c5a..96d7629 100644 --- a/hack/build/generate-docker-script.py +++ b/hack/build/generate-docker-script.py @@ -222,6 +222,11 @@ def docker_compile( "-e", quoted("NVIDIA_MODULES_PATH=/build/override-nvidia-modules.tar.gz"), ] + if os.getenv("KERNEL_DISABLE_SCCACHE"): + compile_command += [ + "-e", + quoted("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"), + ] compile_command += [ '"$(cat %s)"' % staged_iidfile, "./hack/build/docker-build-internal.sh", From 0623cdfdfadc75c095d71000a8e019ac0c17d1e9 Mon Sep 17 00:00:00 2001 From: Luca Di Maio Date: Fri, 18 Sep 2026 10:56:44 +0200 Subject: [PATCH 2/5] feat(zone-tiny): add minimal kernel flavor Builds from tinyconfig plus an explicit allowlist rather than the arch defconfig, so only listed symbols ship and defconfig churn cannot leak in. verify-config.py gates the required/forbidden/subset contract before compiling. Signed-off-by: Luca Di Maio --- config.yaml | 7 + configs/x86_64/zone-tiny.config | 682 ++++++++++++++++++++++++ configs/x86_64/zone-tiny.forbidden.conf | 70 +++ configs/x86_64/zone-tiny.required.conf | 67 +++ configs/x86_64/zone-tiny.whitelist.conf | 15 + hack/build/common.sh | 37 +- hack/build/verify-config.py | 103 ++++ 7 files changed, 979 insertions(+), 2 deletions(-) create mode 100644 configs/x86_64/zone-tiny.config create mode 100644 configs/x86_64/zone-tiny.forbidden.conf create mode 100644 configs/x86_64/zone-tiny.required.conf create mode 100644 configs/x86_64/zone-tiny.whitelist.conf create mode 100755 hack/build/verify-config.py diff --git a/config.yaml b/config.yaml index 9d74d33..cd02f6c 100644 --- a/config.yaml +++ b/config.yaml @@ -18,6 +18,13 @@ flavors: - x86_64 constraints: lower: '6.1' +- name: zone-tiny + # Experimental minimal microVM kernel: a tinyconfig base + an explicit allowlist + # (configs/x86_64/zone-tiny.config), gated by zone-tiny.{required,forbidden}.conf. + architectures: + - x86_64 + constraints: + lower: '6.18' - name: zone-amdgpu constraints: lower: '6.1' diff --git a/configs/x86_64/zone-tiny.config b/configs/x86_64/zone-tiny.config new file mode 100644 index 0000000..6a5f374 --- /dev/null +++ b/configs/x86_64/zone-tiny.config @@ -0,0 +1,682 @@ +# +# Edera zone-tiny (minimal microVM) kernel config - allowlist (x86_64) +# +# Resolved on a tinyconfig base (see hack/build/common.sh): only what is listed +# here ships, so upstream defconfig churn cannot leak in. One kernel boots under +# both KVM (Cloud Hypervisor: PVH, ttyS0, virtio-PCI, virtio-mem, ivshmem/vsock +# IDM) and Xen (PV/PVH: hvc0, the xen frontends, xenbus-channel IDM). The +# criteria in zone-tiny.{required,forbidden}.conf gate every build. Physical NIC/RDMA +# drivers are not here; the full "zone" flavor keeps them. +# +# ---- core plumbing (tinyconfig lacks these) ---- +CONFIG_SMP=y +CONFIG_MULTIUSER=y +CONFIG_PRINTK=y +CONFIG_PRINTK_TIME=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_ELF_CORE=y +CONFIG_DEBUG_FS=y +CONFIG_POSIX_TIMERS=y +CONFIG_POSIX_MQUEUE=y +CONFIG_SYSVIPC=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_MEMBARRIER=y +CONFIG_RSEQ=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_FHANDLE=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_NO_HZ_IDLE=y +CONFIG_EXPERT=y +CONFIG_KEYS=y +CONFIG_JUMP_LABEL=y +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_BLOCK=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_GZIP=y +CONFIG_RD_ZSTD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_TTY=y +CONFIG_UNIX98_PTYS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y + +# ---- namespaces + cgroups (containers) ---- +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_TIME_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_CGROUP_NET_CLASSID=y +CONFIG_SWAP=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y + +# ---- console / boot (x86) ---- +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y +CONFIG_VIRTIO_CONSOLE=y + +# ---- x86 guest platform ---- +CONFIG_X86_X2APIC=y +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_KVM_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_PVH=y +CONFIG_ACPI=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MMCONFIG=y +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +CONFIG_CPU_MITIGATIONS=y + +# ---- virtio (KVM / Cloud-Hypervisor / Firecracker) ---- +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_FS=y +CONFIG_VIRTIO_MEM=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_SCSI=y +CONFIG_SCSI_LOWLEVEL=y +CONFIG_SCSI_VIRTIO=y +CONFIG_BLK_DEV_SD=y +# pvpanic: host detects guest panic (PCI + MMIO transports). +CONFIG_PVPANIC=y +CONFIG_PVPANIC_PCI=y +CONFIG_PVPANIC_MMIO=y + +# ---- Xen guest (PV/PVH domU) ---- +CONFIG_XEN=y +CONFIG_XEN_PV=y +CONFIG_XEN_PVH=y +CONFIG_XEN_PVHVM_GUEST=y +CONFIG_XEN_512GB=y +CONFIG_XEN_BLKDEV_FRONTEND=y +CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_SCSI_FRONTEND=y +CONFIG_XEN_PCIDEV_FRONTEND=y +CONFIG_NET_9P_XEN=y +CONFIG_XEN_BALLOON=y +CONFIG_XEN_BALLOON_MEMORY_HOTPLUG=y +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XEN_DEV_EVTCHN=y +CONFIG_XENFS=y +CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_SYS_HYPERVISOR=y +CONFIG_XEN_GNTDEV=y +CONFIG_XEN_GRANT_DEV_ALLOC=y +CONFIG_XEN_GRANT_DMA_ALLOC=y +CONFIG_XEN_PVCALLS_FRONTEND=y +CONFIG_XEN_PRIVCMD=y +CONFIG_XEN_PRIVCMD_EVENTFD=y +CONFIG_XEN_VIRTIO=y +CONFIG_XEN_IOMMU=y +CONFIG_PARAVIRT_TIME_ACCOUNTING=y + +# ---- storage / filesystems ---- +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_EROFS_FS=y +CONFIG_EROFS_FS_ZIP=y +CONFIG_OVERLAY_FS=y +CONFIG_FUSE_FS=y +CONFIG_9P_FS=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ISO9660_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_DAX=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_FS_VERITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y + +# ---- networking ---- +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IPV6=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +CONFIG_VETH=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_ACT_BPF=y +CONFIG_DNS_RESOLVER=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y +CONFIG_XFRM_USER=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_NAT=y +CONFIG_NF_TABLES=y +CONFIG_NF_TABLES_INET=y +CONFIG_NFT_CT=y +CONFIG_NFT_NAT=y +CONFIG_NFT_MASQ=y +CONFIG_NFT_COMPAT=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP_SET=y + +# ---- IDM (inter-domain messaging): vsock today, ivshmem+vsock next ---- +CONFIG_VFIO=y +CONFIG_VFIO_PCI=y +CONFIG_VIRTIO_IOMMU=y +CONFIG_VIRTIO_VFIO_PCI=y + +# ---- security / LSM ---- +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PATH=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_SECURITY_LOCKDOWN_LSM=y +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_INTEGRITY=y +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor" +CONFIG_AUDIT=y + +# ---- hardening ---- +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_INIT_STACK_ALL_ZERO=y +CONFIG_ZERO_CALL_USED_REGS=y +CONFIG_RANDOMIZE_KSTACK_OFFSET=y +CONFIG_VMAP_STACK=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_LIST_HARDENED=y +CONFIG_SLAB_FREELIST_RANDOM=y +# CONFIG_SLUB_TINY is not set + +# ---- crypto (LUKS, module sig, 9p, general) ---- +CONFIG_CRYPTO=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_AES_NI_INTEL=y +CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_CRYPTO_LZ4=y + +# ---- module signing ---- +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_ALL=y +CONFIG_MODULE_SIG_SHA256=y +CONFIG_MODULE_SIG_KEY_TYPE_RSA=y +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_PKCS7_MESSAGE_PARSER=y +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SECONDARY_TRUSTED_KEYRING=y + +# ---- observability (falco eBPF) ---- +CONFIG_BPF=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_DEBUG_INFO_BTF_MODULES=y +CONFIG_DEBUG_INFO_COMPRESSED_ZSTD=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_KPROBES=y +CONFIG_KPROBE_EVENTS=y +CONFIG_UPROBE_EVENTS=y +CONFIG_PERF_EVENTS=y + +# ---- memory / vNUMA / balloon ---- +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_ZONE_DEVICE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_NUMA=y +CONFIG_NUMA_BALANCING=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_ZRAM=y +CONFIG_ZRAM_BACKEND_ZSTD=y +CONFIG_ZRAM_DEF_COMP_ZSTD=y +CONFIG_MIGRATION=y +CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y +CONFIG_SECRETMEM=y +CONFIG_HUGETLBFS=y + +# ---- gate symbols the empirical tinyconfig resolve proved are needed ---- +# (each gates a leaf above that otherwise silently drops on an allnoconfig base) +CONFIG_MISC_FILESYSTEMS=y +CONFIG_COREDUMP=y +CONFIG_NET_CLS_ACT=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_BPF_EVENTS=y + +# ---- explicit disables: default-y menuconfigs and ACPI/Xen cascades that a +# minimal base still turns on. The forbidden manifest enforces these stay off; +# where a symbol is pulled by a `select`, its selector is disabled instead. ---- +# CONFIG_SOUND is not set +# CONFIG_WIRELESS is not set +# CONFIG_WLAN is not set +# CONFIG_RFKILL is not set +# CONFIG_NFC is not set +# CONFIG_BT is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_DRM is not set +# CONFIG_FB is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_AGP is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +# CONFIG_PCCARD is not set +# CONFIG_FIREWIRE is not set +# CONFIG_IIO is not set +# CONFIG_STAGING is not set +# CONFIG_X86_PLATFORM_DEVICES is not set +# CONFIG_RC_CORE is not set +# CONFIG_HWMON is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# POWER_SUPPLY is selected by ACPI battery/AC and the AMD P-state driver; CPU_FREQ +# by the ITMT scheduler feature (meaningless with virtual CPUs). Disable the +# selectors, not the targets. THERMAL core stays on (pulled by ACPI_PROCESSOR, +# which gives the guest ACPI cpuidle); only the thermal-zone drivers are off. +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_X86_AMD_PSTATE is not set +# CONFIG_SCHED_MC_PRIO is not set +# dom0/backend features (the zone is frontend-only) +# CONFIG_XEN_DOM0 is not set +# CONFIG_XEN_BACKEND is not set +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_EGRESS=y +CONFIG_NETFILTER_NETLINK_HOOK=y +CONFIG_NETFILTER_NETLINK_ACCT=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NETFILTER_NETLINK_OSF=y +CONFIG_NF_LOG_SYSLOG=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=y +CONFIG_NFT_CONNLIMIT=y +CONFIG_NFT_LOG=y +CONFIG_NFT_LIMIT=y +CONFIG_NFT_REDIR=y +CONFIG_NFT_TUNNEL=y +CONFIG_NFT_QUEUE=y +CONFIG_NFT_QUOTA=y +CONFIG_NFT_REJECT=y +CONFIG_NFT_HASH=y +CONFIG_NFT_SOCKET=y +CONFIG_NFT_OSF=y +CONFIG_NFT_TPROXY=y +CONFIG_NFT_SYNPROXY=y +CONFIG_NF_DUP_NETDEV=y +CONFIG_NFT_DUP_NETDEV=y +CONFIG_NFT_FWD_NETDEV=y +CONFIG_NFT_REJECT_NETDEV=y +CONFIG_NF_FLOW_TABLE_INET=y +CONFIG_NF_FLOW_TABLE=y +CONFIG_NF_FLOW_TABLE_PROCFS=y +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y +CONFIG_NETFILTER_XT_SET=y +CONFIG_NETFILTER_XT_TARGET_AUDIT=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y +CONFIG_NETFILTER_XT_TARGET_DSCP=y +CONFIG_NETFILTER_XT_TARGET_HL=y +CONFIG_NETFILTER_XT_TARGET_HMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_RATEEST=y +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=y +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_CGROUP=y +CONFIG_NETFILTER_XT_MATCH_CLUSTER=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_CPU=y +CONFIG_NETFILTER_XT_MATCH_DCCP=y +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ECN=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPCOMP=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_L2TP=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_NFACCT=y +CONFIG_NETFILTER_XT_MATCH_OSF=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_RATEEST=y +CONFIG_NETFILTER_XT_MATCH_REALM=y +CONFIG_NETFILTER_XT_MATCH_RECENT=y +CONFIG_NETFILTER_XT_MATCH_SCTP=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_IP_SET_MAX=256 +CONFIG_NF_SOCKET_IPV4=y +CONFIG_NF_TPROXY_IPV4=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_DUP_IPV4=y +CONFIG_NF_LOG_ARP=y +CONFIG_NF_LOG_IPV4=y +CONFIG_NF_REJECT_IPV4=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_SYNPROXY=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_NF_TPROXY_IPV6=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_DUP_IPV6=y +CONFIG_NF_REJECT_IPV6=y +CONFIG_NF_LOG_IPV6=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_MATCH_MH=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_SYNPROXY=y +CONFIG_NF_CONNTRACK_BRIDGE=y +# Build identity + performance (tinyconfig sets -Os; override to performance) +CONFIG_WERROR=y +CONFIG_LOCALVERSION="-edera-zone" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_BUILD_SALT="" +CONFIG_KERNEL_ZSTD=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_NR_CPUS=256 + +# Module signing key path + trusted keys +CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" +CONFIG_SYSTEM_TRUSTED_KEYS="" + +# Crypto: RNG (DRBG + jitterentropy), IPsec IV generators, key exchange, +# virtio-crypto offload, and the AEAD/mode set LUKS and the module verifier use. +CONFIG_CRYPTO_DH=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y + +# Security / hardening carried by the current kernel +CONFIG_X86_KERNEL_IBT=y +CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y +CONFIG_STRICT_DEVMEM=y +CONFIG_DEVMEM=y +CONFIG_IO_STRICT_DEVMEM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y + +# Filesystem extras: fs-verity signatures (attestation), 9p cache, erofs codecs +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_9P_FSCACHE=y +# Operational + security essentials tinyconfig drops that the current kernel carries. +CONFIG_BUG=y +CONFIG_FSCACHE=y +CONFIG_CACHESTAT_SYSCALL=y +CONFIG_ALLOW_DEV_COREDUMP=y + +# BPF hardening (force JIT, no interpreter; unpriv off by default) +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_BPF_UNPRIV_DEFAULT_OFF=y + +# x86 hardening the current kernel sets +CONFIG_X86_UMIP=y +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y + +# Block IO scheduler + cgroup IO control (container IO limits under k8s/docker) +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_CGROUP_IOLATENCY=y +CONFIG_BLK_CGROUP_IOPRIO=y + +# Extra cgroup controllers container runtimes use +CONFIG_CGROUP_MISC=y + +# Guest cpuidle: halt to yield the pCPU to the host (haltpoll is KVM-optimal) +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_GOV_TEO=y +CONFIG_HALTPOLL_CPUIDLE=y +# Final operational tail the current kernel carries and a zone benefits from. +# DMI/SMBIOS (cloud-init reads instance metadata), qemu fw_cfg (carried patch), +# firmware loader, dma-buf (xen gntdev-dmabuf / virtio), common hashes, hang +# detection, and a few file/notify/compat bits. +CONFIG_DMI=y +CONFIG_DMIID=y +CONFIG_FW_CFG_SYSFS=y +CONFIG_FW_CFG_SYSFS_CMDLINE=y +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_COMPRESS=y +CONFIG_FW_LOADER_COMPRESS_XZ=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_DNOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_DEVTMPFS_SAFE=y +CONFIG_FSCACHE_STATS=y +CONFIG_EROFS_FS_PCPU_KTHREAD=y +CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y + +# Common hash/compat algorithms various userspace and kernel consumers expect +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_XXHASH=y +CONFIG_CRYPTO_LZ4HC=y + +# Production hang/lockup detection (catch a wedged zone) +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_MAGIC_SYSRQ=y + +# TCP: keep cubic available (BBR is already enabled in the base fragment) +CONFIG_TCP_CONG_CUBIC=y + +# ---- match zone's disables that a tinyconfig base leaks back on: PS/2 input, +# VGA console, non-AMD/Intel CPU vendors, and the one stray thermal module ---- +# CONFIG_CPU_SUP_HYGON is not set +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_CPU_SUP_ZHAOXIN is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_MOUSE_PS2 is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set + +# ---- policy: match zone (1000 Hz tick, no vsyscall page, THP opt-in) ---- +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_LEGACY_VSYSCALL_NONE=y +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y + +# needed so the CPU_SUP_* vendor disables above actually take effect +CONFIG_PROCESSOR_SELECT=y + +# ---- align remaining policy choices to zone ---- +# CONFIG_FUNCTION_GRAPH_TRACER is not set +CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y +CONFIG_SQUASHFS_FILE_DIRECT=y + +# ---- minimization: non-hypervisor leaves cut from the allowlist ---- +# Each is present in the full `zone` flavor; none sits on a Xen or KVM boot / IDM +# path. In order: no 32-bit userspace (the COMPAT chain follows); host-side page +# dedup + attack surface; zswap is redundant once zram is the swap device; +# mq-deadline suffices for virtio-blk and xen-blkfront; proc-connector netlink is +# unused; pr_debug() call-site tables; virtio-crypto offload is not wired up; the +# extra EROFS codecs (images are zstd/lz4). forbidden.conf keeps these off. +# CONFIG_IA32_EMULATION is not set +# CONFIG_KSM is not set +# CONFIG_ZSWAP is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_CONNECTOR is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_EROFS_FS_ZIP_LZMA is not set +# CONFIG_EROFS_FS_ZIP_DEFLATE is not set diff --git a/configs/x86_64/zone-tiny.forbidden.conf b/configs/x86_64/zone-tiny.forbidden.conf new file mode 100644 index 0000000..f26f9c2 --- /dev/null +++ b/configs/x86_64/zone-tiny.forbidden.conf @@ -0,0 +1,70 @@ +# Zone kernel FORBIDDEN symbols (x86_64): things a zone must never ship. On the +# tinyconfig allowlist base most are off by default, so this is the guard against a +# fragment or a future upstream default pulling them back. The build fails if any +# resolves to =y or =m. See hack/build/verify-config.py. + +# Hardware classes a virtio/xen guest does not have +CONFIG_SOUND +CONFIG_WIRELESS +CONFIG_WLAN +CONFIG_BT +CONFIG_USB_SUPPORT +CONFIG_MEDIA_SUPPORT +CONFIG_DRM +CONFIG_FB +CONFIG_HID_SUPPORT +CONFIG_ATA +CONFIG_SATA_HOST +CONFIG_IPMI_HANDLER + +# Power / boot features a zone does not use (dom0/host owns them). THERMAL is not +# forbidden: its core is pulled on by ACPI_PROCESSOR (which provides guest cpuidle), +# and only the thermal-zone drivers are disabled in the fragment. +CONFIG_POWER_SUPPLY +CONFIG_CPU_FREQ +CONFIG_HIBERNATION +CONFIG_SUSPEND +CONFIG_KEXEC +CONFIG_CRASH_DUMP + +# dom0-only Xen features (the zone is frontend-only) +CONFIG_XEN_DOM0 +CONFIG_XEN_BACKEND + +# Exotic ciphers never selected by LUKS/dm-crypt (AES is the default) +CONFIG_CRYPTO_ARIA +CONFIG_CRYPTO_SM4 +CONFIG_CRYPTO_CAMELLIA_X86_64 +CONFIG_CRYPTO_SERPENT +CONFIG_CRYPTO_TWOFISH_X86_64 +CONFIG_CRYPTO_CAST5 +CONFIG_CRYPTO_CAST6 +CONFIG_CRYPTO_BLOWFISH_X86_64 + +# Headless workload VM: no VGA console, PS/2 input, rfkill/nfc, non-AMD/Intel CPU +# support, or CPU-package thermal driver. +CONFIG_VGA_CONSOLE +CONFIG_VGA_ARB +CONFIG_SERIO +CONFIG_KEYBOARD_ATKBD +CONFIG_MOUSE_PS2 +CONFIG_RFKILL +CONFIG_NFC +CONFIG_CPU_SUP_HYGON +CONFIG_CPU_SUP_CENTAUR +CONFIG_CPU_SUP_ZHAOXIN +CONFIG_X86_PKG_TEMP_THERMAL + +# Minimization leaves: present in the full `zone` flavor, deliberately off here, +# none on a Xen/KVM boot or IDM path. Guards the cut against upstream default churn +# or a select pulling them back. +CONFIG_IA32_EMULATION +CONFIG_KSM +CONFIG_ZSWAP +CONFIG_IOSCHED_BFQ +CONFIG_BFQ_GROUP_IOSCHED +CONFIG_CONNECTOR +CONFIG_DYNAMIC_DEBUG +CONFIG_CRYPTO_DEV_VIRTIO +CONFIG_EROFS_FS_ZIP_LZMA +CONFIG_EROFS_FS_ZIP_DEFLATE diff --git a/configs/x86_64/zone-tiny.required.conf b/configs/x86_64/zone-tiny.required.conf new file mode 100644 index 0000000..bb74e7e --- /dev/null +++ b/configs/x86_64/zone-tiny.required.conf @@ -0,0 +1,67 @@ +# Zone kernel REQUIRED symbols (x86_64): the boot / I/O / security / observability +# contract a zone must satisfy under both KVM (Cloud Hypervisor) and Xen. The build +# fails if any of these does not resolve to =y or =m. See hack/build/verify-config.py. + +# Boot / console: KVM ttyS0 (8250), Xen hvc0, PVH ELF boot, pvpanic +CONFIG_PVH +CONFIG_SERIAL_8250_CONSOLE +CONFIG_HVC_XEN +CONFIG_PVPANIC +CONFIG_BINFMT_ELF +CONFIG_BINFMT_MISC +CONFIG_TTY +CONFIG_DEVTMPFS +CONFIG_DEBUG_FS +CONFIG_SECURITYFS +CONFIG_BLK_DEV_INITRD + +# Storage a zone actually uses +CONFIG_VIRTIO_BLK +CONFIG_XEN_BLKDEV_FRONTEND +CONFIG_VIRTIO_FS +CONFIG_EXT4_FS +CONFIG_SQUASHFS +CONFIG_EROFS_FS +CONFIG_OVERLAY_FS +CONFIG_9P_FS +CONFIG_NET_9P_XEN +CONFIG_NFS_FS +CONFIG_ISO9660_FS +CONFIG_BLK_DEV_DM + +# Networking +CONFIG_INET +CONFIG_VIRTIO_NET +CONFIG_XEN_NETDEV_FRONTEND +CONFIG_BRIDGE +CONFIG_VETH + +# IDM: KVM vsock + ivshmem-via-VFIO_PCI; Xen channels via userspace +CONFIG_VSOCKETS +CONFIG_VIRTIO_VSOCKETS +CONFIG_VFIO_PCI +CONFIG_VIRTIO_IOMMU +CONFIG_XEN_PRIVCMD +CONFIG_XEN_GNTDEV +CONFIG_XEN_DEV_EVTCHN + +# Memory / balloon: KVM virtio-mem + virtio-balloon, Xen xen-balloon +CONFIG_VIRTIO_MEM +CONFIG_VIRTIO_BALLOON +CONFIG_MEMORY_HOTPLUG +CONFIG_XEN_BALLOON +CONFIG_ZONE_DEVICE + +# Isolation / security / observability +CONFIG_CGROUPS +CONFIG_NAMESPACES +CONFIG_USER_NS +CONFIG_SECCOMP +CONFIG_SECURITY_APPARMOR +CONFIG_SECURITY_SELINUX +CONFIG_SECURITY_LANDLOCK +CONFIG_BPF_SYSCALL +CONFIG_BPF_EVENTS +CONFIG_DEBUG_INFO_BTF +CONFIG_KPROBES +CONFIG_FUNCTION_TRACER diff --git a/configs/x86_64/zone-tiny.whitelist.conf b/configs/x86_64/zone-tiny.whitelist.conf new file mode 100644 index 0000000..a15e1a8 --- /dev/null +++ b/configs/x86_64/zone-tiny.whitelist.conf @@ -0,0 +1,15 @@ +# Zone kernel WHITELIST (x86_64): symbols exempt from the stickiness and forbidden +# checks because they can legitimately not resolve in a given tree. See +# hack/build/verify-config.py. + +# Added by Edera patches; absent from a vanilla tree but present in the patched build. +CONFIG_XEN_IOMMU + +# DEBUG_INFO_BTF and GCC_PLUGINS need pahole / gcc-plugin headers at configure time. +# They resolve correctly in the buildenv (which has them) but not in a toolchain-less +# resolve, so exempt them from stickiness while the required manifest still enforces +# DEBUG_INFO_BTF against the in-build .config. +CONFIG_GCC_PLUGINS + +# Toolchain-gated: the compression choice degrades to NONE without -gz=zstd support. +CONFIG_DEBUG_INFO_COMPRESSED_ZSTD diff --git a/hack/build/common.sh b/hack/build/common.sh index c5c27a5..0ad6c3d 100644 --- a/hack/build/common.sh +++ b/hack/build/common.sh @@ -129,6 +129,17 @@ KCONFIG_FRAGMENT_DEST="${KERNEL_SRC}/arch/${KERNEL_ARCH_STANDARD}/configs/" # Copy out our custom kconfig - if we are building for a -, merge the variant fragment with the flavor baseconfig # by copying the fragment into the kernel src tree and letting the kernel's `make` merge them case "${KERNEL_FLAVOR}" in +zone-tiny) + # Standalone minimal flavor with its own complete config (not a flavor-variant, + # despite the dash). Resolved on a tinyconfig base further below. + BASE_FLAVOR_CONFIG="${KERNEL_DIR}/configs/${TARGET_ARCH_STANDARD}/${KERNEL_FLAVOR}.config" + if [ ! -f "${BASE_FLAVOR_CONFIG}" ]; then + echo "ERROR: kernel flavor base config file not found for ${TARGET_ARCH_STANDARD}: ${BASE_FLAVOR_CONFIG}" >&2 + exit 1 + fi + cp "${BASE_FLAVOR_CONFIG}" "${KCONFIG_FRAGMENT_DEST}" + MAKE_CONFIG_FRAGMENTS="${KERNEL_FLAVOR}.config" + ;; *-*) # Looks like we are dealing with -.config, versus .config, so we have 2 fragments FLAVOR=$(echo "${KERNEL_FLAVOR}" | cut -d'-' -f1) @@ -173,8 +184,30 @@ case "${KERNEL_FLAVOR}" in ;; esac -# shellcheck disable=SC2086 -make -C "${KERNEL_SRC}" O="${KERNEL_OBJ}" ARCH="${TARGET_ARCH_KERNEL}" "${CROSS_COMPILE_MAKE}" olddefconfig $MAKE_CONFIG_FRAGMENTS +# zone-tiny is the experimental minimal flavor: a tinyconfig base plus its own +# allowlist, so only what it lists ships and upstream defconfig churn cannot leak +# in. It is gated by its criteria manifests before the expensive compile. Every +# other flavor keeps the original arch-defconfig path, unchanged. +case "${KERNEL_FLAVOR}" in +zone-tiny) + make -C "${KERNEL_SRC}" O="${KERNEL_OBJ}" ARCH="${TARGET_ARCH_KERNEL}" "${CROSS_COMPILE_MAKE}" tinyconfig + # shellcheck disable=SC2086 + make -C "${KERNEL_SRC}" O="${KERNEL_OBJ}" ARCH="${TARGET_ARCH_KERNEL}" "${CROSS_COMPILE_MAKE}" $MAKE_CONFIG_FRAGMENTS + # Runs on the patched tree with the real toolchain, so patched-in and + # toolchain-gated symbols (XEN_IOMMU, DEBUG_INFO_BTF via pahole) resolve. + CRIT_DIR="${KERNEL_DIR}/configs/${TARGET_ARCH_STANDARD}" + uv run "${KERNEL_DIR}/hack/build/verify-config.py" \ + --config "${KERNEL_OBJ}/.config" \ + --whitelist "${CRIT_DIR}/zone-tiny.whitelist.conf" \ + --fragment "${BASE_FLAVOR_CONFIG}" \ + --required "${CRIT_DIR}/zone-tiny.required.conf" \ + --forbidden "${CRIT_DIR}/zone-tiny.forbidden.conf" + ;; +*) + # shellcheck disable=SC2086 + make -C "${KERNEL_SRC}" O="${KERNEL_OBJ}" ARCH="${TARGET_ARCH_KERNEL}" "${CROSS_COMPILE_MAKE}" olddefconfig $MAKE_CONFIG_FRAGMENTS + ;; +esac # shellcheck disable=SC2034 IMAGE_TARGET="bzImage" diff --git a/hack/build/verify-config.py b/hack/build/verify-config.py new file mode 100755 index 0000000..e08426a --- /dev/null +++ b/hack/build/verify-config.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Gate a resolved kernel .config against explicit zone criteria. + +Three checks, all of which fail the build on violation: + + 1. stickiness - every symbol a fragment requests resolves to that value + 2. required - every symbol in a required manifest is =y or =m + 3. forbidden - every symbol in a forbidden manifest is absent or 'n' + +Symbols listed in a whitelist are exempt from the stickiness and forbidden checks: +patched-in symbols (absent from a vanilla tree) or toolchain-gated symbols +(DEBUG_INFO_BTF needs pahole, GCC_PLUGINS needs plugin headers) that can legitimately +not resolve in a given tree. + +This must run against the fully-resolved .config of the patched tree with the real +toolchain, i.e. after `make olddefconfig` in prepare.sh, so those symbols resolve. + +Usage: + verify-config.py --config <.config> [--whitelist ] + [--fragment ...] [--required ...] [--forbidden ...] +""" + +import argparse +import re +import sys + +SET = re.compile(r"^(CONFIG_[A-Za-z0-9_]+)=(.*)$") +NOTSET = re.compile(r"^# (CONFIG_[A-Za-z0-9_]+) is not set$") + + +def parse_config(path: str) -> dict[str, str]: + """Parse a .config or fragment into {symbol: value}; 'n' for 'is not set'.""" + values: dict[str, str] = {} + with open(path) as handle: + for line in handle: + line = line.rstrip("\n") + match = SET.match(line) + if match: + values[match.group(1)] = match.group(2) + continue + match = NOTSET.match(line) + if match: + values[match.group(1)] = "n" + return values + + +def parse_list(path: str) -> list[str]: + """Read a manifest of one CONFIG symbol per line; ignore blanks and comments.""" + out: list[str] = [] + with open(path) as handle: + for line in handle: + token = line.strip() + if token and not token.startswith("#"): + out.append(token.split("=")[0] if "=" in token else token) + return out + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--config", required=True) + parser.add_argument("--whitelist") + parser.add_argument("--fragment", action="append", default=[]) + parser.add_argument("--required", action="append", default=[]) + parser.add_argument("--forbidden", action="append", default=[]) + args = parser.parse_args() + + resolved = parse_config(args.config) + whitelist = set(parse_list(args.whitelist)) if args.whitelist else set() + fails: list[str] = [] + + for fragment in args.fragment: + for symbol, want in parse_config(fragment).items(): + if symbol in whitelist: + continue + have = resolved.get(symbol) # None: absent (off / unmet deps / unknown) + if want in ("y", "m") and (have is None or have == "n"): + fails.append(f"STICK {symbol}: asked {want}, resolved {have or 'ABSENT'}") + elif want == "n" and have in ("y", "m"): + fails.append(f"STICK {symbol}: asked n, resolved {have}") + elif want not in ("y", "m", "n") and have is not None and have != want: + fails.append(f"STICK {symbol}: asked {want}, resolved {have}") + + for manifest in args.required: + for symbol in parse_list(manifest): + if resolved.get(symbol) not in ("y", "m"): + got = resolved.get(symbol) or "ABSENT" + fails.append(f"REQ {symbol}: must be y/m, resolved {got}") + + for manifest in args.forbidden: + for symbol in parse_list(manifest): + if symbol not in whitelist and resolved.get(symbol) in ("y", "m"): + fails.append(f"FORBID {symbol}: must be off, resolved {resolved[symbol]}") + + if fails: + print(f"verify-config: FAIL ({len(fails)} violations):", file=sys.stderr) + for fail in sorted(fails): + print(" " + fail, file=sys.stderr) + sys.exit(1) + print("verify-config: PASS") + + +if __name__ == "__main__": + main() From e28fbd527f5229855ea93c6afd4e77db6ef76bee Mon Sep 17 00:00:00 2001 From: Luca Di Maio Date: Fri, 18 Sep 2026 10:57:15 +0200 Subject: [PATCH 3/5] chore(bench): add kernel size/boot benchmark scripts Signed-off-by: Luca Di Maio --- hack/bench/compare-kernel-size.sh | 65 ++++++++++ hack/bench/measure-boot-time.sh | 196 ++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100755 hack/bench/compare-kernel-size.sh create mode 100755 hack/bench/measure-boot-time.sh diff --git a/hack/bench/compare-kernel-size.sh b/hack/bench/compare-kernel-size.sh new file mode 100755 index 0000000..4497ec6 --- /dev/null +++ b/hack/bench/compare-kernel-size.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# +# Compare the OCI kernel payload size across flavors: bzImage (kernel) + config.gz +# + addons.squashfs (modules) + metadata. Builds each flavor and reads the repo's +# target/, which docker-build.sh bind-mounts, so no push/pull. Sizes are ~= the +# registry pull size (kernel, squashfs, and config.gz are already compressed). +# +# Lives in hack/bench/; the repo root is derived from this script's location, so it +# runs from any working directory. Needs docker (buildx). +# +# Usage: hack/bench/compare-kernel-size.sh # zone vs zone-tiny, 6.18 +# FLAVORS="zone zone-tiny" SERIES=6.18 hack/bench/compare-kernel-size.sh +set -euo pipefail + +BENCH_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_REPO="${KERNEL_REPO:-$(cd -- "$BENCH_DIR/../.." && pwd)}" +ARCH="${ARCH:-x86_64}" +SERIES="${SERIES:-6.18}" +FLAVORS="${FLAVORS:-zone zone-tiny}" +REGISTRY="${REGISTRY:-127.0.0.1:5000}" # build target, so we never touch ghcr +REG_NAME="${REG_NAME:-edera-local-registry}" +# no sccache backend locally, and its wrapper can fail the kernel assembler probe +export KERNEL_DISABLE_SCCACHE="${KERNEL_DISABLE_SCCACHE-1}" + +cd "$KERNEL_REPO" +mb() { awk -v b="${1:-0}" 'BEGIN { printf "%.3f", b / 1048576 }'; } +fsize() { stat -c %s "$1" 2>/dev/null || echo 0; } + +# local registry so a publish flavor build doesn't try to reach ghcr +docker container inspect "$REG_NAME" >/dev/null 2>&1 || + docker run -d --name "$REG_NAME" --restart=unless-stopped \ + -p 127.0.0.1:5000:5000 docker.io/library/registry:2 >/dev/null + +cp config.yaml config.yaml.sizebak +trap 'mv -f "$KERNEL_REPO/config.yaml.sizebak" "$KERNEL_REPO/config.yaml" 2>/dev/null || true' EXIT +sed -i "s|^imageNameFormat:.*|imageNameFormat: \"${REGISTRY}/edera-dev/[image]:[tag]\"|" config.yaml + +printf '\n%-12s %10s %10s %9s %9s %11s\n' FLAVOR KERNEL ADDONS CONFIG META 'TOTAL(MB)' +printf -- '---------------------------------------------------------------------\n' +declare -A TOT +for f in $FLAVORS; do + docker buildx rm edera >/dev/null 2>&1 || true + if ! KERNEL_ARCHITECTURES="$ARCH" ./hack/build/docker-build.sh \ + "stable:flavor=${f};series=${SERIES}" >"/tmp/ksize-${f}.log" 2>&1; then + printf '%-12s BUILD FAILED (see /tmp/ksize-%s.log)\n' "$f" "$f" + continue + fi + k=$(fsize target/kernel) + a=$(fsize target/addons.squashfs) + c=$(fsize target/config.gz) + m=$(fsize target/metadata) + t=$((k + a + c + m)) + TOT[$f]=$t + printf '%-12s %10s %10s %9s %9s %11s\n' \ + "$f" "$(mb "$k")" "$(mb "$a")" "$(mb "$c")" "$(mb "$m")" "$(mb "$t")" +done + +# shellcheck disable=SC2086 +set -- $FLAVORS +if [ "$#" -eq 2 ] && [ -n "${TOT[$1]:-}" ] && [ -n "${TOT[$2]:-}" ]; then + d=$((TOT[$1] - TOT[$2])) + base=$((TOT[$1] > 0 ? TOT[$1] : 1)) + printf '\ndelta %s -> %s: %s MB smaller (%d%%)\n' \ + "$1" "$2" "$(mb "$d")" "$((d * 100 / base))" +fi diff --git a/hack/bench/measure-boot-time.sh b/hack/bench/measure-boot-time.sh new file mode 100755 index 0000000..7b06417 --- /dev/null +++ b/hack/bench/measure-boot-time.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env bash +# +# Measure zone kernel boot time under Cloud Hypervisor (the real KVM path). Builds +# each flavor (zone, zone-tiny) once and caches the bzImage under KCACHE; re-runs +# reuse a valid cached kernel (REBUILD=1 forces a rebuild). Each kernel is +# PVH-booted by cloud-hypervisor with a minimal busybox initramfs that powers off +# immediately; hyperfine benchmarks the VM-boot wall-clock (warmup + mean/stddev + +# an N-times-faster comparison), and one extra boot samples in-guest /proc/uptime +# for the config-isolated kernel->init time. +# +# Lives in hack/bench/; the repo root is derived from this script's location, so it +# runs from any working directory. Uses upstream cloud-hypervisor: set CHV=/path, or +# have `cloud-hypervisor` on PATH, else the static release binary is fetched to +# KCACHE. Needs /dev/kvm. Not the full protect zone boot. +# x86_64 only. Needs: docker (buildx), podman, hyperfine (+ curl if fetching CHV). +# +# Usage: +# hack/bench/measure-boot-time.sh # build/cache zone + zone-tiny, compare +# REBUILD=1 hack/bench/measure-boot-time.sh # force rebuild +# RUNS=15 FLAVORS="zone zone-tiny" hack/bench/measure-boot-time.sh +# hack/bench/measure-boot-time.sh /tmp/a.bzImage /tmp/b.bzImage # measure given images +set -euo pipefail + +RUNS="${RUNS:-100}" +while getopts "n:" opt; do + case "$opt" in + n) RUNS="$OPTARG" ;; + *) echo "usage: $0 [-n RUNS] [kernel...]" >&2; exit 2 ;; + esac +done +shift $((OPTIND - 1)) + +for tool in hyperfine docker podman; do + command -v "$tool" >/dev/null 2>&1 || { echo "ERROR: '$tool' not found on the host." >&2; exit 3; } +done + +BENCH_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_REPO="${KERNEL_REPO:-$(cd -- "$BENCH_DIR/../.." && pwd)}" +ARCH="${ARCH:-x86_64}" +SERIES="${SERIES:-6.18}" +FLAVORS="${FLAVORS:-zone zone-tiny}" +REGISTRY="${REGISTRY:-127.0.0.1:5000}" +REG_NAME="${REG_NAME:-edera-local-registry}" +# no sccache backend locally, and its wrapper can fail the kernel assembler probe +export KERNEL_DISABLE_SCCACHE="${KERNEL_DISABLE_SCCACHE-1}" +KCACHE="${KCACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/edera-kernel-bench}" +CHV_URL="${CHV_URL:-https://github.com/cloud-hypervisor/cloud-hypervisor/releases/latest/download/cloud-hypervisor-static}" + +mkdir -p "$KCACHE" +CHV="${CHV:-}" +if [ -z "$CHV" ]; then + if command -v cloud-hypervisor >/dev/null 2>&1; then + CHV="cloud-hypervisor" + else + CHV="$KCACHE/cloud-hypervisor" + if [ ! -x "$CHV" ]; then + command -v curl >/dev/null 2>&1 || { echo "ERROR: need cloud-hypervisor on PATH, CHV=/path, or curl to fetch it." >&2; exit 3; } + echo ">> fetching upstream cloud-hypervisor -> $CHV" >&2 + curl -fsSL -o "$CHV" "$CHV_URL" + chmod +x "$CHV" + fi + fi +fi +[ -e /dev/kvm ] || { echo "ERROR: /dev/kvm not available; Cloud Hypervisor needs KVM." >&2; exit 3; } + +WORK="$(mktemp -d)" +CFG_BAK="" +cleanup() { + rm -rf "$WORK" 2>/dev/null || true + [ -n "$CFG_BAK" ] && mv -f "$CFG_BAK" "$KERNEL_REPO/config.yaml" 2>/dev/null || true +} +trap cleanup EXIT + +valid_kernel() { + local k="$1" sz + [ -f "$k" ] || return 1 + sz=$(stat -c %s "$k" 2>/dev/null || echo 0) + [ "$sz" -gt 1000000 ] || return 1 + if command -v file >/dev/null 2>&1; then + file -b "$k" | grep -qiE 'bzImage|kernel' || return 1 + fi + return 0 +} + +ensure_build_env() { + [ -n "${BUILD_ENV_READY:-}" ] && return 0 + docker container inspect "$REG_NAME" >/dev/null 2>&1 || + docker run -d --name "$REG_NAME" --restart=unless-stopped \ + -p 127.0.0.1:5000:5000 docker.io/library/registry:2 >/dev/null + CFG_BAK="$KERNEL_REPO/config.yaml.bootbak" + cp "$KERNEL_REPO/config.yaml" "$CFG_BAK" + sed -i "s|^imageNameFormat:.*|imageNameFormat: \"${REGISTRY}/edera-dev/[image]:[tag]\"|" "$KERNEL_REPO/config.yaml" + BUILD_ENV_READY=1 +} + +# ---- collect kernels: explicit paths, or build/cache each flavor ---- +ORDER=() +declare -A KPATH +if [ "$#" -ge 1 ]; then + for k in "$@"; do l="$(basename "$k")"; ORDER+=("$l"); KPATH[$l]="$k"; done +else + cd "$KERNEL_REPO" + for f in $FLAVORS; do + cache="$KCACHE/${f}-${SERIES}.bzImage" + if [ -z "${REBUILD:-}" ] && valid_kernel "$cache"; then + echo ">> reusing cached $f ($cache)" >&2 + else + ensure_build_env + echo ">> building $f ..." >&2 + docker buildx rm edera >/dev/null 2>&1 || true + if ! KERNEL_ARCHITECTURES="$ARCH" ./hack/build/docker-build.sh \ + "stable:flavor=${f};series=${SERIES}" >"/tmp/kboot-${f}.log" 2>&1; then + echo " build FAILED for $f (see /tmp/kboot-${f}.log)" >&2 + continue + fi + if ! valid_kernel target/kernel; then + echo " build produced no valid target/kernel for $f" >&2 + continue + fi + cp target/kernel "$cache" + fi + valid_kernel "$cache" || { echo " no valid kernel for $f, skipping" >&2; continue; } + ORDER+=("$f"); KPATH[$f]="$cache" + done + cd - >/dev/null +fi +[ "${#ORDER[@]}" -ge 1 ] || { echo "no kernels to measure" >&2; exit 1; } + +# ---- initramfs: busybox + a /init that samples uptime and powers off. Built +# entirely inside the container (no host bind-mount) and streamed out. ---- +INIT_B64=$(base64 -w0 <<'EOF' +#!/bin/sh +mount -t proc none /proc 2>/dev/null +read -r up _ < /proc/uptime +echo "BOOT_UPTIME=${up}" +poweroff -f +EOF +) +if ! podman run --rm docker.io/library/busybox:musl sh -c ' + set -e; R=/tmp/r; mkdir -p "$R/bin" + echo '"$INIT_B64"' | base64 -d > "$R/init"; chmod +x "$R/init" + for a in sh mount poweroff; do ln -sf /bin/busybox "$R/bin/$a"; done + cp /bin/busybox "$R/bin/busybox" + cd "$R" && find . | cpio -o -H newc 2>/dev/null | gzip -9 +' >"$WORK/initrd.cpio.gz" 2>"$WORK/initramfs.err"; then + echo "ERROR: initramfs build failed:" >&2 + cat "$WORK/initramfs.err" >&2 + exit 4 +fi +[ -s "$WORK/initrd.cpio.gz" ] || { echo "ERROR: empty initrd.cpio.gz:" >&2; cat "$WORK/initramfs.err" >&2; exit 4; } + +# ---- cloud-hypervisor PVH boot; guest serial -> a file we can read. +# cmdline matches protect's default container-zone boot (earlyprintk + console on +# ttyS0, quiet); protect also appends init.zone.memory.min=N and any caller args. ---- +APPEND="earlyprintk=ttyS0 console=ttyS0 quiet" +chvcmd() { # $1 = kernel, $2 = serial output file + echo "timeout 60 '$CHV' --kernel '$1' --initramfs '$WORK/initrd.cpio.gz' --cmdline '$APPEND' --cpus boot=1 --memory size=512M --serial file='$2' --console off" +} + +# ---- preflight: confirm a boot actually reaches /init, else numbers are noise ---- +eval "$(chvcmd "${KPATH[${ORDER[0]}]}" "$WORK/pre.log")" >/dev/null 2>&1 || true +grep -q '^BOOT_UPTIME=' "$WORK/pre.log" 2>/dev/null || { + echo "ERROR: cloud-hypervisor boot did not reach /init (no BOOT_UPTIME). Serial tail:" >&2 + tail -n 25 "$WORK/pre.log" 2>/dev/null >&2 || true + exit 4 +} + +# ---- single in-guest kernel->init sample per flavor ---- +echo +for label in "${ORDER[@]}"; do + eval "$(chvcmd "${KPATH[$label]}" "$WORK/con.log")" >/dev/null 2>&1 || true + up=$(sed -n 's/^BOOT_UPTIME=//p' "$WORK/con.log" | tail -1 | tr -d '\r') + printf 'kernel->init %-14s %ss\n' "$label" "${up:-?}" +done + +# ---- hyperfine wall-clock VM-boot benchmark ---- +hf=(hyperfine --shell=sh --warmup 2 --runs "$RUNS") +for label in "${ORDER[@]}"; do + hf+=(-n "$label" "$(chvcmd "${KPATH[$label]}" /dev/null) >/dev/null 2>&1") +done +echo +echo "hyperfine command:" +line=" " +i=0 +while [ "$i" -lt "${#hf[@]}" ]; do + if [ "${hf[$i]}" = "-n" ]; then + printf '%s\n' "$line" + line=" -n ${hf[$((i + 1))]} ${hf[$((i + 2))]}" + i=$((i + 3)) + else + line="$line ${hf[$i]}" + i=$((i + 1)) + fi +done +printf '%s\n\n' "$line" +"${hf[@]}" From 4c593afcf6c308c8cb11ed5c8c1b3622e7f27cca Mon Sep 17 00:00:00 2001 From: Luca Di Maio Date: Fri, 18 Sep 2026 11:15:53 +0200 Subject: [PATCH 4/5] chore: fix linting Signed-off-by: Luca Di Maio --- hack/bench/compare-kernel-size.sh | 4 +-- hack/bench/measure-boot-time.sh | 48 ++++++++++++++++++++++------ hack/build/generate-docker-script.py | 4 ++- hack/build/verify-config.py | 8 +++-- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/hack/bench/compare-kernel-size.sh b/hack/bench/compare-kernel-size.sh index 4497ec6..a88ac5e 100755 --- a/hack/bench/compare-kernel-size.sh +++ b/hack/bench/compare-kernel-size.sh @@ -17,13 +17,13 @@ KERNEL_REPO="${KERNEL_REPO:-$(cd -- "$BENCH_DIR/../.." && pwd)}" ARCH="${ARCH:-x86_64}" SERIES="${SERIES:-6.18}" FLAVORS="${FLAVORS:-zone zone-tiny}" -REGISTRY="${REGISTRY:-127.0.0.1:5000}" # build target, so we never touch ghcr +REGISTRY="${REGISTRY:-127.0.0.1:5000}" # build target, so we never touch ghcr REG_NAME="${REG_NAME:-edera-local-registry}" # no sccache backend locally, and its wrapper can fail the kernel assembler probe export KERNEL_DISABLE_SCCACHE="${KERNEL_DISABLE_SCCACHE-1}" cd "$KERNEL_REPO" -mb() { awk -v b="${1:-0}" 'BEGIN { printf "%.3f", b / 1048576 }'; } +mb() { awk -v b="${1:-0}" 'BEGIN { printf "%.3f", b / 1048576 }'; } fsize() { stat -c %s "$1" 2>/dev/null || echo 0; } # local registry so a publish flavor build doesn't try to reach ghcr diff --git a/hack/bench/measure-boot-time.sh b/hack/bench/measure-boot-time.sh index 7b06417..164e326 100755 --- a/hack/bench/measure-boot-time.sh +++ b/hack/bench/measure-boot-time.sh @@ -25,13 +25,19 @@ RUNS="${RUNS:-100}" while getopts "n:" opt; do case "$opt" in n) RUNS="$OPTARG" ;; - *) echo "usage: $0 [-n RUNS] [kernel...]" >&2; exit 2 ;; + *) + echo "usage: $0 [-n RUNS] [kernel...]" >&2 + exit 2 + ;; esac done shift $((OPTIND - 1)) for tool in hyperfine docker podman; do - command -v "$tool" >/dev/null 2>&1 || { echo "ERROR: '$tool' not found on the host." >&2; exit 3; } + command -v "$tool" >/dev/null 2>&1 || { + echo "ERROR: '$tool' not found on the host." >&2 + exit 3 + } done BENCH_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" @@ -54,14 +60,20 @@ if [ -z "$CHV" ]; then else CHV="$KCACHE/cloud-hypervisor" if [ ! -x "$CHV" ]; then - command -v curl >/dev/null 2>&1 || { echo "ERROR: need cloud-hypervisor on PATH, CHV=/path, or curl to fetch it." >&2; exit 3; } + command -v curl >/dev/null 2>&1 || { + echo "ERROR: need cloud-hypervisor on PATH, CHV=/path, or curl to fetch it." >&2 + exit 3 + } echo ">> fetching upstream cloud-hypervisor -> $CHV" >&2 curl -fsSL -o "$CHV" "$CHV_URL" chmod +x "$CHV" fi fi fi -[ -e /dev/kvm ] || { echo "ERROR: /dev/kvm not available; Cloud Hypervisor needs KVM." >&2; exit 3; } +[ -e /dev/kvm ] || { + echo "ERROR: /dev/kvm not available; Cloud Hypervisor needs KVM." >&2 + exit 3 +} WORK="$(mktemp -d)" CFG_BAK="" @@ -97,7 +109,11 @@ ensure_build_env() { ORDER=() declare -A KPATH if [ "$#" -ge 1 ]; then - for k in "$@"; do l="$(basename "$k")"; ORDER+=("$l"); KPATH[$l]="$k"; done + for k in "$@"; do + l="$(basename "$k")" + ORDER+=("$l") + KPATH[$l]="$k" + done else cd "$KERNEL_REPO" for f in $FLAVORS; do @@ -119,16 +135,24 @@ else fi cp target/kernel "$cache" fi - valid_kernel "$cache" || { echo " no valid kernel for $f, skipping" >&2; continue; } - ORDER+=("$f"); KPATH[$f]="$cache" + valid_kernel "$cache" || { + echo " no valid kernel for $f, skipping" >&2 + continue + } + ORDER+=("$f") + KPATH[$f]="$cache" done cd - >/dev/null fi -[ "${#ORDER[@]}" -ge 1 ] || { echo "no kernels to measure" >&2; exit 1; } +[ "${#ORDER[@]}" -ge 1 ] || { + echo "no kernels to measure" >&2 + exit 1 +} # ---- initramfs: busybox + a /init that samples uptime and powers off. Built # entirely inside the container (no host bind-mount) and streamed out. ---- -INIT_B64=$(base64 -w0 <<'EOF' +INIT_B64=$( + base64 -w0 <<'EOF' #!/bin/sh mount -t proc none /proc 2>/dev/null read -r up _ < /proc/uptime @@ -147,7 +171,11 @@ if ! podman run --rm docker.io/library/busybox:musl sh -c ' cat "$WORK/initramfs.err" >&2 exit 4 fi -[ -s "$WORK/initrd.cpio.gz" ] || { echo "ERROR: empty initrd.cpio.gz:" >&2; cat "$WORK/initramfs.err" >&2; exit 4; } +[ -s "$WORK/initrd.cpio.gz" ] || { + echo "ERROR: empty initrd.cpio.gz:" >&2 + cat "$WORK/initramfs.err" >&2 + exit 4 +} # ---- cloud-hypervisor PVH boot; guest serial -> a file we can read. # cmdline matches protect's default container-zone boot (earlyprintk + console on diff --git a/hack/build/generate-docker-script.py b/hack/build/generate-docker-script.py index 96d7629..db2fb9a 100644 --- a/hack/build/generate-docker-script.py +++ b/hack/build/generate-docker-script.py @@ -225,7 +225,9 @@ def docker_compile( if os.getenv("KERNEL_DISABLE_SCCACHE"): compile_command += [ "-e", - quoted("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"), + quoted( + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ), ] compile_command += [ '"$(cat %s)"' % staged_iidfile, diff --git a/hack/build/verify-config.py b/hack/build/verify-config.py index e08426a..a9993f9 100755 --- a/hack/build/verify-config.py +++ b/hack/build/verify-config.py @@ -74,7 +74,9 @@ def main() -> None: continue have = resolved.get(symbol) # None: absent (off / unmet deps / unknown) if want in ("y", "m") and (have is None or have == "n"): - fails.append(f"STICK {symbol}: asked {want}, resolved {have or 'ABSENT'}") + fails.append( + f"STICK {symbol}: asked {want}, resolved {have or 'ABSENT'}" + ) elif want == "n" and have in ("y", "m"): fails.append(f"STICK {symbol}: asked n, resolved {have}") elif want not in ("y", "m", "n") and have is not None and have != want: @@ -89,7 +91,9 @@ def main() -> None: for manifest in args.forbidden: for symbol in parse_list(manifest): if symbol not in whitelist and resolved.get(symbol) in ("y", "m"): - fails.append(f"FORBID {symbol}: must be off, resolved {resolved[symbol]}") + fails.append( + f"FORBID {symbol}: must be off, resolved {resolved[symbol]}" + ) if fails: print(f"verify-config: FAIL ({len(fails)} violations):", file=sys.stderr) From 1c718be327cae1648958910f56b57de0482d7c73 Mon Sep 17 00:00:00 2001 From: Luca Di Maio Date: Sat, 19 Sep 2026 19:38:08 +0200 Subject: [PATCH 5/5] feat(zone-tiny): enable NIC, NVMe, and PCIe/SR-IOV passthrough drivers Signed-off-by: Luca Di Maio --- configs/x86_64/zone-tiny.config | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/configs/x86_64/zone-tiny.config b/configs/x86_64/zone-tiny.config index 6a5f374..e4eba50 100644 --- a/configs/x86_64/zone-tiny.config +++ b/configs/x86_64/zone-tiny.config @@ -115,8 +115,14 @@ CONFIG_ACPI=y CONFIG_PCI=y CONFIG_PCI_MSI=y CONFIG_PCI_MMCONFIG=y +# SR-IOV: required by the bnx2x/bnxt *_SRIOV options and for VF passthrough +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y CONFIG_CPU_MITIGATIONS=y # ---- virtio (KVM / Cloud-Hypervisor / Firecracker) ---- @@ -136,6 +142,7 @@ CONFIG_SCSI=y CONFIG_SCSI_LOWLEVEL=y CONFIG_SCSI_VIRTIO=y CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_NVME=y # pvpanic: host detects guest panic (PCI + MMIO transports). CONFIG_PVPANIC=y CONFIG_PVPANIC_PCI=y @@ -167,6 +174,13 @@ CONFIG_XEN_PRIVCMD=y CONFIG_XEN_PRIVCMD_EVENTFD=y CONFIG_XEN_VIRTIO=y CONFIG_XEN_IOMMU=y +# hardware vIOMMU drivers for emulated VT-d / AMD-Vi passthrough (enable via cmdline) +CONFIG_AMD_IOMMU=y +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_PERF_EVENTS=y +CONFIG_IRQ_REMAP=y +CONFIG_IOMMU_DEFAULT_DMA_LAZY=y CONFIG_PARAVIRT_TIME_ACCOUNTING=y # ---- storage / filesystems ---- @@ -216,6 +230,51 @@ CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_NETDEVICES=y CONFIG_NET_CORE=y +# ethernet NIC + VF drivers, for PCI / SR-IOV passthrough into the zone +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_BNX2=m +CONFIG_CNIC=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_BNX2X_SRIOV=y +CONFIG_BNXT=m +CONFIG_BNXT_SRIOV=y +CONFIG_BNXT_FLOWER_OFFLOAD=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_E1000E_HWTS=y +CONFIG_IGB=m +CONFIG_IGBVF=m +CONFIG_IXGBE=m +CONFIG_IXGBEVF=m +CONFIG_I40E=m +CONFIG_I40EVF=m +CONFIG_ICE=m +CONFIG_FM10K=m +CONFIG_IGC=m +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_MLX4_EN=m +CONFIG_MLX4_CORE_GEN2=y +CONFIG_MLX5_CORE=m +CONFIG_MLX5_CORE_EN=y +CONFIG_MLX5_EN_ARFS=y +CONFIG_MLX5_EN_RXNFC=y +CONFIG_MLX5_MPFS=y +CONFIG_MLX5_CORE_IPOIB=y +CONFIG_MLX5_SF=y +CONFIG_MLX5_DPLL=m +CONFIG_MLXFW=m +# RDMA / InfiniBand HCA passthrough (RoCE, HPC, NVMe-oF) +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_MLX4_INFINIBAND=m +CONFIG_MLX5_INFINIBAND=m CONFIG_VETH=y CONFIG_BRIDGE=y CONFIG_BRIDGE_VLAN_FILTERING=y @@ -282,6 +341,8 @@ CONFIG_SLAB_FREELIST_RANDOM=y # ---- crypto (LUKS, module sig, 9p, general) ---- CONFIG_CRYPTO=y +# AMD Cryptographic Coprocessor (SEV / crypto offload) +CONFIG_CRYPTO_DEV_CCP=y CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_GCM=y