Note
(more about this metric and what it means at securityscorecards.dev) - track progress on anything surfaced by it in this repo's issues
- Fedora 44 (fresh install off the live USB image)
- Computer with
- Two graphics cards
- Motherboard with the Intel 200 series chipset (Union Point) or newer
- A fresh backup of anything you don't care to lose
🆕 Just want the RPMs? There's a dnf repo, so you can skip every (ACS only) step below and install the patched kernel directly. It's rebuilt daily against the newest Fedora kernel, so dnf update keeps you current.
sudo dnf config-manager addrepo --from-repofile=https://some-natalie.github.io/fedora-acs-override/acs-override.repo
sudo dnf install kernel-acs kernel-acs-core kernel-acs-devel kernel-acs-modules kernel-acs-modules-extraThese are named kernel-acs* rather than kernel* on purpose — they're a separate package family from Fedora's own kernel, so installing them never replaces or conflicts with the stock one. Both stay installed and bootable, dnf update tracks each independently, and you pick which one runs at the boot menu or with grubby --set-default. uname -r tells you which you're on, since the ACS builds carry .acs in the release.
The five most recent kernel versions stay in the repo, so if a new one breaks your passthrough you can boot the previous entry, or make it the default:
dnf list --showduplicates kernel-acs-core # what's available
sudo grubby --info=ALL | grep -E 'index|title'
sudo grubby --set-default=/boot/vmlinuz-7.1.9-200.acs.fc44.x86_64Kernels are installonly packages, so dnf downgrade refuses to touch them. To pull an older build back down, install it by exact version — it lands alongside what you already have rather than replacing it:
sudo dnf install kernel-acs-core-7.1.8-200.acs.fc44 kernel-acs-modules-7.1.8-200.acs.fc44Those five stick around after a Fedora release goes EOL and stops being built, so upgrading Fedora is your call to make rather than something a build schedule forces.
The packages and the repo metadata are both signed, so dnf asks you to accept the signing key the first time. Check it before you accept it — gpg --show-keys on what the site serves should print FC3F2A6C5D05CE26434442BBD9500E334C48DD8B, matching pages/RPM-GPG-KEY-acs-override here in the repo. Every build is attested too, so gh attestation verify <rpm> --repo some-natalie/fedora-acs-override will tell you which workflow run produced it.
Tip
The two graphics cards can be different models. If your cards are identical, you'll need to do some extra steps that are prefaced with (ACS only). These steps include compiling your own kernel to include Alex Williamson's patch to allow any PCIe device to use Access Control Services. More information on this patch, why it's necessary, and what it does is available on the LKML thread that proposed it. If your cards aren't identical, skip these steps.
-
Add RPM Fusion
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
-
(ACS only) - Install the dependencies to start building your own kernel.
sudo dnf install fedpkg fedora-packager rpmdevtools ncurses-devel pesign bpftool
-
(ACS only) - Set up your home build directory (if you haven't ever built any RPMs before)
rpmdev-setuptree
-
(ACS only) - Install the kernel source and finish installing dependencies.
koji download-build --arch=src kernel-6.2.15-300.fc40.src.rpm rpm -Uvh kernel-6.2.15-300.fc40.src.rpm cd rpmbuild/SPECS/ sudo dnf builddep kernel.spec -
(ACS only) - Add the ACS patch from this repo as
~/rpmbuild/SOURCES/add-acs-override.patch.curl -o ~/rpmbuild/SOURCES/add-acs-override.patch https://raw.githubusercontent.com/some-natalie/fedora-acs-override/main/acs/add-acs-override.patch -
(ACS only) - Edit
~/rpmbuild/SPECS/kernel.specto rename the package, set the build ID, and add the patch. Since each release of the spec file could change, it's not much help giving line numbers, but the first two of these should be near the top of the file. Change the package name so your build is a separate package family from Fedora's kernel instead of competing with it — every subpackage is named off this one line, sokernel-acs-core,kernel-acs-develand the rest follow.%global package_name kernel-acsThen set the build id, near the top with the other release information, so
uname -rsays which kernel you're on.# Set buildid %define buildid .acs
To add the patch, add the two lines below to the spec file in the section for patches (usually right below the sources).
# ACS override patch Patch1000: add-acs-override.patch
Then tell it to apply the patch in the
prepsection. It will be below theApplyOptionalPatch()function definition, normally right above the# END OF PATCH APPLICATIONScomment.ApplyOptionalPatch add-acs-override.patch
-
(ACS only) - Compile! This takes a long time.
rpmbuild -bb kernel.spec
-
(ACS only) - Install the new packages!
cd ~/rpmbuild/RPMS/x86_64 sudo dnf localinstall *.rpm
ℹ️ You should now have at least the following packages installed:
kernel-acs,kernel-acs-core,kernel-acs-devel,kernel-acs-modules, andkernel-acs-modules-extra. Your stockkernelpackages are untouched and still bootable. -
Update and reboot
sudo dnf clean all sudo dnf update -y sudo reboot
-
Install virtualization software and add yourself to the user group
sudo dnf install @virtualization sudo usermod -G libvirt -a $(whoami) sudo usermod -G kvm -a $(whoami)
-
Install (proprietary) nVidia drivers and remove/blacklist (open source) nouveau drivers.
sudo su - dnf install xorg-x11-drv-nvidia akmod-nvidia kernel-devel xorg-x11-drv-nvidia-cuda vulkan vdpauinfo libva-utils dnf remove *nouveau* echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
ℹ️ On the ACS kernel that's
kernel-acs-develinstead ofkernel-devel. It provideskernel-devel-uname-r, which is what akmod matches against, so the nVidia module builds against it the same way. -
Reboot again!
sudo reboot
-
Verify that the nVidia drivers are installed correctly.
lsmod | grep nouveau # This should display nothing lsmod | grep nvidia # This should display at least a couple things
-
Edit
/etc/default/grubto enable IOMMU, blacklist nouveau, and load vfio-pci first.If your video cards are different:
GRUB_CMDLINE_LINUX="rd.driver.pre=vfio-pci rd.driver.blacklist=nouveau modprobe.blacklist=nouveau rd.lvm.lv=fedora/root rd.lvm.lv=fedora/swap rhgb quiet intel_iommu=on iommu=pt"If your video cards are identical, use this instead:
GRUB_CMDLINE_LINUX="rd.driver.pre=vfio-pci rd.driver.blacklist=nouveau,nova_core modprobe.blacklist=nouveau,nova_core nvidia-drm.modeset=1 rhgb quiet intel_iommu=on iommu=pt pcie_acs_override=downstream" -
Rebuild GRUB's configuration
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
-
Edit
/etc/modprobe.d/kvm.conf. These two lines are edited out due to stability concerns. YMMV.#options kvm_intel nested=1 #options kvm_amd nested=1
-
Create or edit
/etc/modprobe.d/local.conf, adding the line below:install vfio-pci /sbin/vfio-pci-override.sh
-
Create or edit
/etc/dracut.conf.d/local.conf, adding the line below:add_drivers+= " vfio vfio_iommu_type1 vfio_pci vfio_virqfd " install_items+=" /sbin/vfio-pci-override.sh /usr/bin/find /usr/bin/dirname "
-
Create a file
/sbin/vfio-pci-override.shwith permissions755(file in this directory of the repo). -
Rebuild using
dracutsudo dracut -f --kver `uname -r` -
Reboot again!
-
Verify that your target hardware is using
vfio-pcias the driver. Omit the-s 00:02:00on another machine to get the entire output, as this argument narrows the output down to the device specified.nataliepc /h/n/k/kernel $ lspci -vv -n -s 00:02:00 02:00.0 0300: 10de:1c82 (rev a1) (prog-if 00 [VGA controller]) Subsystem: 3842:6251 Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx- Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- Interrupt: pin A routed to IRQ 10 Region 0: Memory at dc000000 (32-bit, non-prefetchable) [disabled] [size=16M] Region 1: Memory at a0000000 (64-bit, prefetchable) [disabled] [size=256M] Region 3: Memory at b0000000 (64-bit, prefetchable) [disabled] [size=32M] Region 5: I/O ports at d000 [disabled] [size=128] Expansion ROM at dd000000 [disabled] [size=512K] Capabilities: <access denied> Kernel driver in use: vfio-pci Kernel modules: nouveau, nvidia_drm, nvidia 02:00.1 0403: 10de:0fb9 (rev a1) Subsystem: 3842:6251 Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx- Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- Interrupt: pin B routed to IRQ 11 Region 0: Memory at dd080000 (32-bit, non-prefetchable) [disabled] [size=16K] Capabilities: <access denied> Kernel driver in use: vfio-pci Kernel modules: snd_hda_intel
-
Proceed to set up your virtual machine.
I put this together based on my own machine at home because I knew I'd forget this process if I ever had to do it again. There was a lot of reading of Bugzilla, StackOverflow, and a bunch of blogs/forums/mailing lists all over the internet. Thanks to everyone who did something similar so I could cobble together something from all of them that Works On My Machine. This is by no means the only way to solve the problem. 😃