Skip to content

Commit

Permalink
parsing list-provided values implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
d1sgr4c3 committed Dec 21, 2024
1 parent 12eb32d commit ba0a56a
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 2 deletions.
2 changes: 1 addition & 1 deletion kernel_hardening_checker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ def main() -> None:
add_kconfig_checks(config_checklist, arch)
print(f'CONFIG_{arch}=y') # the Kconfig fragment should describe the microarchitecture
for opt in config_checklist:
if opt.name in ('CONFIG_ARCH_MMAP_RND_BITS', 'CONFIG_ARCH_MMAP_RND_COMPAT_BITS'):
if opt.name in ('CONFIG_ARCH_MMAP_RND_BITS', 'CONFIG_ARCH_MMAP_RND_COMPAT_BITS', 'CONFIG_LSM'):
continue # don't add Kconfig options with a value that needs refinement
if opt.expected == 'is not off':
continue # don't add Kconfig options without explicitly recommended values
Expand Down
10 changes: 10 additions & 0 deletions kernel_hardening_checker/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ def add_kconfig_checks(l: List[ChecklistObjType], arch: str) -> None:
l += [KconfigCheck('self_protection', 'kspp', 'STATIC_USERMODEHELPER', 'y')] # needs userspace support
l += [KconfigCheck('self_protection', 'kspp', 'SCHED_CORE', 'y')]
l += [KconfigCheck('self_protection', 'kspp', 'SECURITY_LOCKDOWN_LSM', 'y')]
major_lsm = OR(KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_SELINUX', 'y'),
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_APPARMOR', 'y'),
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_SMACK', 'y'),
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_TOMOYO', 'y'))
l += [AND(KconfigCheck('self_protection', 'kspp', 'LSM', '*lockdown*'),
major_lsm)]
l += [KconfigCheck('self_protection', 'kspp', 'SECURITY_LOCKDOWN_LSM_EARLY', 'y')]
l += [KconfigCheck('self_protection', 'kspp', 'LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY', 'y')]
l += [OR(KconfigCheck('self_protection', 'kspp', 'LIST_HARDENED', 'y'),
Expand Down Expand Up @@ -300,6 +306,10 @@ def add_kconfig_checks(l: List[ChecklistObjType], arch: str) -> None:
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_APPARMOR', 'y'),
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_SMACK', 'y'),
KconfigCheck('security_policy', 'a13xp0p0v', 'SECURITY_TOMOYO', 'y'))] # one of major LSMs implementing MAC
l += [AND(KconfigCheck('security_policy', 'kspp', 'LSM', '*yama*'),
major_lsm)]
l += [AND(KconfigCheck('security_policy', 'kspp', 'LSM', '*landlock*'),
major_lsm)]

# N.B. We don't use 'if arch' for the 'cut_attack_surface' checks that require 'is not set'.
# It makes the maintainance easier. These kernel options should be disabled anyway.
Expand Down
16 changes: 16 additions & 0 deletions kernel_hardening_checker/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ def set_state(self, data: StrOrNone) -> None:
self.state = data

def check(self) -> None:
# handle the *special* check
if self.expected.startswith('*') and self.expected.endswith('*'):
if self.state is not None:
if self.state.startswith('"') and self.state.endswith('"'):
option = self.expected.strip('*')
optlist = list(self.state.strip('"').split(','))
if option in optlist:
self.result = f'OK: {self.state}'
else:
self.result = f'FAIL: {self.state}'
else:
self.result = f'FAIL: {self.state}'
else:
self.result = f'FAIL: {self.state}'
return

# handle the 'is present' check
if self.expected == 'is present':
if self.state is None:
Expand Down
7 changes: 6 additions & 1 deletion kernel_hardening_checker/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ def test_simple_kconfig(self) -> None:
config_checklist += [KconfigCheck('reason_8', 'decision_8', 'NAME_8', 'is not off')]
config_checklist += [KconfigCheck('reason_9', 'decision_9', 'NAME_9', 'is not off')]
config_checklist += [KconfigCheck('reason_10', 'decision_10', 'NAME_10', 'is not off')]
config_checklist += [KconfigCheck('reason_11', 'decision_11', 'NAME_11', '*expected_11*')]
config_checklist += [KconfigCheck('reason_12', 'decision_12', 'NAME_11', '*expected_12*')]

# 2. prepare the parsed kconfig options
parsed_kconfig_options = {}
Expand All @@ -139,6 +141,7 @@ def test_simple_kconfig(self) -> None:
parsed_kconfig_options['CONFIG_NAME_7'] = 'really_not_off'
parsed_kconfig_options['CONFIG_NAME_8'] = 'off'
parsed_kconfig_options['CONFIG_NAME_9'] = '0'
parsed_kconfig_options['CONFIG_NAME_11'] = '"expected_11,something,UNexpected_12"'

# 3. run the engine
self.run_engine(config_checklist, parsed_kconfig_options, None, None, None)
Expand All @@ -157,7 +160,9 @@ def test_simple_kconfig(self) -> None:
{'option_name': 'CONFIG_NAME_7', 'type': 'kconfig', 'desired_val': 'is not off', 'decision': 'decision_7', 'reason': 'reason_7', 'check_result': 'OK: is not off, "really_not_off"', 'check_result_bool': True},
{'option_name': 'CONFIG_NAME_8', 'type': 'kconfig', 'desired_val': 'is not off', 'decision': 'decision_8', 'reason': 'reason_8', 'check_result': 'FAIL: is off', 'check_result_bool': False},
{'option_name': 'CONFIG_NAME_9', 'type': 'kconfig', 'desired_val': 'is not off', 'decision': 'decision_9', 'reason': 'reason_9', 'check_result': 'FAIL: is off, "0"', 'check_result_bool': False},
{'option_name': 'CONFIG_NAME_10', 'type': 'kconfig', 'desired_val': 'is not off', 'decision': 'decision_10', 'reason': 'reason_10', 'check_result': 'FAIL: is off, not found', 'check_result_bool': False}]
{'option_name': 'CONFIG_NAME_10', 'type': 'kconfig', 'desired_val': 'is not off', 'decision': 'decision_10', 'reason': 'reason_10', 'check_result': 'FAIL: is off, not found', 'check_result_bool': False},
{"option_name": 'CONFIG_NAME_11', 'type': 'kconfig', 'desired_val': '*expected_11*', 'decision': 'decision_11', 'reason': 'reason_11', "check_result": "OK: \"expected_11,something,UNexpected_12\"", "check_result_bool": True},
{"option_name": 'CONFIG_NAME_11', 'type': 'kconfig', 'desired_val': '*expected_12*', 'decision': 'decision_12', 'reason': 'reason_12', "check_result": "FAIL: \"expected_11,something,UNexpected_12\"", "check_result_bool": False}]
)

def test_simple_cmdline(self) -> None:
Expand Down

0 comments on commit ba0a56a

Please sign in to comment.