Skip to content

Commit

Permalink
Merge branch 'arch_mmap_rnd'
Browse files Browse the repository at this point in the history
Refers to #164, #146
  • Loading branch information
a13xp0p0v committed Nov 9, 2024
2 parents e4896e0 + d7fa8eb commit fab8d79
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 14 deletions.
39 changes: 26 additions & 13 deletions kernel_hardening_checker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,18 @@ def parse_sysctl_file(mode: StrOrNone, parsed_options: Dict[str, str], fname: st
print(f'[!] WARNING: sysctl options available for root are not found in {fname}, please use the output of `sudo sysctl -a`')


def refine_check(mode: StrOrNone, checklist: List[ChecklistObjType], parsed_options: Dict[str, str],
target: str, source: str) -> None:
source_val = parsed_options.get(source, None)
if source_val:
override_expected_value(checklist, target, source_val)
else:
# remove the target check to avoid false results
if mode != 'json':
print(f'[-] Can\'t check {target} without {source}')
checklist[:] = [o for o in checklist if o.name != target]


def perform_checking(mode: StrOrNone, version: TupleOrNone,
kconfig: StrOrNone, cmdline: StrOrNone, sysctl: StrOrNone) -> None:
config_checklist = [] # type: List[ChecklistObjType]
Expand Down Expand Up @@ -296,21 +308,17 @@ def perform_checking(mode: StrOrNone, version: TupleOrNone,
# populate the checklist with the kernel version data
populate_with_data(config_checklist, version, 'version')

parsed_kconfig_options = {} # type: Dict[str, str]
if kconfig:
# populate the checklist with the parsed Kconfig data
parsed_kconfig_options = {} # type: Dict[str, str]
parse_kconfig_file(mode, parsed_kconfig_options, kconfig)
populate_with_data(config_checklist, parsed_kconfig_options, 'kconfig')

# 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)
else:
# remove the CONFIG_ARCH_MMAP_RND_BITS check to avoid false results
if mode != 'json':
print('[-] Can\'t check CONFIG_ARCH_MMAP_RND_BITS without CONFIG_ARCH_MMAP_RND_BITS_MAX')
config_checklist[:] = [o for o in config_checklist if o.name != 'CONFIG_ARCH_MMAP_RND_BITS']
# refine the values of some checks
refine_check(mode, config_checklist, parsed_kconfig_options,
'CONFIG_ARCH_MMAP_RND_BITS', 'CONFIG_ARCH_MMAP_RND_BITS_MAX')
refine_check(mode, config_checklist, parsed_kconfig_options,
'CONFIG_ARCH_MMAP_RND_COMPAT_BITS', 'CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX')
# and don't forget to skip these Kconfig checks in --generate

if cmdline:
# populate the checklist with the parsed cmdline data
Expand All @@ -323,6 +331,11 @@ def perform_checking(mode: StrOrNone, version: TupleOrNone,
parsed_sysctl_options = {} # type: Dict[str, str]
parse_sysctl_file(mode, parsed_sysctl_options, sysctl)
populate_with_data(config_checklist, parsed_sysctl_options, 'sysctl')
# refine the values of some checks
refine_check(mode, config_checklist, parsed_kconfig_options,
'vm.mmap_rnd_bits', 'CONFIG_ARCH_MMAP_RND_BITS_MAX')
refine_check(mode, config_checklist, parsed_kconfig_options,
'vm.mmap_rnd_compat_bits', 'CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX')

# now everything is ready, perform the checks
perform_checks(config_checklist)
Expand Down Expand Up @@ -441,8 +454,8 @@ 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 == 'CONFIG_ARCH_MMAP_RND_BITS':
continue # don't add CONFIG_ARCH_MMAP_RND_BITS because its value needs refinement
if opt.name in ('CONFIG_ARCH_MMAP_RND_BITS', 'CONFIG_ARCH_MMAP_RND_COMPAT_BITS'):
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
if opt.expected == 'is not set':
Expand Down
9 changes: 8 additions & 1 deletion kernel_hardening_checker/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,10 @@ def add_kconfig_checks(l: List[ChecklistObjType], arch: str) -> None:
if arch in ('ARM', 'X86_32'):
l += [KconfigCheck('harden_userspace', 'defconfig', 'VMSPLIT_3G', 'y')]
l += [KconfigCheck('harden_userspace', 'clipos', 'COREDUMP', 'is not set')]
l += [KconfigCheck('harden_userspace', 'a13xp0p0v', 'ARCH_MMAP_RND_BITS', 'MAX')] # 'MAX' value is refined using ARCH_MMAP_RND_BITS_MAX
l += [KconfigCheck('harden_userspace', 'a13xp0p0v', 'ARCH_MMAP_RND_BITS', 'MAX')]
# 'MAX' value is refined using ARCH_MMAP_RND_BITS_MAX
l += [KconfigCheck('harden_userspace', 'a13xp0p0v', 'ARCH_MMAP_RND_COMPAT_BITS', 'MAX')]
# 'MAX' value is refined using ARCH_MMAP_RND_COMPAT_BITS_MAX
if arch == 'X86_64':
l += [KconfigCheck('harden_userspace', 'kspp', 'X86_USER_SHADOW_STACK', 'y')]

Expand Down Expand Up @@ -788,3 +791,7 @@ def add_sysctl_checks(l: List[ChecklistObjType], arch: StrOrNone) -> None:
l += [SysctlCheck('harden_userspace', 'kspp', 'fs.suid_dumpable', '0')]
l += [SysctlCheck('harden_userspace', 'kspp', 'kernel.randomize_va_space', '2')]
l += [SysctlCheck('harden_userspace', 'kspp', 'kernel.yama.ptrace_scope', '3')]
l += [SysctlCheck('harden_userspace', 'a13xp0p0v', 'vm.mmap_rnd_bits', 'MAX')]
# 'MAX' value is refined using ARCH_MMAP_RND_BITS_MAX
l += [SysctlCheck('harden_userspace', 'a13xp0p0v', 'vm.mmap_rnd_compat_bits', 'MAX')]
# 'MAX' value is refined using ARCH_MMAP_RND_COMPAT_BITS_MAX

0 comments on commit fab8d79

Please sign in to comment.