diff --git a/pkgs/os-specific/linux/kernel/update-hardened.py b/pkgs/os-specific/linux/kernel/update-hardened.py index 7f6949653af..49a6228fb97 100755 --- a/pkgs/os-specific/linux/kernel/update-hardened.py +++ b/pkgs/os-specific/linux/kernel/update-hardened.py @@ -3,60 +3,68 @@ # This is automatically called by ./update.sh. -import re import json -import sys import os.path -from glob import glob +import re import subprocess +import sys +from glob import glob from tempfile import TemporaryDirectory from github import Github 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') +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_VERSION = [4, 14] + def run(*args, **kwargs): try: return subprocess.run( - args, **kwargs, - check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + args, + **kwargs, + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) except subprocess.CalledProcessError as err: print( - f'error: `{err.cmd}` failed unexpectedly\n' - f'status code: {err.returncode}\n' + f"error: `{err.cmd}` failed unexpectedly\n" + f"status code: {err.returncode}\n" f'stdout:\n{err.stdout.decode("utf-8").strip()}\n' f'stderr:\n{err.stderr.decode("utf-8").strip()}', file=sys.stderr, ) sys.exit(1) + def nix_prefetch_url(url): - output = run('nix-prefetch-url', '--print-path', url).stdout - return output.decode('utf-8').strip().split('\n') + output = run("nix-prefetch-url", "--print-path", url).stdout + return output.decode("utf-8").strip().split("\n") + def verify_openpgp_signature(*, name, trusted_key, sig_path, data_path): - with TemporaryDirectory(suffix='.nixpkgs-gnupg-home') as gnupg_home: - run('gpg', '--homedir', gnupg_home, '--import', trusted_key) - keyring = os.path.join(gnupg_home, 'pubring.kbx') + with TemporaryDirectory(suffix=".nixpkgs-gnupg-home") as gnupg_home: + run("gpg", "--homedir", gnupg_home, "--import", trusted_key) + keyring = os.path.join(gnupg_home, "pubring.kbx") try: subprocess.run( - ('gpgv', '--keyring', keyring, sig_path, data_path), - check=True, stderr=subprocess.PIPE, + ("gpgv", "--keyring", keyring, sig_path, data_path), + check=True, + stderr=subprocess.PIPE, ) return True except subprocess.CalledProcessError as err: print( - f'error: signature for {name} failed to verify!', + f"error: signature for {name} failed to verify!", file=sys.stderr, ) - print(err.stderr.decode('utf-8'), file=sys.stderr, end='') + print(err.stderr.decode("utf-8"), file=sys.stderr, end="") return False + def fetch_patch(*, name, release): def find_asset(filename): try: @@ -68,12 +76,12 @@ def fetch_patch(*, name, release): except StopIteration: raise KeyError(filename) - patch_filename = f'{name}.patch' + patch_filename = f"{name}.patch" try: patch_url = find_asset(patch_filename) - sig_url = find_asset(patch_filename + '.sig') + sig_url = find_asset(patch_filename + ".sig") except KeyError: - print(f'error: {patch_filename}{{,.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) @@ -88,59 +96,71 @@ def fetch_patch(*, name, release): return None return { - 'name': patch_filename, - 'url': patch_url, - 'sha256': sha256, + "name": patch_filename, + "url": patch_url, + "sha256": sha256, } + def parse_version(version_str): version = [] - for component in version_str.split('.'): + 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) + 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: + 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_key}: {message}' + new_patches_file.write("\n") + os.rename(HARDENED_PATCHES_PATH + ".new", HARDENED_PATCHES_PATH) + message = f"linux/hardened-patches/{kernel_key}: {message}" print(message) - if os.environ.get('COMMIT'): + if os.environ.get("COMMIT"): run( - 'git', '-C', HERE, 'commit', f'--message={message}', - 'hardened-patches.json', + "git", + "-C", + HERE, + "commit", + f"--message={message}", + "hardened-patches.json", ) + # Load the existing patches. with open(HARDENED_PATCHES_PATH) as patches_file: patches = json.load(patches_file) -NIX_VERSION_RE = re.compile(r''' - \s* version \s* = - \s* " (?P [^"]*) " - \s* ; \s* \n -''', re.VERBOSE) +NIX_VERSION_RE = re.compile( + r""" + \s* version \s* = + \s* " (?P [^"]*) " + \s* ; \s* \n + """, + re.VERBOSE, +) # Get the set of currently packaged kernel versions. kernel_versions = {} for filename in os.listdir(HERE): - filename_match = re.fullmatch(r'linux-(\d+)\.(\d+)\.nix', filename) + filename_match = re.fullmatch(r"linux-(\d+)\.(\d+)\.nix", filename) if filename_match: 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_version = parse_version(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) @@ -148,9 +168,9 @@ for filename in os.listdir(HERE): # Remove patches for unpackaged kernel versions. for kernel_key in sorted(patches.keys() - kernel_versions.keys()): - commit_patches(kernel_key=kernel_key, message='remove') + commit_patches(kernel_key=kernel_key, message="remove") -g = Github(os.environ.get('GITHUB_TOKEN')) +g = Github(os.environ.get("GITHUB_TOKEN")) repo = g.get_repo(HARDENED_GITHUB_REPO) failures = False @@ -171,8 +191,8 @@ for release in repo.get_releases(): continue release_info = { - 'version': version, - 'release': release, + "version": version, + "release": release, } if kernel_version == packaged_kernel_version: @@ -182,22 +202,24 @@ for release in repo.get_releases(): # 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): + 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'] + release = release_info["release"] + version = release_info["version"] version_str = release.tag_name - name = f'linux-hardened-{version_str}' + name = f"linux-hardened-{version_str}" try: - old_filename = patches[kernel_key]['name'] - old_version_str = (old_filename - .replace('linux-hardened-', '') - .replace('.patch', '')) + 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: @@ -211,17 +233,17 @@ for kernel_key, release_info in releases.items(): else: patches[kernel_key] = patch if old_version: - message = f'{old_version_str} -> {version_str}' + message = f"{old_version_str} -> {version_str}" else: - message = f'init at {version_str}' + message = f"init at {version_str}" 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), + f"warning: no patches for kernel versions " + + ", ".join(missing_kernel_versions), file=sys.stderr, )