X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig_hardened_check%2F__init__.py;h=cdb08288fa0f3ccf2b938cf88fb92462070da61f;hb=2588752f2803d58118f8d7b05ae16983cf588dc9;hp=f89ac983a1694012b8faefc586e294e5fe7fbd13;hpb=b4de795e6120b264cfacad74b96df508419c6076;p=kconfig-hardened-check.git diff --git a/kconfig_hardened_check/__init__.py b/kconfig_hardened_check/__init__.py index f89ac98..cdb0828 100644 --- a/kconfig_hardened_check/__init__.py +++ b/kconfig_hardened_check/__init__.py @@ -12,6 +12,7 @@ This module performs input/output. # pylint: disable=missing-function-docstring,line-too-long,invalid-name,too-many-branches,too-many-statements +import gzip import sys from argparse import ArgumentParser from collections import OrderedDict @@ -19,11 +20,19 @@ import re import json from .__about__ import __version__ from .checks import add_kconfig_checks, add_cmdline_checks, normalize_cmdline_options -from .engine import populate_with_data, perform_checks +from .engine import populate_with_data, perform_checks, override_expected_value + + +def _open(file: str, *args, **kwargs): + open_method = open + if file.endswith(".gz"): + open_method = gzip.open + + return open_method(file, *args, **kwargs) def detect_arch(fname, archs): - with open(fname, 'r', encoding='utf-8') as f: + with _open(fname, 'rt', encoding='utf-8') as f: arch_pattern = re.compile("CONFIG_[a-zA-Z0-9_]*=y") arch = None for line in f.readlines(): @@ -40,7 +49,7 @@ def detect_arch(fname, archs): def detect_kernel_version(fname): - with open(fname, 'r', encoding='utf-8') as f: + with _open(fname, 'rt', encoding='utf-8') as f: ver_pattern = re.compile("# Linux/.* Kernel Configuration") for line in f.readlines(): if ver_pattern.match(line): @@ -49,7 +58,7 @@ def detect_kernel_version(fname): ver_str = parts[2] ver_numbers = ver_str.split('.') if len(ver_numbers) < 3 or not ver_numbers[0].isdigit() or not ver_numbers[1].isdigit(): - msg = 'failed to parse the version "' + ver_str + '"' + msg = f'failed to parse the version "{ver_str}"' return None, msg return (int(ver_numbers[0]), int(ver_numbers[1])), None return None, 'no kernel version detected' @@ -58,7 +67,7 @@ def detect_kernel_version(fname): def detect_compiler(fname): gcc_version = None clang_version = None - with open(fname, 'r', encoding='utf-8') as f: + with _open(fname, 'rt', encoding='utf-8') as f: gcc_version_pattern = re.compile("CONFIG_GCC_VERSION=[0-9]*") clang_version_pattern = re.compile("CONFIG_CLANG_VERSION=[0-9]*") for line in f.readlines(): @@ -101,8 +110,8 @@ def print_unknown_options(checklist, parsed_options): def print_checklist(mode, checklist, with_results): if mode == 'json': output = [] - for o in checklist: - output.append(o.json_dump(with_results)) + for opt in checklist: + output.append(opt.json_dump(with_results)) print(json.dumps(output)) return @@ -111,7 +120,7 @@ def print_checklist(mode, checklist, with_results): if with_results: sep_line_len += 30 print('=' * sep_line_len) - print(f"{'option name':^40}|{'type':^7}|{'desired val':^12}|{'decision':^10}|{'reason':^18}", end='') + print(f'{"option name":^40}|{"type":^7}|{"desired val":^12}|{"decision":^10}|{"reason":^18}', end='') if with_results: print('| check result', end='') print() @@ -142,12 +151,11 @@ def print_checklist(mode, checklist, with_results): fail_suppressed = ' (suppressed in output)' if mode == 'show_fail': ok_suppressed = ' (suppressed in output)' - if mode != 'json': - print(f'[+] Config check is finished: \'OK\' - {ok_count}{ok_suppressed} / \'FAIL\' - {fail_count}{fail_suppressed}') + print(f'[+] Config check is finished: \'OK\' - {ok_count}{ok_suppressed} / \'FAIL\' - {fail_count}{fail_suppressed}') def parse_kconfig_file(parsed_options, fname): - with open(fname, 'r', encoding='utf-8') as f: + with _open(fname, 'rt', encoding='utf-8') as f: opt_is_on = re.compile("CONFIG_[a-zA-Z0-9_]*=[a-zA-Z0-9_\"]*") opt_is_off = re.compile("# CONFIG_[a-zA-Z0-9_]* is not set") @@ -205,7 +213,7 @@ def main(): parser.add_argument('-p', '--print', choices=supported_archs, help='print security hardening preferences for the selected architecture') parser.add_argument('-c', '--config', - help='check the kernel kconfig file against these preferences') + help='check the kernel kconfig file against these preferences (also supports *.gz files)') parser.add_argument('-l', '--cmdline', help='check the kernel cmdline file against these preferences') parser.add_argument('-m', '--mode', choices=report_modes, @@ -259,14 +267,21 @@ def main(): parsed_kconfig_options = OrderedDict() parse_kconfig_file(parsed_kconfig_options, args.config) populate_with_data(config_checklist, parsed_kconfig_options, 'kconfig') + + # populate the checklist with the kernel version data populate_with_data(config_checklist, kernel_version, 'version') if args.cmdline: - # populate the checklist with the parsed kconfig data + # populate the checklist with the parsed cmdline data parsed_cmdline_options = OrderedDict() parse_cmdline_file(parsed_cmdline_options, args.cmdline) populate_with_data(config_checklist, parsed_cmdline_options, 'cmdline') + # hackish refinement of the CONFIG_ARCH_MMAP_RND_BITS check + mmap_rnd_bits_max = parsed_kconfig_options.get('CONFIG_ARCH_MMAP_RND_BITS_MAX', None) + if mmap_rnd_bits_max: + override_expected_value(config_checklist, 'CONFIG_ARCH_MMAP_RND_BITS', mmap_rnd_bits_max) + # now everything is ready, perform the checks perform_checks(config_checklist)