From 24c2654fcbc7c0dcd9a1d51e1720f8160d4f5931 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 13 May 2024 19:03:19 +0300 Subject: [PATCH] Use dict instead of OrderedDict Changed in Python version 3.7: Dictionary order is guaranteed to be insertion order. This makes the code simpler and faster. --- kernel_hardening_checker/__init__.py | 17 +++++----- kernel_hardening_checker/engine.py | 14 ++++----- kernel_hardening_checker/test_engine.py | 41 ++++++++++++------------- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/kernel_hardening_checker/__init__.py b/kernel_hardening_checker/__init__.py index 601619e..182f76f 100644 --- a/kernel_hardening_checker/__init__.py +++ b/kernel_hardening_checker/__init__.py @@ -13,8 +13,7 @@ This module performs input/output. import gzip import sys from argparse import ArgumentParser -from collections import OrderedDict -from typing import List, Tuple, OrderedDict, TextIO +from typing import List, Tuple, Dict, TextIO import re import json from .__about__ import __version__ @@ -132,7 +131,7 @@ def print_checklist(mode: StrOrNone, checklist: List[ChecklistObjType], with_res print(f'[+] Config check is finished: \'OK\' - {ok_count}{ok_suppressed} / \'FAIL\' - {fail_count}{fail_suppressed}') -def parse_kconfig_file(_mode: StrOrNone, parsed_options: OrderedDict[str, str], fname: str) -> None: +def parse_kconfig_file(_mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None: with _open(fname, 'rt', encoding='utf-8') 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$") @@ -161,7 +160,7 @@ def parse_kconfig_file(_mode: StrOrNone, parsed_options: OrderedDict[str, str], parsed_options[option] = value -def parse_cmdline_file(mode: StrOrNone, parsed_options: OrderedDict[str, str], fname: str) -> None: +def parse_cmdline_file(mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None: with open(fname, 'r', encoding='utf-8') as f: line = f.readline() opts = line.split() @@ -183,7 +182,7 @@ def parse_cmdline_file(mode: StrOrNone, parsed_options: OrderedDict[str, str], f parsed_options[name] = value -def parse_sysctl_file(mode: StrOrNone, parsed_options: OrderedDict[str, str], fname: str) -> None: +def parse_sysctl_file(mode: StrOrNone, parsed_options: Dict[str, str], fname: str) -> None: with open(fname, 'r', encoding='utf-8') as f: sysctl_pattern = re.compile(r"[a-zA-Z0-9/\._-]+ =.*$") for line in f.readlines(): @@ -290,7 +289,7 @@ def main() -> None: add_sysctl_checks(config_checklist, arch) # populate the checklist with the parsed Kconfig data - parsed_kconfig_options = OrderedDict() # type: OrderedDict[str, str] + parsed_kconfig_options = {} # type: Dict[str, str] parse_kconfig_file(mode, parsed_kconfig_options, args.config) populate_with_data(config_checklist, parsed_kconfig_options, 'kconfig') @@ -299,13 +298,13 @@ def main() -> None: if args.cmdline: # populate the checklist with the parsed cmdline data - parsed_cmdline_options = OrderedDict() # type: OrderedDict[str, str] + parsed_cmdline_options = {} # type: Dict[str, str] parse_cmdline_file(mode, parsed_cmdline_options, args.cmdline) populate_with_data(config_checklist, parsed_cmdline_options, 'cmdline') if args.sysctl: # populate the checklist with the parsed sysctl data - parsed_sysctl_options = OrderedDict() # type: OrderedDict[str, str] + parsed_sysctl_options = {} # type: Dict[str, str] parse_sysctl_file(mode, parsed_sysctl_options, args.sysctl) populate_with_data(config_checklist, parsed_sysctl_options, 'sysctl') @@ -350,7 +349,7 @@ def main() -> None: add_sysctl_checks(config_checklist, None) # populate the checklist with the parsed sysctl data - parsed_sysctl_options = OrderedDict() + parsed_sysctl_options = {} parse_sysctl_file(mode, parsed_sysctl_options, args.sysctl) populate_with_data(config_checklist, parsed_sysctl_options, 'sysctl') diff --git a/kernel_hardening_checker/engine.py b/kernel_hardening_checker/engine.py index a816c29..7195bc0 100644 --- a/kernel_hardening_checker/engine.py +++ b/kernel_hardening_checker/engine.py @@ -14,10 +14,10 @@ This module is the engine of checks. from __future__ import annotations import sys -from typing import Union, Optional, List, Dict, OrderedDict, Tuple +from typing import Union, Optional, List, Dict, Tuple StrOrNone = Optional[str] TupleOrNone = Optional[Tuple] -TupleOrOrderedDict = Union[Tuple, OrderedDict[str, str]] +DictOrTuple = Union[Dict[str, str], Tuple] StrOrBool = Union[str, bool] GREEN_COLOR = '\x1b[32m' @@ -338,7 +338,7 @@ ChecklistObjType = Union[KconfigCheck, CmdlineCheck, SysctlCheck, OR, AND] AnyOptCheckType = Union[KconfigCheck, CmdlineCheck, SysctlCheck, VersionCheck, OR, AND] -def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedDict, data_type: str) -> None: +def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: DictOrTuple, data_type: str) -> None: assert(opt.opt_type != 'complex'), f'unexpected opt_type "{opt.opt_type}" for {opt}' assert(opt.opt_type in SIMPLE_OPTION_TYPES), f'invalid opt_type "{opt.opt_type}"' assert(data_type in SIMPLE_OPTION_TYPES), f'invalid data_type "{data_type}"' @@ -348,7 +348,7 @@ def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedD return if data_type in ('kconfig', 'cmdline', 'sysctl'): - assert(isinstance(data, OrderedDict)), \ + assert(isinstance(data, dict)), \ f'unexpected data with data_type {data_type}' assert(isinstance(opt, SimpleNamedOptCheckTypes)), \ f'unexpected VersionCheck with opt_type "{opt.opt_type}"' @@ -361,7 +361,7 @@ def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedD opt.set_state(data) -def populate_opt_with_data(opt: AnyOptCheckType, data: TupleOrOrderedDict, data_type: str) -> None: +def populate_opt_with_data(opt: AnyOptCheckType, data: DictOrTuple, data_type: str) -> None: assert(opt.opt_type != 'version'), 'a single VersionCheck is useless' if opt.opt_type != 'complex': assert(isinstance(opt, SimpleOptCheckTypes)), \ @@ -380,7 +380,7 @@ def populate_opt_with_data(opt: AnyOptCheckType, data: TupleOrOrderedDict, data_ populate_opt_with_data(o, data, data_type) -def populate_with_data(checklist: List[ChecklistObjType], data: TupleOrOrderedDict, data_type: str) -> None: +def populate_with_data(checklist: List[ChecklistObjType], data: DictOrTuple, data_type: str) -> None: for opt in checklist: populate_opt_with_data(opt, data, data_type) @@ -398,7 +398,7 @@ def perform_checks(checklist: List[ChecklistObjType]) -> None: opt.check() -def print_unknown_options(checklist: List[ChecklistObjType], parsed_options: OrderedDict[str, str], opt_type: str) -> None: +def print_unknown_options(checklist: List[ChecklistObjType], parsed_options: Dict[str, str], opt_type: str) -> None: known_options = [] for o1 in checklist: diff --git a/kernel_hardening_checker/test_engine.py b/kernel_hardening_checker/test_engine.py index 3e5e60c..d1745b3 100644 --- a/kernel_hardening_checker/test_engine.py +++ b/kernel_hardening_checker/test_engine.py @@ -13,10 +13,9 @@ This module performs unit-testing of the kernel-hardening-checker engine. import unittest import io import sys -from collections import OrderedDict import json import inspect -from typing import Optional, List, OrderedDict, Tuple +from typing import Optional, List, Dict, Tuple from .engine import ChecklistObjType, KconfigCheck, CmdlineCheck, SysctlCheck, VersionCheck, OR, AND, populate_with_data, perform_checks, override_expected_value @@ -31,15 +30,15 @@ class TestEngine(unittest.TestCase): config_checklist += [SysctlCheck('reason_3', 'decision_3', 'sysctl_name', 'expected_3')] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_KCONFIG_NAME'] = 'UNexpected_1' # 3. prepare the parsed cmdline options - parsed_cmdline_options = OrderedDict() + parsed_cmdline_options = {} parsed_cmdline_options['cmdline_name'] = 'expected_2' # 4. prepare the parsed sysctl options - parsed_sysctl_options = OrderedDict() + parsed_sysctl_options = {} parsed_sysctl_options['sysctl_name'] = 'expected_3' # 5. prepare the kernel version @@ -58,9 +57,9 @@ class TestEngine(unittest.TestCase): @staticmethod def run_engine(checklist: List[ChecklistObjType], - parsed_kconfig_options: Optional[OrderedDict], - parsed_cmdline_options: Optional[OrderedDict], - parsed_sysctl_options: Optional[OrderedDict], + parsed_kconfig_options: Optional[Dict], + parsed_cmdline_options: Optional[Dict], + parsed_sysctl_options: Optional[Dict], kernel_version: Optional[Tuple]) -> None: # populate the checklist with data if parsed_kconfig_options: @@ -126,7 +125,7 @@ class TestEngine(unittest.TestCase): config_checklist += [KconfigCheck('reason_10', 'decision_10', 'NAME_10', 'is not off')] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'expected_1' parsed_kconfig_options['CONFIG_NAME_2'] = 'UNexpected_2' parsed_kconfig_options['CONFIG_NAME_5'] = 'UNexpected_5' @@ -169,7 +168,7 @@ class TestEngine(unittest.TestCase): config_checklist += [CmdlineCheck('reason_10', 'decision_10', 'name_10', 'is not off')] # 2. prepare the parsed cmdline options - parsed_cmdline_options = OrderedDict() + parsed_cmdline_options = {} parsed_cmdline_options['name_1'] = 'expected_1' parsed_cmdline_options['name_2'] = 'UNexpected_2' parsed_cmdline_options['name_5'] = '' @@ -212,7 +211,7 @@ class TestEngine(unittest.TestCase): config_checklist += [SysctlCheck('reason_10', 'decision_10', 'name_10', 'is not off')] # 2. prepare the parsed sysctl options - parsed_sysctl_options = OrderedDict() + parsed_sysctl_options = {} parsed_sysctl_options['name_1'] = 'expected_1' parsed_sysctl_options['name_2'] = 'UNexpected_2' parsed_sysctl_options['name_5'] = '' @@ -257,7 +256,7 @@ class TestEngine(unittest.TestCase): KconfigCheck('reason_12', 'decision_12', 'NAME_12', 'is not off'))] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'expected_1' parsed_kconfig_options['CONFIG_NAME_2'] = 'UNexpected_2' parsed_kconfig_options['CONFIG_NAME_3'] = 'UNexpected_3' @@ -300,7 +299,7 @@ class TestEngine(unittest.TestCase): KconfigCheck('reason_12', 'decision_12', 'NAME_12', 'is not off'))] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'expected_1' parsed_kconfig_options['CONFIG_NAME_2'] = 'expected_2' parsed_kconfig_options['CONFIG_NAME_3'] = 'expected_3' @@ -345,7 +344,7 @@ class TestEngine(unittest.TestCase): KconfigCheck('reason_12', 'decision_12', 'NAME_12', 'expected_12')))] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'expected_1' parsed_kconfig_options['CONFIG_NAME_2'] = 'UNexpected_2' parsed_kconfig_options['CONFIG_NAME_3'] = 'expected_3' @@ -390,7 +389,7 @@ class TestEngine(unittest.TestCase): VersionCheck((42, 43, 45)))] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_2'] = 'expected_2' parsed_kconfig_options['CONFIG_NAME_4'] = 'expected_4' parsed_kconfig_options['CONFIG_NAME_6'] = 'expected_6' @@ -425,16 +424,16 @@ class TestEngine(unittest.TestCase): SysctlCheck('reason_6', 'decision_6', 'name_6', 'expected_6'))] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'UNexpected_1' # 3. prepare the parsed cmdline options - parsed_cmdline_options = OrderedDict() + parsed_cmdline_options = {} parsed_cmdline_options['name_2'] = 'expected_2' parsed_cmdline_options['name_5'] = 'UNexpected_5' # 4. prepare the parsed sysctl options - parsed_sysctl_options = OrderedDict() + parsed_sysctl_options = {} parsed_sysctl_options['name_6'] = 'expected_6' # 5. run the engine @@ -487,15 +486,15 @@ name_6 |sysctl | expected_6 |decision_6| re config_checklist += [SysctlCheck('reason_3', 'decision_3', 'name_3', 'expected_3')] # 2. prepare the parsed kconfig options - parsed_kconfig_options = OrderedDict() + parsed_kconfig_options = {} parsed_kconfig_options['CONFIG_NAME_1'] = 'expected_1_new' # 3. prepare the parsed cmdline options - parsed_cmdline_options = OrderedDict() + parsed_cmdline_options = {} parsed_cmdline_options['name_2'] = 'expected_2_new' # 4. prepare the parsed sysctl options - parsed_sysctl_options = OrderedDict() + parsed_sysctl_options = {} parsed_sysctl_options['name_3'] = 'expected_3_new' # 5. run the engine -- 2.31.1