Building a minimal kernel, stripping out unneeded drivers

Hey there, I am sure this is somewhere, but I haven’t found it yet.

My goal

  • latest longterm Kernel source (currently 6.12)
  • custom configuration that only includes modules I need
  • no NVIDIA, AMD, blobs from random companies, drivers for obscure and/or old hardware

This would improve security by removing highly privileged code, especially drivers dumped somewhere by various companies.

List used kernel modules

For now I have installed modprobed-db and followed the Arch wiki on how to use it.

modprobed-db #create config file
kate ~/.config/modprobed-db.conf #remove ignored drivers as I dont use them
modprobed-db store #write used kernel modules to the database
modprobed-db list

A lot of things might be missing, like some filesystems I rarely use, the ability to use Veracrypt or hardware sensors.

Configure the kernel

This is where I have issues. I am using nixos-unstable with flakes enabled, and would like a small flake or NixOS-module that builds the kernel from official sources, adding a custom build config.

I have checked the wiki but it is a bit too complicated for me, Nix is not simple :smiley:

So, I asked ChatGPT, with a clear goal and a ton of back and forth

  • take 6.12 source
  • use modprobed-db as reference for drivers to include (using localmodconfig)
  • add a list of drivers to always include

This is the result, and for now it seems to work?

Click to Expand
# /etc/nixos/flakes/kernel.nix
{ pkgs, lib, ... }:

let
  modprobedDb = ../settings/kernel/modprobed.db;

  # force enable some drivers that may not be loaded

  # Nonexistent?
  #EFI_VARS_PSTORE = "y";
  #FS_VERACRYPT = "m";      # loop and kernel crypto instead
  #CRYPTO_LUKS = "m";       # CRYPT_LUKS instead
  #EFI_SECURE_BOOT_SIG_ENFORCE = "y";  # when verifying binaries via the kernel, renamed to "EFI_SECUREBOOT_KEYRING"?

  extraConfigs = {

    # Filesystems
    UDF_FS = "m";         # optical disks
    ISO9660_FS = "m";     # optical disks and ISOs
    NTFS3_FS = "m";       # windows ntfs partitions
    BLK_DEV_LOOP = "m";   # loopback
    VFAT_FS = "m";        # USB sticks, EFI Partition
    EXFAT_FS = "m";       # exFat
    EXT3_FS = "m";        # ext3
    EXT4_FS = "m";        # ext4
    XFS_FS = "m";         # XFS filesystem
    F2FS_FS = "m";        # Flash-Friendly FS (Android)
    BCACHEFS_FS = "m";
    FUSE_FS = "m";        # Userspace filesystem (required for sshfs, rclone, AppImages)
    TMPFS = "y";          # Tempfs for /tmp etc.

    #RAMFS = "y";         # almost never used, tempfs instead
    #CEPH_FS = "m";       # Ceph network FS
    #9P_FS = "m";         # Plan 9 Filesystem

    # Block & RAID
    DM_VERITY = "m";      # Verified read-only block devices (used in secure OS images)
    PARTITION_ADVANCED = "y";   # GPT, MBR helpers
    BLOCK = "y";                # Core block device layer
    #MD_AUTODETECT = "y";       # software RAID

    # Compression
    ZSTD_COMPRESS = "m";  # zstandard compression
    ZSTD_DECOMPRESS = "m";

    # External Storage
    USB_STORAGE = "y";    # USB mass storage (flash drives, card readers)
    SCSI_MOD = "y";       # SATA, SAS, USB devices
    SD_MOD = "m";         # SCSI disk support (all disks)
    #SG = "m";            # SCSI generic (CD/DVD access)
    #SR_MOD = "m";        # SCSI CD-ROM
    MMC = "m";            # SD card interfaces
    MMC_BLOCK = "m";

    # Network filesystems
    NFS_FS = "m";         # NFS client
    NFS_V4 = "y";         # NFSv4 support
    NFS_V4_1 = "y";       # NFSv4.1
    NFS_V4_2 = "y";       # NFSv4.2
    NFS_USE_KERNEL_DNS = "y";
    CIFS = "m";           # SMB/Samba/Windows shares
    CIFS_XATTR = "y";     # Extended attributes
    CIFS_POSIX = "y";     # POSIX extensions
    #OCFS2_FS = "m";      # optional cluster
    #SMB_SERVER = "m";    # SMB server
    #NCP_FS = "m";        # NetWare

    # EFI support
    EFI = "y";
    EFI_STUB = "y";
    EFI_VARS = "y";
    EFI_ESRT = "y";
    EFI_PARTITION = "y";
    PSTORE = "y";
    EFI_PSTORE = "m";     # recover logs via efivarfs/pstore
    EFIVAR_FS = "y";      # mountpoint for Efi variables
    #EFIVAR_FS_DEVMEM     # when tools are used to poke Efi via /dev/mem
    #EFI_MIXED = "y";     # legacy
    #EFI_RUNTIME_MAP = "y"; #legacy
    #EFI_PXE = "m";       # network boot via EFI

    # Secure Boot
    EFI_SECURE_BOOT = "y";
    EFI_SECUREBOOT_KEYRING = "m";

    # Firmware and ACPI
    ACPI = "y";
    ACPI_BUTTON = "y";
    ACPI_VIDEO = "y";
    X86_PLATFORM_DEVICES = "y"; # generic platform device bus, many laptops
    FIRMWARE_CLASS_SYSFS = "y"; # sysfs interface for firmware blobs in /sys/class/firmware
    #ACPI_PROCFS = "y";         # sometimes required for legacy support
    #ACPI_REV_OVERRIDE_POSSIBLE = "y"; # nieche
    #ACPI_PROC_EVENT = "m";     # legacy, /proc/acpi/event, custom ACPI scripts

    # Encryption
    CRYPT_LUKS = "m";
    DM_CRYPT = "m";
    FS_ENCRYPTION = "m";
    CRYPT_DEV_LUKS2 = "m";
    CRYPT_DEV_LOOP = "m";       # loop devices over encrypted partitions
    CRYPTO_AES = "y";           # Full disk encryption, TPM attestation
    CRYPTO_GCM = "y";
    CRYPTO_SHA1 = "m";
    CRYPTO_SHA256 = "m";
    CRYPTO_SHA512 = "m";
    CRYPTO_CHACHA20    = "m";
    CRYPTO_POLY1305    = "m";
    CRYPTO_CHACHA20POLY1305 = "m";
    CRYPTO_SHA3_256    = "m";   # SHA-3 family
    CRYPTO_SHA3_512    = "m";

    # USB
    USB_CORE = "m";
    USB_COMMON = "m";
    OHCI_HCD = "m";
    UHCI_HCD = "m";

    # Input devices
    INPUT_EVDEV = "m";          # Generic input events
    MOUSE_PS2 = "m";            # Touchpads/trackpoints
    SERIO_LIBPS2 = "m";         # PS/2 input devices, mostly internal keyboards and touchpads
    USB_HID = "m";              # USB mouse/keyboard
    HID_GENERIC = "m";
    #INPUT_JOYDEV = "m";        # Joystick interface

    # Suspend-Resume
    XHCI_HCD = "m";
    EHCI_HCD = "m";

    # General firmware and platform support
    DMIID = "y";
    DMI_SYSFS = "y";

    # Always built in on x86_64
    #PROC_FS = "y";
    #SYSFS = "y";

    # NVRAM variable access (for `efibootmgr`, systemd-boot)
    NVRAM = "y";
    EFI_CAPSULE_LOADER = "y";     # firmware updates

    # EFI framebuffer support for early console
    FRAMEBUFFER_CONSOLE = "y";
    FB_EFI = "y";

    # TPM and TCG
    TCG_TPM = "y";
    TPM_CRB = "y";                # TPM 2.0 interface (newer systems)
    TPM_TIS = "y";                # TPM 1.2 interface
    TPM_TIS_CORE = "y";
    TPM_EVENT_LOG = "y";
    TPM_KEYRRING = "y";
    TPM_DEVICE = "y";
    TPM_TIS_SPI = "m";            # SPI-based TPMs
    #TPM_TIS_I2C_ATMEL = "m";     # For some embedded systems
    #TPM_TIS_I2C_INFINEON = "m";
    #TPM_TIS_I2C_NUVOTON = "m";

    # RNG/crypto for secure elements
    HW_RANDOM = "y";
    HW_RANDOM_TPM = "y";
    CRYPTO_RNG = "y";
    CRYPTO_DRB = "m";

    # Platform security (Intel/AMD firmware modules)
    INTEL_MEI = "y";
    INTEL_MEI_ME = "y";
    INTEL_MEI_HDCP = "m";
    #MEI_TEE = "m";               # Intel TEE for TXT or SGX
    #AMD_PSP = "y";

    # Security modules and integrity framework
    SECURITYFS = "y";
    INTEGRITY = "y";
    IMA = "y";
    IMA_MEASURE_PCR_IDX = "10";
    IMA_LSM_RULES = "y";

    # Cryptographic subsystem
    CRYPTO_USER_API = "y";
    CRYPTO_USER_API_HASH = "y";
    CRYPTO_USER_API_SKCIPHER = "y";

    # Virtualization
    VIRTIO = "m";                   # Paravirtualized drivers (VMs)
    VIRTIO_PCI = "m";
    VIRTIO_BLK = "m";
    VIRTIO_NET = "m";

    # Character Sets, Unicode
    NLS = "m";                      # core code-page layer
    NLS_UTF8 = "m";                 # UTF-8 support

    # Printing
    USB_PRINTER = "m";
    #PARPORT = "m";                 # Parallel port support
    #PARPORT_PC = "m";              # Standard PC-style parallel port
    #LP = "m";                      # Printer driver for parallel port
    #IEEE1284 = "m";                # parralel port, Communication protocol
  };

  # Derivation to generate a .config using localmodconfig
  generatedConfig = pkgs.stdenv.mkDerivation {
    name = "kernel-longterm-minimal";
    src = pkgs.linux_6_12.src;
    nativeBuildInputs = with pkgs; [ ncurses pkg-config bc flex bison perl ];

    unpackPhase = "true";

    buildPhase = ''
      cp -r ${pkgs.linux_6_12.src}/* .

      # generate default configuration
      make defconfig

      # Simulate /proc/modules from modprobed.db
      export LSMOD=$(mktemp)
      awk '{ print $1, 0, 0 }' ${modprobedDb} > $LSMOD

      # customize the defconfig using the currently "loaded" modules from modprobed-db
      yes "" | make localmodconfig

      # Add extra modules we always want
      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "scripts/config --module ${k}") extraConfigs)}

      # Show result
      cp .config $out/config
    '';

    installPhase = "true"; # no install needed
  };

customKernelPackages = pkgs.linuxPackagesFor (pkgs.linux_6_12.override {
    configfile = "${generatedConfig}/config";
  });

in {
  config = {
    boot.kernelPackages = customKernelPackages;
  };
}

#### Update modprobed-db
# modprobed-db store
# sudo cp ~/.config/modprobed.db /etc/nixos/settings/kernel/modprobed.db

(This took 3 “reasoning” iterations to hopefully remove most AI hallucinations. The things that are not existent or deprecated all came from the first output of ChatGPT.)

Alternative

Instead of compiling a custom kernel, a lot of modules can be prevented from loading using the boot.extraModprobeConfig option. Here I disabled a ton of unneeded stuff already, taking Secureblue as example.

Click to expand
boot.extraModprobeConfig = ''

# Unneeded Things
install nouveau /bin/false

# Fedora Defaults (Fedora uses "blacklist")
install ax25 /bin/false
install batman-adv /bin/false
install floppy /bin/false
install l2tp_eth /bin/false
install l2tp_netlink /bin/false
install l2tp_ppp /bin/false
install netrom /bin/false
install rds /bin/false
install rose /bin/false
install sch_choke /bin/false
install sch_drr /bin/false
install sch_etf /bin/false
install sch_gred /bin/false
install sch_mqprio /bin/false
install sch_multiq /bin/false
install sch_netem /bin/false
install sch_qfq /bin/false
install sch_red /bin/false
install sch_sfb /bin/false

# AppImages
install squashfs /bin/false

# Apple Stuff
install appletalk /bin/false
install hfs /bin/false
install hfsplus /bin/false

# Bluetooth
# install bluetooth /bin/false
# install btusb /bin/false

# CD ROMs
install cdrom /bin/false
install sr_mod /bin/false

# DVDs (UDF Filesystem)
# install udf /bin/false

# Firewire
install firewire-core /bin/false
install firewire_core /bin/false
install firewire-ohci /bin/false
install firewire_ohci /bin/false
install firewire-sbp2 /bin/false
install firewire_sbp2 bin/false
install firewire-net /bin/false
install firewire_net /bin/false

# Framebuffer
# source, Ubuntu: https://git.launchpad.net/ubuntu/+source/kmod/tree/debian/modprobe.d/blacklist-framebuffer.conf
install cyber2000fb /bin/false
install cyblafb /bin/false
install gx1fb /bin/false
install hgafb /bin/false
install kyrofb /bin/false
install lxfb /bin/false
install matroxfb_base /bin/false
install neofb /bin/false
install nvidiafb /bin/false
install pm2fb /bin/false
install s1d13xxxfb /bin/false
install sisfb /bin/false
install tdfxfb /bin/false
install vesafb /bin/false
install vfb /bin/false
install vt8623fb /bin/false
install udlfb /bin/false

# unused network protocols
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
install n-hdlc /bin/false
install ax25 /bin/false
install netrom /bin/false
install x25 /bin/false
install rose /bin/false
install decnet /bin/false
install econet /bin/false
install af_802154 /bin/false
install ipx /bin/false
install psnap /bin/false
install p8023 /bin/false
install p8022 /bin/false
install can /bin/false

# NFS (Network Filesystem)
# https://en.wikipedia.org/wiki/Network_File_System
install nfs /bin/false
install nfsv2 /bin/false
# install nfsv3 /bin/false
# install nfsv4 /bin/false

# unused filesystems
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install cifs /bin/false
install ksmbd /bin/false
install gfs2 /bin/false
install reiserfs /bin/false
install kafs /bin/false
install orangefs /bin/false
install 9p /bin/false
install adfs /bin/false
install affs /bin/false
install afs /bin/false
install befs /bin/false
install ceph /bin/false
install coda /bin/false
install ecryptfs /bin/false
install erofs /bin/false
install jfs /bin/false
install minix /bin/false
install netfs /bin/false
install nilfs2 /bin/false
install ocfs2 /bin/false
install romfs /bin/false
install ubifs /bin/false
install zonefs /bin/false
install sysv /bin/false
install ufs /bin/false

# Thunderbolt
install thunderbolt /bin/false
install ohci1394 /bin/false
install sbp2 /bin/false
install dv1394 /bin/false
install raw1394 /bin/false
install video1394 /bin/false

# Various
# disable vivid
install vivid /bin/false

# disable GNSS
install gnss /bin/false
install gnss-mtk /bin/false
install gnss-serial /bin/false
install gnss-sirf /bin/false
install gnss-usb /bin/false
install gnss-ubx /bin/false

# blacklist ath_pci
blacklist ath_pci

### Not Security Related
# Improve KVM
options vhost max_mem_regions=509

'';

Result

As typical with LLMs, I am not sure anymore what is hallucination and what not. The rebuild is too fast, which tells me there is no compilation of anything.

For now I will stall the effort and am happy to hear about your experiences, or see configs that you use when compiling a minimal kernel.

How’s this been going? I’d like to do the same thing- make an ultra-minimal NixOS version for servers and VMs

NixOS is a good server OS, except when it isn’t this is the best writing on the subject I’ve seen in case you haven’t come across it

I doubt the kernel size will be the biggest offender.

Still, the NixOS manual has instructions for doing this: NixOS Manual

I also don’t think the wiki instructions are that complex: Linux kernel - NixOS Wiki

The post here isn’t bad, but you really don’t need to do IFD for a static configuration. Just generate a config manually once using those tools and literally add it to your configuration directory.