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.