diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix index 34e0597777a6..63e833dd7fb3 100644 --- a/nixos/tests/kernel-generic.nix +++ b/nixos/tests/kernel-generic.nix @@ -35,14 +35,8 @@ let ) args); kernels = pkgs.linuxKernel.vanillaPackages // { inherit (pkgs.linuxKernel.packages) - linux_5_4_hardened - linux_5_10_hardened - linux_5_15_hardened - linux_6_1_hardened - linux_6_6_hardened linux_6_12_hardened - linux_6_13_hardened - linux_6_14_hardened + linux_6_15_hardened linux_rt_5_4 linux_rt_5_10 linux_rt_5_15 diff --git a/pkgs/os-specific/linux/kernel/hardened/update.py b/pkgs/os-specific/linux/kernel/hardened/update.py index 0603812124be..3e12a0e2dd5d 100755 --- a/pkgs/os-specific/linux/kernel/hardened/update.py +++ b/pkgs/os-specific/linux/kernel/hardened/update.py @@ -156,10 +156,11 @@ def fetch_patch(*, name: str, release_info: ReleaseInfo) -> Optional[Patch]: ) -def parse_version(version_str: str) -> Version: +def normalize_kernel_version(version_str: str) -> list[str|int]: # There have been two variants v6.10[..] and 6.10[..], drop the v version_str_without_v = version_str[1:] if not version_str[0].isdigit() else version_str - version: Version = [] + + version: list[str|int] = [] for component in re.split(r'\.|\-', version_str_without_v): try: @@ -173,14 +174,14 @@ def version_string(version: Version) -> str: return ".".join(str(component) for component in version) -def major_kernel_version_key(kernel_version: Version) -> str: +def major_kernel_version_key(kernel_version: list[int|str]) -> str: return version_string(kernel_version[:-1]) -def commit_patches(*, kernel_key: str, message: str) -> None: +def commit_patches(*, kernel_key: Version, message: str) -> None: new_patches_path = HARDENED_PATCHES_PATH.with_suffix(".new") with open(new_patches_path, "w") as new_patches_file: - json.dump(patches, new_patches_file, indent=4, sort_keys=True) + json.dump(patch_json, new_patches_file, indent=4, sort_keys=True) new_patches_file.write("\n") os.rename(new_patches_path, HARDENED_PATCHES_PATH) message = f"linux/hardened/patches/{kernel_key}: {message}" @@ -197,43 +198,32 @@ def commit_patches(*, kernel_key: str, message: str) -> None: # Load the existing patches. -patches: Dict[str, Patch] with open(HARDENED_PATCHES_PATH) as patches_file: - patches = json.load(patches_file) + patch_json = json.load(patches_file) + patch_versions = set([parse_version(k) for k in patch_json.keys()]) -# Get the set of currently packaged kernel versions. -kernel_versions = {} with open(NIXPKGS_KERNEL_PATH / "kernels-org.json") as kernel_versions_json: kernel_versions = json.load(kernel_versions_json) - for kernel_branch_str in kernel_versions: - if kernel_branch_str == "testing": continue - kernel_branch = [int(i) for i in kernel_branch_str.split(".")] - if kernel_branch < MIN_KERNEL_VERSION: continue - kernel_version = [int(i) for i in kernel_versions[kernel_branch_str]["version"].split(".")] - kernel_versions[kernel_branch_str] = kernel_version -# Remove patches for unpackaged kernel versions. -for kernel_key in sorted(patches.keys() - kernel_versions.keys()): - del patches[kernel_key] - commit_patches(kernel_key=kernel_key, message="remove") + kernels = { + parse_version(version): meta + for version, meta in kernel_versions.items() + if version != "testing" + } + + latest_lts = sorted(ver for ver, meta in kernels.items() if meta.get("lts", False))[-1] + keys = sorted(kernels.keys()) + latest_release = keys[-1] + fallback = keys[-2] g = Github(os.environ.get("GITHUB_TOKEN")) repo = g.get_repo(HARDENED_GITHUB_REPO) failures = False -# Match each kernel version with the best patch version. -releases = {} -i = 0 -for release in repo.get_releases(): - # Dirty workaround to make sure that we don't run into issues because - # GitHub's API only allows fetching the last 1000 releases. - # It's not reliable to exit earlier because not every kernel minor may - # have hardened patches, hence the naive search below. - i += 1 - if i > 100: - break - - version = parse_version(release.tag_name) +all_candidates = set([latest_lts, latest_release, fallback]) +kernels_to_package = {} +for release in repo.get_releases()[:30]: + version = normalize_kernel_version(release.tag_name) # needs to look like e.g. 5.6.3-hardened1 if len(version) < 4: continue @@ -242,44 +232,51 @@ for release in repo.get_releases(): continue kernel_version = version[:-1] + kernel_key = parse_version(major_kernel_version_key(kernel_version)) - kernel_key = major_kernel_version_key(kernel_version) - try: - packaged_kernel_version = kernel_versions[kernel_key] - except KeyError: + if kernel_key not in all_candidates: continue - release_info = ReleaseInfo(version=version, release=release) - - if kernel_version == packaged_kernel_version: - releases[kernel_key] = release_info - else: - # Fall back to the latest patch for this major kernel version, - # skipping patches for kernels newer than the packaged one. - if '.'.join(str(x) for x in kernel_version) > '.'.join(str(x) for x in packaged_kernel_version): + try: + found = kernels_to_package[kernel_key] + if found.version > version: continue - elif ( - kernel_key not in releases or releases[kernel_key].version < version - ): - releases[kernel_key] = release_info + except KeyError: + pass + + kernels_to_package[kernel_key] = ReleaseInfo(version=version, release=release) + +if latest_release in kernels_to_package: + if fallback != latest_lts: + del kernels_to_package[fallback] + kernel_versions = set([latest_lts, latest_release]) +else: + kernel_versions = set([latest_lts, fallback]) + +# Remove patches for unpackaged kernel versions. +removals = False +for kernel_key in sorted(patch_versions - kernels_to_package.keys()): + del patch_json[str(kernel_key)] + removals = True + commit_patches(kernel_key=kernel_key, message="remove") # Update hardened-patches.json for each release. -for kernel_key in sorted(releases.keys()): - release_info = releases[kernel_key] +for kernel_key in sorted(kernels_to_package.keys()): + release_info = kernels_to_package[kernel_key] release = release_info.release version = release_info.version version_str = release.tag_name name = f"linux-hardened-{version_str}" - old_version: Optional[Version] = None + old_version: Optional[list[int|str]] = None old_version_str: Optional[str] = None update: bool try: - old_filename = patches[kernel_key]["patch"]["name"] + old_filename = patch_json[str(kernel_key)]["patch"]["name"] old_version_str = old_filename.replace("linux-hardened-", "").replace( ".patch", "" ) - old_version = parse_version(old_version_str) + old_version = normalize_kernel_version(old_version_str) update = old_version < version except KeyError: update = True @@ -289,21 +286,16 @@ for kernel_key in sorted(releases.keys()): if patch is None: failures = True else: - patches[kernel_key] = patch - if old_version: + if str(kernel_key) in patch_json: message = f"{old_version_str} -> {version_str}" else: message = f"init at {version_str}" + patch_json[str(kernel_key)] = patch + commit_patches(kernel_key=kernel_key, message=message) -missing_kernel_versions = kernel_versions.keys() - patches.keys() - -if missing_kernel_versions: - print( - f"warning: no patches for kernel versions " - + ", ".join(missing_kernel_versions), - file=sys.stderr, - ) +if removals: + print("Hardened kernels were removed. Don't forget to remove their attributes!") if failures: sys.exit(1) diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix index 6ef821fdd265..93e628a8fb72 100644 --- a/pkgs/top-level/aliases.nix +++ b/pkgs/top-level/aliases.nix @@ -1413,6 +1413,22 @@ mapAliases { ''; linux_latest_hardened = linuxPackages_latest_hardened; + # Added 2025-08-10 + linuxPackages_hardened = linuxKernel.packages.linux_hardened; + linux_hardened = linuxPackages_hardened.kernel; + linuxPackages_5_4_hardened = linuxKernel.packages.linux_5_4_hardened; + linux_5_4_hardened = linuxKernel.kernels.linux_5_4_hardened; + linuxPackages_5_10_hardened = linuxKernel.packages.linux_5_10_hardened; + linux_5_10_hardened = linuxKernel.kernels.linux_5_10_hardened; + linuxPackages_5_15_hardened = linuxKernel.packages.linux_5_15_hardened; + linux_5_15_hardened = linuxKernel.kernels.linux_5_15_hardened; + linuxPackages_6_1_hardened = linuxKernel.packages.linux_6_1_hardened; + linux_6_1_hardened = linuxKernel.kernels.linux_6_1_hardened; + linuxPackages_6_6_hardened = linuxKernel.packages.linux_6_6_hardened; + linux_6_6_hardened = linuxKernel.kernels.linux_6_6_hardened; + linuxPackages_6_12_hardened = linuxKernel.packages.linux_6_12_hardened; + linux_6_12_hardened = linuxKernel.kernels.linux_6_12_hardened; + # Added 2023-11-18, modified 2024-01-09 linuxPackages_testing_bcachefs = throw "'linuxPackages_testing_bcachefs' has been removed, please use 'linuxPackages_latest', any kernel version at least 6.7, or any other linux kernel with bcachefs support"; linux_testing_bcachefs = throw "'linux_testing_bcachefs' has been removed, please use 'linux_latest', any kernel version at least 6.7, or any other linux kernel with bcachefs support"; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index b85fbca632bb..cde6dc7f7bc5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -10602,20 +10602,6 @@ with pkgs; linux-rt = linuxPackages-rt.kernel; linux-rt_latest = linuxPackages-rt_latest.kernel; - # hardened kernels - linuxPackages_hardened = linuxKernel.packages.linux_hardened; - linux_hardened = linuxPackages_hardened.kernel; - linuxPackages_5_10_hardened = linuxKernel.packages.linux_5_10_hardened; - linux_5_10_hardened = linuxKernel.kernels.linux_5_10_hardened; - linuxPackages_5_15_hardened = linuxKernel.packages.linux_5_15_hardened; - linux_5_15_hardened = linuxKernel.kernels.linux_5_15_hardened; - linuxPackages_6_1_hardened = linuxKernel.packages.linux_6_1_hardened; - linux_6_1_hardened = linuxKernel.kernels.linux_6_1_hardened; - linuxPackages_6_6_hardened = linuxKernel.packages.linux_6_6_hardened; - linux_6_6_hardened = linuxKernel.kernels.linux_6_6_hardened; - linuxPackages_6_12_hardened = linuxKernel.packages.linux_6_12_hardened; - linux_6_12_hardened = linuxKernel.kernels.linux_6_12_hardened; - # GNU Linux-libre kernels linuxPackages-libre = linuxKernel.packages.linux_libre; linux-libre = linuxPackages-libre.kernel; diff --git a/pkgs/top-level/linux-kernels.nix b/pkgs/top-level/linux-kernels.nix index 83a8a024e0ac..92e7265ed62b 100644 --- a/pkgs/top-level/linux-kernels.nix +++ b/pkgs/top-level/linux-kernels.nix @@ -294,14 +294,10 @@ in linux_latest_libre = deblobKernel packageAliases.linux_latest.kernel; - linux_hardened = hardenedKernelFor packageAliases.linux_default.kernel { }; - - linux_5_10_hardened = hardenedKernelFor kernels.linux_5_10 { }; - linux_5_15_hardened = hardenedKernelFor kernels.linux_5_15 { }; - linux_6_1_hardened = hardenedKernelFor kernels.linux_6_1 { }; - linux_6_6_hardened = hardenedKernelFor kernels.linux_6_6 { }; linux_6_12_hardened = hardenedKernelFor kernels.linux_6_12 { }; + linux_6_15_hardened = hardenedKernelFor kernels.linux_6_15 { }; + linux_hardened = hardenedKernelFor packageAliases.linux_default.kernel { }; } // lib.optionalAttrs config.allowAliases { linux_4_19 = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; @@ -311,6 +307,11 @@ in linux_6_13 = throw "linux 6.13 was removed because it has reached its end of life upstream"; linux_6_14 = throw "linux 6.14 was removed because it has reached its end of life upstream"; + linux_5_10_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_5_15_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_6_1_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_6_6_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_4_19_hardened = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; linux_5_4_hardened = throw "linux_5_4_hardened was removed because it was broken"; linux_6_9_hardened = throw "linux 6.9 was removed because it has reached its end of life upstream"; @@ -776,11 +777,8 @@ in linux_hardened = recurseIntoAttrs (packagesFor kernels.linux_hardened); - linux_5_10_hardened = recurseIntoAttrs (packagesFor kernels.linux_5_10_hardened); - linux_5_15_hardened = recurseIntoAttrs (packagesFor kernels.linux_5_15_hardened); - linux_6_1_hardened = recurseIntoAttrs (packagesFor kernels.linux_6_1_hardened); - linux_6_6_hardened = recurseIntoAttrs (packagesFor kernels.linux_6_6_hardened); linux_6_12_hardened = recurseIntoAttrs (packagesFor kernels.linux_6_12_hardened); + linux_6_15_hardened = recurseIntoAttrs (packagesFor kernels.linux_6_15_hardened); linux_zen = recurseIntoAttrs (packagesFor kernels.linux_zen); linux_lqx = recurseIntoAttrs (packagesFor kernels.linux_lqx); @@ -794,6 +792,12 @@ in __recurseIntoDerivationForReleaseJobs = true; } // lib.optionalAttrs config.allowAliases { + + linux_5_10_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_5_15_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_6_1_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_6_6_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; + linux_4_19_hardened = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; linux_5_4_hardened = throw "linux_5_4_hardened was removed because it was broken"; linux_6_9_hardened = throw "linux 6.9 was removed because it has reached its end of life upstream";