linux_*_hardened: index patches by major kernel version
This will avoid breaking the build whenever a non-major kernel update happens. In the update script, we map each kernel version to the latest patch for the latest kernel version less than or equal to what we have packaged.
This commit is contained in:
parent
b16a5e2847
commit
2c1db9649e
@ -1,27 +1,27 @@
|
|||||||
{
|
{
|
||||||
"4.14.176": {
|
"4.14": {
|
||||||
|
"name": "linux-hardened-4.14.176.a.patch",
|
||||||
"sha256": "0pr3m2j63mc746fcbzg1hlwv85im9f87qkl6r4033gwnpa9brcgk",
|
"sha256": "0pr3m2j63mc746fcbzg1hlwv85im9f87qkl6r4033gwnpa9brcgk",
|
||||||
"url": "https://github.com/anthraxx/linux-hardened/releases/download/4.14.176.a/linux-hardened-4.14.176.a.patch",
|
"url": "https://github.com/anthraxx/linux-hardened/releases/download/4.14.176.a/linux-hardened-4.14.176.a.patch"
|
||||||
"version_suffix": "a"
|
|
||||||
},
|
},
|
||||||
"4.19.117": {
|
"4.19": {
|
||||||
|
"name": "linux-hardened-4.19.117.a.patch",
|
||||||
"sha256": "0c8dvh49nzypxwvsls10i896smvpdrk40x8ybljb3qk3r8j7niaw",
|
"sha256": "0c8dvh49nzypxwvsls10i896smvpdrk40x8ybljb3qk3r8j7niaw",
|
||||||
"url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.117.a/linux-hardened-4.19.117.a.patch",
|
"url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.117.a/linux-hardened-4.19.117.a.patch"
|
||||||
"version_suffix": "a"
|
|
||||||
},
|
},
|
||||||
"5.4.35": {
|
"5.4": {
|
||||||
|
"name": "linux-hardened-5.4.34.a.patch",
|
||||||
"sha256": "1xwpqr9nzpjg837b3wnzb8fmrl2g9rz8gz5yb55vnnllbzbz36v6",
|
"sha256": "1xwpqr9nzpjg837b3wnzb8fmrl2g9rz8gz5yb55vnnllbzbz36v6",
|
||||||
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.34.a/linux-hardened-5.4.34.a.patch",
|
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.34.a/linux-hardened-5.4.34.a.patch"
|
||||||
"version_suffix": "a"
|
|
||||||
},
|
},
|
||||||
"5.5.19": {
|
"5.5": {
|
||||||
|
"name": "linux-hardened-5.5.19.a.patch",
|
||||||
"sha256": "1ya5nsfhr3nwz6qiz4pdhvm6k9mx1kr0prhdvhx3p40f1vk281sc",
|
"sha256": "1ya5nsfhr3nwz6qiz4pdhvm6k9mx1kr0prhdvhx3p40f1vk281sc",
|
||||||
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.19.a/linux-hardened-5.5.19.a.patch",
|
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.19.a/linux-hardened-5.5.19.a.patch"
|
||||||
"version_suffix": "a"
|
|
||||||
},
|
},
|
||||||
"5.6.7": {
|
"5.6": {
|
||||||
|
"name": "linux-hardened-5.6.6.a.patch",
|
||||||
"sha256": "0jiqh0frxirjbccgfdk007fca6r6n36n0pkqq4jszkckn59ayl7r",
|
"sha256": "0jiqh0frxirjbccgfdk007fca6r6n36n0pkqq4jszkckn59ayl7r",
|
||||||
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.6.a/linux-hardened-5.6.6.a.patch",
|
"url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.6.a/linux-hardened-5.6.6.a.patch"
|
||||||
"version_suffix": "a"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,16 +39,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
hardened = let
|
hardened = let
|
||||||
mkPatch = kernelVersion: patch: let
|
mkPatch = kernelVersion: src: {
|
||||||
fullVersion = "${kernelVersion}.${patch.version_suffix}";
|
name = lib.removeSuffix ".patch" src.name;
|
||||||
name = "linux-hardened-${fullVersion}";
|
patch = fetchurl src;
|
||||||
in {
|
|
||||||
inherit name;
|
|
||||||
patch = fetchurl {
|
|
||||||
name = "${name}.patch";
|
|
||||||
inherit (patch) url sha256;
|
|
||||||
meta.maintainers = with lib.maintainers; [ emily ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
patches = builtins.fromJSON (builtins.readFile ./hardened-patches.json);
|
patches = builtins.fromJSON (builtins.readFile ./hardened-patches.json);
|
||||||
in lib.mapAttrs mkPatch patches;
|
in lib.mapAttrs mkPatch patches;
|
||||||
|
@ -17,17 +17,7 @@ HERE = os.path.dirname(os.path.realpath(__file__))
|
|||||||
HARDENED_GITHUB_REPO = 'anthraxx/linux-hardened'
|
HARDENED_GITHUB_REPO = 'anthraxx/linux-hardened'
|
||||||
HARDENED_TRUSTED_KEY = os.path.join(HERE, 'anthraxx.asc')
|
HARDENED_TRUSTED_KEY = os.path.join(HERE, 'anthraxx.asc')
|
||||||
HARDENED_PATCHES_PATH = os.path.join(HERE, 'hardened-patches.json')
|
HARDENED_PATCHES_PATH = os.path.join(HERE, 'hardened-patches.json')
|
||||||
MIN_KERNEL = (4, 14)
|
MIN_KERNEL_VERSION = [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()
|
|
||||||
|
|
||||||
def run(*args, **kwargs):
|
def run(*args, **kwargs):
|
||||||
try:
|
try:
|
||||||
@ -78,11 +68,12 @@ def fetch_patch(*, name, release):
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise KeyError(filename)
|
raise KeyError(filename)
|
||||||
|
|
||||||
|
patch_filename = f'{name}.patch'
|
||||||
try:
|
try:
|
||||||
patch_url = find_asset(f'{name}.patch')
|
patch_url = find_asset(patch_filename)
|
||||||
sig_url = find_asset(f'{name}.patch.sig')
|
sig_url = find_asset(patch_filename + '.sig')
|
||||||
except KeyError:
|
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
|
return None
|
||||||
|
|
||||||
sha256, patch_path = nix_prefetch_url(patch_url)
|
sha256, patch_path = nix_prefetch_url(patch_url)
|
||||||
@ -97,16 +88,32 @@ def fetch_patch(*, name, release):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
'name': patch_filename,
|
||||||
'url': patch_url,
|
'url': patch_url,
|
||||||
'sha256': sha256,
|
'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:
|
with open(HARDENED_PATCHES_PATH + '.new', 'w') as new_patches_file:
|
||||||
json.dump(patches, new_patches_file, indent=4, sort_keys=True)
|
json.dump(patches, new_patches_file, indent=4, sort_keys=True)
|
||||||
new_patches_file.write('\n')
|
new_patches_file.write('\n')
|
||||||
os.rename(HARDENED_PATCHES_PATH + '.new', HARDENED_PATCHES_PATH)
|
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)
|
print(message)
|
||||||
if os.environ.get('COMMIT'):
|
if os.environ.get('COMMIT'):
|
||||||
run(
|
run(
|
||||||
@ -125,74 +132,96 @@ NIX_VERSION_RE = re.compile(r'''
|
|||||||
''', re.VERBOSE)
|
''', re.VERBOSE)
|
||||||
|
|
||||||
# Get the set of currently packaged kernel versions.
|
# Get the set of currently packaged kernel versions.
|
||||||
kernel_versions = set()
|
kernel_versions = {}
|
||||||
for filename in os.listdir(HERE):
|
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:
|
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:
|
with open(os.path.join(HERE, filename)) as nix_file:
|
||||||
for nix_line in nix_file:
|
for nix_line in nix_file:
|
||||||
match = NIX_VERSION_RE.fullmatch(nix_line)
|
match = NIX_VERSION_RE.fullmatch(nix_line)
|
||||||
if match:
|
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.
|
# Remove patches for unpackaged kernel versions.
|
||||||
for kernel_version in patches.keys() - kernel_versions:
|
for kernel_key in sorted(patches.keys() - kernel_versions.keys()):
|
||||||
del patches[kernel_version]
|
commit_patches(kernel_key=kernel_key, message='remove')
|
||||||
commit_patches(kernel_version=kernel_version, message='remove')
|
|
||||||
|
|
||||||
g = Github(os.environ.get('GITHUB_TOKEN'))
|
g = Github(os.environ.get('GITHUB_TOKEN'))
|
||||||
repo = g.get_repo(HARDENED_GITHUB_REPO)
|
repo = g.get_repo(HARDENED_GITHUB_REPO)
|
||||||
releases = repo.get_releases()
|
|
||||||
|
|
||||||
found_kernel_versions = set()
|
|
||||||
failures = False
|
failures = False
|
||||||
|
|
||||||
for release in releases:
|
# Match each kernel version with the best patch version.
|
||||||
remaining_kernel_versions = kernel_versions - found_kernel_versions
|
releases = {}
|
||||||
|
for release in repo.get_releases():
|
||||||
if not remaining_kernel_versions:
|
version = parse_version(release.tag_name)
|
||||||
break
|
# needs to look like e.g. 5.6.3.a
|
||||||
|
if len(version) < 4:
|
||||||
version = release.tag_name
|
|
||||||
name = f'linux-hardened-{version}'
|
|
||||||
version_info = parse_version(version)
|
|
||||||
if not version_info:
|
|
||||||
continue
|
continue
|
||||||
kernel_version, version_suffix = version_info
|
|
||||||
|
|
||||||
if kernel_version in remaining_kernel_versions:
|
kernel_version = version[:-1]
|
||||||
found_kernel_versions.add(kernel_version)
|
kernel_key = major_kernel_version_key(kernel_version)
|
||||||
try:
|
try:
|
||||||
old_version_suffix = patches[kernel_version]['version_suffix']
|
packaged_kernel_version = kernel_versions[kernel_key]
|
||||||
old_version = f'{kernel_version}.{old_version_suffix}'
|
except KeyError:
|
||||||
update = old_version_suffix < version_suffix
|
continue
|
||||||
except KeyError:
|
|
||||||
update = True
|
|
||||||
old_version = None
|
|
||||||
|
|
||||||
if update:
|
release_info = {
|
||||||
patch = fetch_patch(name=name, release=release)
|
'version': version,
|
||||||
if patch is None:
|
'release': release,
|
||||||
failures = True
|
}
|
||||||
|
|
||||||
|
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:
|
else:
|
||||||
patch['version_suffix'] = version_suffix
|
message = f'init at {version_str}'
|
||||||
patches[kernel_version] = patch
|
commit_patches(kernel_key=kernel_key, message=message)
|
||||||
if old_version:
|
|
||||||
message = f'{old_version} -> {version}'
|
|
||||||
else:
|
|
||||||
message = f'init at {version}'
|
|
||||||
commit_patches(kernel_version=kernel_version, message=message)
|
|
||||||
|
|
||||||
missing_kernel_versions = kernel_versions - patches.keys()
|
missing_kernel_versions = kernel_versions.keys() - patches.keys()
|
||||||
|
|
||||||
if missing_kernel_versions:
|
if missing_kernel_versions:
|
||||||
print(
|
print(
|
||||||
f'warning: no patches for kernel versions ' +
|
f'warning: no patches for kernel versions ' +
|
||||||
', '.join(missing_kernel_versions) +
|
', '.join(missing_kernel_versions),
|
||||||
'\nwarning: consider manually backporting older patches (bump '
|
|
||||||
'JSON key, set version_suffix to "NixOS-a")',
|
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17047,7 +17047,7 @@ in
|
|||||||
};
|
};
|
||||||
kernelPatches = kernel.kernelPatches ++ [
|
kernelPatches = kernel.kernelPatches ++ [
|
||||||
kernelPatches.tag_hardened
|
kernelPatches.tag_hardened
|
||||||
kernelPatches.hardened.${kernel.version}
|
kernelPatches.hardened.${kernel.meta.branch}
|
||||||
];
|
];
|
||||||
modDirVersionArg = kernel.modDirVersion + "-hardened";
|
modDirVersionArg = kernel.modDirVersion + "-hardened";
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user