Skip to main content
  1. Blog posts/

Blocking PCIe Adresses in the Linux Kernel

Linux
Table of Contents

Why
#

I needed a quick and dirty way to make a NVMe device disappear. But not only for userland applications, but also for shitty kernel modules that may do terrible things. So the idea is to prevent a specific NVMe device from being enumerated and set-up in the first place.

How to create a hacky kernel patch
#

As always, the greeat arch wiki has a great article about how to achieve this. However, a few steps in between were missing for me, as i have never done this before. Since they are too specifc, i rather document them here than in the arch wiki.

Setup the build environment
#

First, we need to get the linux kernel pkgbuild, with which we can get the sources and then build the kernel.

pkgctl repo clone --protocol=https linux
makepkg --nobuild

That will clone the git repo and download source tar balls, as well as extract them.

The next step is to adjust the PKGBUILD to:

  • rename the package to our custom thing (using linux is not recommended, as it clashes with official kernels)
  • add our foo patch (that we will create in a second)
  • disable generating the docs
diff --git a/PKGBUILD b/PKGBUILD
-pkgbase=linux
+pkgbase=linux-guard

 source=(
+  foobar.patch.zst
 )

build() {
-  make htmldocs
+  #make htmldocs
 }

_package-docs() {
 pkgname=(
-  "$pkgbase-docs"
+  #"$pkgbase-docs"
 )
}

(boring lines omitted)

Creating the patch
#

I do have a kernel checked out at another location (/home/marco/git/linux-6.13.2), in which i made the modifications. The actual patch simply hooks into nvme_probe, dumps the info and matches vendor and id against some hard coded values. If they match, it aborts setting up the device.

diff linux-6.13.2/drivers/nvme/host/pci.c /home/marco/gitlinux-6.13.2/drivers/nvme/host/pci.c
 	struct nvme_dev *dev;
 	int result = -ENOMEM;

+	printk("Guard trigggered in nvme_probe\n");
+	dev_info(dev->ctrl.device, "Dumping dev info\n");
+
+	if(id->vendor == 0x144d && id->device == 0x1337) {
+		printk("Guard blacklisted samsung device\n");
+		return result;
+	}
+
+
 	dev = nvme_pci_alloc_dev(pdev, id);
 	if (IS_ERR(dev))
 		return PTR_ERR(dev);

Now all that is left to create the patch, is to diff these two repos:

# from within the `src` directory
diff --unified --recursive --text linux-6.13.2/drivers/nvme/host/pci.c /home/marco/git/linux-6.13.2/drivers/nvme/host/pci.c > foobar.patch

Now we move our patch to the build root and package it:

mv src/foobar.patch .
zstd -T0 -16 foobar.patch

In the initial step, we told the build config about our foobar.patch.zst. We need to update the checksums though. When running updpkgsums, that is done automatically and updates the PKGBUILD for us.

diff --git a/PKGBUILD b/PKGBUILD
-sha256sums=('9452f28d7a0051fba4886712395b484c4c7fcf9f85944a62fd3d97dc923f5339'
+sha256sums=('43744de7a32177b897c45b5ce30a3a581e5201b8fdfe51ed4bc7d52315fc5b9c'
+            '9452f28d7a0051fba4886712395b484c4c7fcf9f85944a62fd3d97dc923f5339'
...
)
-b2sums=('8f5f44fa6f7b2a964a3fb14afd10dc0c6cc5ec73eb3b6dba24d35664f7083546b70eff7a3d5a9b3ba3c8b84785518c6df91aff0ed948cd538ff0b3b0484fd613'
+b2sums=('0a1254202f1b3763b1e36de4fe6a18d27e97ffe68862c6160320e44f9657135e022afdfe7cfcce5d72205fef70599d230b274e05b0b7d8e6c8872144f0504608'
+        '8f5f44fa6f7b2a964a3fb14afd10dc0c6cc5ec73eb3b6dba24d35664f7083546b70eff7a3d5a9b3ba3c8b84785518c6df91aff0ed948cd538ff0b3b0484fd613'
...
)

Building the kernel
#

Now it’s time to build: MAKEFLAGS="--jobs=$(nproc)" makepkg -sf. After a few minutes, we have a kernel image that we can install via pacman:

sudo pacman -U linux-guard-headers-6.13.2.arch1-1-x86_64.pkg.tar.zst linux-guard-6.13.2.arch1-1-x86_64.pkg.tar.zst

If that goes well, updating the grub config will allow you to select the kernel at boot: sudo grub-mkconfig -o /boot/grub/grub.cfg.

And that’s it, the NVMe device no longer shows up! As you can see, 22:00.0 it is still recognized as a PCIe device in lspci, but it’s no longer a disk, as compared to 01:00.0, which is allowed to exist.

Image showing that a samsung device of 22:00.0 is not shown as disk