Merge pull request #85880 from emilazy/linux-hardened-update-resilience

This commit is contained in:
Jörg Thalheim 2020-04-24 12:24:23 +01:00 committed by GitHub
commit 16e4b9ca69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 87 deletions

View file

@ -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"
}
}

View file

@ -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;

View file

@ -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
version = release.tag_name
name = f'linux-hardened-{version}'
version_info = parse_version(version)
if not version_info:
# 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
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
kernel_version = version[:-1]
kernel_key = major_kernel_version_key(kernel_version)
try:
packaged_kernel_version = kernel_versions[kernel_key]
except KeyError:
continue
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,
)

View file

@ -17051,7 +17051,7 @@ in
};
kernelPatches = kernel.kernelPatches ++ [
kernelPatches.tag_hardened
kernelPatches.hardened.${kernel.version}
kernelPatches.hardened.${kernel.meta.branch}
];
modDirVersionArg = kernel.modDirVersion + "-hardened";
});