about summary refs log tree commit diff
path: root/pkgs/os-specific
diff options
context:
space:
mode:
authorJörg Thalheim <Mic92@users.noreply.github.com>2020-04-24 12:24:23 +0100
committerGitHub <noreply@github.com>2020-04-24 12:24:23 +0100
commit16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e (patch)
treefb485933147d411453061f5a995a9601eb28a4ca /pkgs/os-specific
parent2bba291913d19ad31e35988783f4e5f2089b9ddb (diff)
parent2c1db9649e66e9399fa572d3bb0da67c6e6e1962 (diff)
downloadnixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar.gz
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar.bz2
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar.lz
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar.xz
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.tar.zst
nixlib-16e4b9ca6969358ceb461fa9b5f9caca5fa8b32e.zip
Merge pull request #85880 from emilazy/linux-hardened-update-resilience
Diffstat (limited to 'pkgs/os-specific')
-rw-r--r--pkgs/os-specific/linux/kernel/hardened-patches.json30
-rw-r--r--pkgs/os-specific/linux/kernel/patches.nix13
-rwxr-xr-xpkgs/os-specific/linux/kernel/update-hardened.py151
3 files changed, 108 insertions, 86 deletions
diff --git a/pkgs/os-specific/linux/kernel/hardened-patches.json b/pkgs/os-specific/linux/kernel/hardened-patches.json
index f916ad13488f..eecb27cdb669 100644
--- a/pkgs/os-specific/linux/kernel/hardened-patches.json
+++ b/pkgs/os-specific/linux/kernel/hardened-patches.json
@@ -1,27 +1,27 @@
 {
-    "4.14.176": {
+    "4.14": {
+        "name": "linux-hardened-4.14.176.a.patch",
         "sha256": "0pr3m2j63mc746fcbzg1hlwv85im9f87qkl6r4033gwnpa9brcgk",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.14.176.a/linux-hardened-4.14.176.a.patch",
-        "version_suffix": "a"
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.14.176.a/linux-hardened-4.14.176.a.patch"
     },
-    "4.19.117": {
+    "4.19": {
+        "name": "linux-hardened-4.19.117.a.patch",
         "sha256": "0c8dvh49nzypxwvsls10i896smvpdrk40x8ybljb3qk3r8j7niaw",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.117.a/linux-hardened-4.19.117.a.patch",
-        "version_suffix": "a"
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.117.a/linux-hardened-4.19.117.a.patch"
     },
-    "5.4.35": {
+    "5.4": {
+        "name": "linux-hardened-5.4.34.a.patch",
         "sha256": "1xwpqr9nzpjg837b3wnzb8fmrl2g9rz8gz5yb55vnnllbzbz36v6",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.34.a/linux-hardened-5.4.34.a.patch",
-        "version_suffix": "a"
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.34.a/linux-hardened-5.4.34.a.patch"
     },
-    "5.5.19": {
+    "5.5": {
+        "name": "linux-hardened-5.5.19.a.patch",
         "sha256": "1ya5nsfhr3nwz6qiz4pdhvm6k9mx1kr0prhdvhx3p40f1vk281sc",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.19.a/linux-hardened-5.5.19.a.patch",
-        "version_suffix": "a"
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.19.a/linux-hardened-5.5.19.a.patch"
     },
-    "5.6.7": {
+    "5.6": {
+        "name": "linux-hardened-5.6.6.a.patch",
         "sha256": "0jiqh0frxirjbccgfdk007fca6r6n36n0pkqq4jszkckn59ayl7r",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.6.a/linux-hardened-5.6.6.a.patch",
-        "version_suffix": "a"
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.6.a/linux-hardened-5.6.6.a.patch"
     }
 }
diff --git a/pkgs/os-specific/linux/kernel/patches.nix b/pkgs/os-specific/linux/kernel/patches.nix
index 69b0197d4e68..1c4af8c32a6f 100644
--- a/pkgs/os-specific/linux/kernel/patches.nix
+++ b/pkgs/os-specific/linux/kernel/patches.nix
@@ -39,16 +39,9 @@
   };
 
   hardened = let
-    mkPatch = kernelVersion: patch: let
-      fullVersion = "${kernelVersion}.${patch.version_suffix}";
-      name = "linux-hardened-${fullVersion}";
-    in {
-      inherit name;
-      patch = fetchurl {
-        name = "${name}.patch";
-        inherit (patch) url sha256;
-        meta.maintainers = with lib.maintainers; [ emily ];
-      };
+    mkPatch = kernelVersion: src: {
+      name = lib.removeSuffix ".patch" src.name;
+      patch = fetchurl src;
     };
     patches = builtins.fromJSON (builtins.readFile ./hardened-patches.json);
   in lib.mapAttrs mkPatch patches;
diff --git a/pkgs/os-specific/linux/kernel/update-hardened.py b/pkgs/os-specific/linux/kernel/update-hardened.py
index 089e991d06bc..7f6949653afc 100755
--- a/pkgs/os-specific/linux/kernel/update-hardened.py
+++ b/pkgs/os-specific/linux/kernel/update-hardened.py
@@ -17,17 +17,7 @@ HERE = os.path.dirname(os.path.realpath(__file__))
 HARDENED_GITHUB_REPO = 'anthraxx/linux-hardened'
 HARDENED_TRUSTED_KEY = os.path.join(HERE, 'anthraxx.asc')
 HARDENED_PATCHES_PATH = os.path.join(HERE, 'hardened-patches.json')
-MIN_KERNEL = (4, 14)
-
-HARDENED_VERSION_RE = re.compile(r'''
-    (?P<kernel_version> [\d.]+) \.
-    (?P<version_suffix> [a-z]+)
-''', re.VERBOSE)
-
-def parse_version(version):
-    match = HARDENED_VERSION_RE.fullmatch(version)
-    if match:
-        return match.groups()
+MIN_KERNEL_VERSION = [4, 14]
 
 def run(*args, **kwargs):
     try:
@@ -78,11 +68,12 @@ def fetch_patch(*, name, release):
         except StopIteration:
             raise KeyError(filename)
 
+    patch_filename = f'{name}.patch'
     try:
-        patch_url = find_asset(f'{name}.patch')
-        sig_url = find_asset(f'{name}.patch.sig')
+        patch_url = find_asset(patch_filename)
+        sig_url = find_asset(patch_filename + '.sig')
     except KeyError:
-        print(f'error: {name}.patch{{,sig}} not present', file=sys.stderr)
+        print(f'error: {patch_filename}{{,.sig}} not present', file=sys.stderr)
         return None
 
     sha256, patch_path = nix_prefetch_url(patch_url)
@@ -97,16 +88,32 @@ def fetch_patch(*, name, release):
         return None
 
     return {
+        'name': patch_filename,
         'url': patch_url,
         'sha256': sha256,
     }
 
-def commit_patches(*, kernel_version, message):
+def parse_version(version_str):
+    version = []
+    for component in version_str.split('.'):
+        try:
+            version.append(int(component))
+        except ValueError:
+            version.append(component)
+    return version
+
+def version_string(version):
+    return '.'.join(str(component) for component in version)
+
+def major_kernel_version_key(kernel_version):
+    return version_string(kernel_version[:-1])
+
+def commit_patches(*, kernel_key, message):
     with open(HARDENED_PATCHES_PATH + '.new', 'w') as new_patches_file:
         json.dump(patches, new_patches_file, indent=4, sort_keys=True)
         new_patches_file.write('\n')
     os.rename(HARDENED_PATCHES_PATH + '.new', HARDENED_PATCHES_PATH)
-    message = f'linux/hardened-patches/{kernel_version}: {message}'
+    message = f'linux/hardened-patches/{kernel_key}: {message}'
     print(message)
     if os.environ.get('COMMIT'):
         run(
@@ -125,74 +132,96 @@ NIX_VERSION_RE = re.compile(r'''
 ''', re.VERBOSE)
 
 # Get the set of currently packaged kernel versions.
-kernel_versions = set()
+kernel_versions = {}
 for filename in os.listdir(HERE):
     filename_match = re.fullmatch(r'linux-(\d+)\.(\d+)\.nix', filename)
     if filename_match:
-        if tuple(int(v) for v in filename_match.groups()) < MIN_KERNEL:
-            continue
         with open(os.path.join(HERE, filename)) as nix_file:
             for nix_line in nix_file:
                 match = NIX_VERSION_RE.fullmatch(nix_line)
                 if match:
-                    kernel_versions.add(match.group('version'))
+                    kernel_version = parse_version(match.group('version'))
+                    if kernel_version < MIN_KERNEL_VERSION:
+                        continue
+                    kernel_key = major_kernel_version_key(kernel_version)
+                    kernel_versions[kernel_key] = kernel_version
 
-# Remove patches for old kernel versions.
-for kernel_version in patches.keys() - kernel_versions:
-    del patches[kernel_version]
-    commit_patches(kernel_version=kernel_version, message='remove')
+# Remove patches for unpackaged kernel versions.
+for kernel_key in sorted(patches.keys() - kernel_versions.keys()):
+    commit_patches(kernel_key=kernel_key, message='remove')
 
 g = Github(os.environ.get('GITHUB_TOKEN'))
 repo = g.get_repo(HARDENED_GITHUB_REPO)
-releases = repo.get_releases()
 
-found_kernel_versions = set()
 failures = False
 
-for release in releases:
-    remaining_kernel_versions = kernel_versions - found_kernel_versions
-
-    if not remaining_kernel_versions:
-        break
+# Match each kernel version with the best patch version.
+releases = {}
+for release in repo.get_releases():
+    version = parse_version(release.tag_name)
+    # needs to look like e.g. 5.6.3.a
+    if len(version) < 4:
+        continue
 
-    version = release.tag_name
-    name = f'linux-hardened-{version}'
-    version_info = parse_version(version)
-    if not version_info:
+    kernel_version = version[:-1]
+    kernel_key = major_kernel_version_key(kernel_version)
+    try:
+        packaged_kernel_version = kernel_versions[kernel_key]
+    except KeyError:
         continue
-    kernel_version, version_suffix = version_info
 
-    if kernel_version in remaining_kernel_versions:
-        found_kernel_versions.add(kernel_version)
-        try:
-            old_version_suffix = patches[kernel_version]['version_suffix']
-            old_version = f'{kernel_version}.{old_version_suffix}'
-            update = old_version_suffix < version_suffix
-        except KeyError:
-            update = True
-            old_version = None
-
-        if update:
-            patch = fetch_patch(name=name, release=release)
-            if patch is None:
-                failures = True
+    release_info = {
+        '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 kernel_version > packaged_kernel_version:
+            continue
+        elif (kernel_key not in releases or
+                releases[kernel_key]['version'] < version):
+            releases[kernel_key] = release_info
+
+# Update hardened-patches.json for each release.
+for kernel_key, release_info in releases.items():
+    release = release_info['release']
+    version = release_info['version']
+    version_str = release.tag_name
+    name = f'linux-hardened-{version_str}'
+
+    try:
+        old_filename = patches[kernel_key]['name']
+        old_version_str = (old_filename
+            .replace('linux-hardened-', '')
+            .replace('.patch', ''))
+        old_version = parse_version(old_version_str)
+        update = old_version < version
+    except KeyError:
+        update = True
+        old_version = None
+
+    if update:
+        patch = fetch_patch(name=name, release=release)
+        if patch is None:
+            failures = True
+        else:
+            patches[kernel_key] = patch
+            if old_version:
+                message = f'{old_version_str} -> {version_str}'
             else:
-                patch['version_suffix'] = version_suffix
-                patches[kernel_version] = patch
-                if old_version:
-                    message = f'{old_version} -> {version}'
-                else:
-                    message = f'init at {version}'
-                commit_patches(kernel_version=kernel_version, message=message)
+                message = f'init at {version_str}'
+            commit_patches(kernel_key=kernel_key, message=message)
 
-missing_kernel_versions = kernel_versions - patches.keys()
+missing_kernel_versions = kernel_versions.keys() - patches.keys()
 
 if missing_kernel_versions:
     print(
         f'warning: no patches for kernel versions ' +
-        ', '.join(missing_kernel_versions) +
-        '\nwarning: consider manually backporting older patches (bump '
-        'JSON key, set version_suffix to "NixOS-a")',
+        ', '.join(missing_kernel_versions),
         file=sys.stderr,
     )