This module performs input/output.
"""
-# pylint: disable=missing-function-docstring,line-too-long,invalid-name,too-many-branches,too-many-statements
+# pylint: disable=missing-function-docstring,line-too-long,too-many-branches,too-many-statements
+import os
import gzip
import sys
from argparse import ArgumentParser
from typing import List, Tuple, Dict, TextIO
import re
import json
-from .__about__ import __version__
from .checks import add_kconfig_checks, add_cmdline_checks, normalize_cmdline_options, add_sysctl_checks
-from .engine import StrOrNone, TupleOrNone, ChecklistObjType, print_unknown_options, populate_with_data, perform_checks, override_expected_value
+from .engine import StrOrNone, TupleOrNone, ChecklistObjType
+from .engine import print_unknown_options, populate_with_data, perform_checks, override_expected_value
-def _open(file: str, *args, **kwargs) -> TextIO:
- if file.endswith('.gz'):
- return gzip.open(file, *args, **kwargs)
- return open(file, *args, **kwargs)
+# kernel-hardening-checker version
+__version__ = '0.6.6'
+
+
+def _open(file: str) -> TextIO:
+ try:
+ if file.endswith('.gz'):
+ return gzip.open(file, 'rt', encoding='utf-8')
+ return open(file, 'rt', encoding='utf-8')
+ except FileNotFoundError:
+ sys.exit(f'[!] ERROR: unable to open {file}, are you sure it exists?')
def detect_arch(fname: str, archs: List[str]) -> Tuple[StrOrNone, str]:
- with _open(fname, 'rt', encoding='utf-8') as f:
+ with _open(fname) as f:
arch_pattern = re.compile(r"CONFIG_[a-zA-Z0-9_]+=y$")
arch = None
for line in f.readlines():
def detect_kernel_version(fname: str) -> Tuple[TupleOrNone, str]:
- with _open(fname, 'rt', encoding='utf-8') as f:
+ with _open(fname) as f:
ver_pattern = re.compile(r"^# Linux/.+ Kernel Configuration$|^Linux version .+")
for line in f.readlines():
if ver_pattern.match(line):
ver_str = parts[2].split('-', 1)[0]
ver_numbers = ver_str.split('.')
if len(ver_numbers) >= 3:
- if all(map(lambda x: x.isdigit(), ver_numbers)):
+ if all(map(lambda x: x.isdecimal(), ver_numbers)):
return tuple(map(int, ver_numbers)), 'OK'
msg = f'failed to parse the version "{parts[2]}"'
return None, msg
def detect_compiler(fname: str) -> Tuple[StrOrNone, str]:
gcc_version = None
clang_version = None
- with _open(fname, 'rt', encoding='utf-8') as f:
+ with _open(fname) as f:
for line in f.readlines():
if line.startswith('CONFIG_GCC_VERSION='):
gcc_version = line[19:-1]
ok_count += 1
if mode == 'show_fail':
continue
- elif opt.result.startswith('FAIL'):
+ else:
+ assert(opt.result.startswith('FAIL')), \
+ f'unexpected result "{opt.result}" of {opt.name} check'
fail_count += 1
if mode == 'show_ok':
continue
- else:
- assert(False), f'unexpected result "{opt.result}" of {opt.name} check'
opt.table_print(mode, with_results)
print()
if mode == 'verbose':
def parse_kconfig_file(_mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None:
- with _open(fname, 'rt', encoding='utf-8') as f:
+ with _open(fname) as f:
opt_is_on = re.compile(r"CONFIG_[a-zA-Z0-9_]+=.+$")
opt_is_off = re.compile(r"# CONFIG_[a-zA-Z0-9_]+ is not set$")
def parse_cmdline_file(mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None:
+ if not os.path.isfile(fname):
+ sys.exit(f'[!] ERROR: unable to open {fname}, are you sure it exists?')
+
with open(fname, 'r', encoding='utf-8') as f:
line = f.readline()
+ if not line:
+ sys.exit(f'[!] ERROR: empty "{fname}"')
+
opts = line.split()
line = f.readline()
def parse_sysctl_file(mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None:
+ if not os.path.isfile(fname):
+ sys.exit(f'[!] ERROR: unable to open {fname}, are you sure it exists?')
+
with open(fname, 'r', encoding='utf-8') as f:
sysctl_pattern = re.compile(r"[a-zA-Z0-9/\._-]+ =.*$")
for line in f.readlines():