How to downgrade a core NixOS package using overlays

Snowflakes resting on a car's rear windshield.
BlogLink to blog
Blog
4 min read

How to use overlays to downgrade a core package in NixOS. "Snowflakes" by Runningonbrains is licensed under CC BY-SA 4.0. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/4.0/?ref=openverse.


Contents


Introduction 

I won’t add too much preamble to this blog, because if you’re reading this, you’ve probably already suffered enough as-is. Here’s how to downgrade a core package in NixOS: specifically, how to downgrade linux-firmware to version 20240610. I’ll assume you’re using Flakes.

For the sake of organization, create a folder in your NixOS configuration repository called overlays and create a file in it called linux-firmware_20240610.nix. Open linux-firmware_20240610.nix and paste these contents:

{
  config,
  pkgs,
  lib,
  ...
}:

{
  nixpkgs.overlays = [
    (self: super: {
      linux-firmware = super.callPackage (
        {
          stdenvNoCC,
          fetchzip,
          lib,
          rdfind,
          which,
        }:

        stdenvNoCC.mkDerivation rec {
          pname = "linux-firmware";
          version = "20240610";

          src = fetchzip {
            url = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/snapshot/linux-firmware-${version}.tar.gz";
            hash = "sha256-tjDqviOMvrBoEG8+Yn+XqdBlIDfQUX0KK2kpW6/jed8=";
          };

          nativeBuildInputs = [
            rdfind
            which
          ];

          installFlags = [ "DESTDIR=$(out)" ];

          # Firmware blobs do not need fixing and should not be modified
          dontFixup = true;

          meta = with lib; {
            description = "Binary firmware collection packaged by kernel.org";
            homepage = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git";
            license = licenses.unfreeRedistributableFirmware;
            platforms = platforms.linux;
            maintainers = with maintainers; [ fpletz ];
            priority = 6; # give precedence to kernel firmware
          };
          passthru.updateScript = ./update.sh;
        }
      ) { };
    })
  ];
}

Next, open flake.nix and add this to your system’s list of modules:

modules = [
  (import ./overlays/linux-firmware.nix)
  ./hosts/myHost
];

Remember to git add * to add the new overlay file and folder. Then, run nixos-rebuild boot. Done.

Alright, now that that’s out of the way, let’s talk about what this actually does.

How to downgrade a NixOS package using overlays 

So what exactly did we just do? First, some context.

A recent update to the iwlwifi driver 🔗 caused the Wi-Fi chip in my Surface Pro 9 to go absolutely haywire. As soon as it connected to a network, the firmware crashed and restarted itself. This repeated over and over, making my poor little tabtop struggle for its life. The version just before it 🔗 worked fine, so I had a (seemingly) simple mission: downgrade linux-firmware.

My biggest problem when starting this journey is that linux-firmware is a core package. It’s not one that you install explicitly, so I couldn’t just change the package definition like I could with other packages like duplicacy-web 🔗. I had to use an overlay.

Think of an overlay like a patch. In this case, our “patch” is a specific version of linux-firmware, and we’re patching Nixpkgs. While we could do something more drastic like pin Nixpkgs to a specific version, that would impact all packages. We just want to pin one specific one.

I spent hours trying to wrap my head around overlays for core packages. Fortunately, the solution is quite easy, once you know what it is. So here’s how you do it.

Step 1: Find the package definition you want to use 

The obvious first step is to find the package version you want to downgrade to. For my Surface Pro 9, the most recent version of linux-firmware with a working iwlwifi driver is 20240610 🔗. Here’s the link to the raw file 🔗.

We’ll need to use this definition in our NixOS configuration. IMO, the easiest way to do this is to just copy and paste the text into a file within your configuration folder. I just created a new folder for overlays named (unsurprisingly) “overlays”, then added a file named linux-firmware_20240610.nix. Then, I added this to the file:

{
  config,
  pkgs,
  lib,
  ...
}:

{
  nixpkgs.overlays = [
    (self: super: {
      linux-firmware = super.callPackage (
        <PASTE PACKAGE DEFINITION HERE>
      ) { };
    })
  ];
}

If you want to overlay a package other than linux-firmware, just replace linux-firmware with the name of the package. I’m sure there’s a way to use builtins.fetchGit to point to the file that’s already hosted on GitHub, but Nix complained about impurities, so I just copied and pasted the contents into a file. On a good note, this makes it easy to see which version you’ve pinned it to.

Next, I copied and pasted the contents of the raw file 🔗 over the part of this file that says <PASTE PACKAGE DEFINITION HERE>, and saved. Remember to run git add *, or else nixos-rebuild won’t pick up the new folder and file.

Step 2: Import the overlay into your Flake 

The next step is to import this overlay. This is the easy part. Open your flake.nix file, scroll down to the nixosConfigurations section, and find the host you want to add the overlay to. Then, add this to the list of modules and save:

(import ./overlays/linux-firmware_20240610.nix)

Step 3: Rebuild and reboot 

Now, just run nixos-rebuild boot. You don’t need to update your lock file, because we’ve explicitly defined the package ourselves. We’re not using an old revision of Nixpkgs or anything like that. We’re basically just treating this like any other package, only we’re patching it over the version of this package that came with Nixpkgs.

Reboot your system, and you’re good to go!

If you want to check out the full example, see my Nix configuration repo 🔗.

Previous: "Managing your NixOS filesystem (without Disko)"Next: "Why is enabling automatic updates in NixOS so hard?"
art atmospheric breaks breakbeat buddhism chicago code disco fediverse fiction funk furry house house music kubernetes lgbt linux logseq mastodon mental health movies music nixos obsidian personal philosophy pkm poetry prompt second life social software soul technology writing