#
#
# N.B Hardening command line parameters:
-# page_poison=1
# slub_debug=FZP
# slab_nomerge
# kernel.kptr_restrict=1
# lockdown=1 (is it changed?)
# page_alloc.shuffle=1
# iommu=force (does it help against DMA attacks?)
+# page_poison=1 (if enabled)
#
# Mitigations of CPU vulnerabilities:
# Аrch-independent:
with open(fname, 'r') as f:
arch_pattern = re.compile("CONFIG_[a-zA-Z0-9_]*=y")
arch = None
- msg = None
if not json_mode:
print('[+] Trying to detect architecture in "{}"...'.format(fname))
for line in f.readlines():
return arch, 'OK'
+def detect_version(fname):
+ with open(fname, 'r') as f:
+ ver_pattern = re.compile("# Linux/.* Kernel Configuration")
+ if not json_mode:
+ print('[+] Trying to detect kernel version in "{}"...'.format(fname))
+ for line in f.readlines():
+ if ver_pattern.match(line):
+ line = line.strip()
+ if not json_mode:
+ print('[+] Found version line: "{}"'.format(line))
+ parts = line.split()
+ 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 + '"'
+ return None, msg
+ else:
+ return (int(ver_numbers[0]), int(ver_numbers[1])), None
+ return None, 'no kernel version detected'
+
+
def construct_checklist(checklist, arch):
modules_not_set = OptCheck('MODULES', 'is not set', 'kspp', 'cut_attack_surface')
devmem_not_set = OptCheck('DEVMEM', 'is not set', 'kspp', 'cut_attack_surface') # refers to LOCK_DOWN_KERNEL
checklist.append(OR(OptCheck('STRICT_MODULE_RWX', 'y', 'defconfig', 'self_protection'), \
OptCheck('DEBUG_SET_MODULE_RONX', 'y', 'defconfig', 'self_protection'), \
modules_not_set)) # DEBUG_SET_MODULE_RONX was before v4.11
+ checklist.append(OptCheck('GCC_PLUGINS', 'y', 'defconfig', 'self_protection'))
if debug_mode or arch == 'X86_64' or arch == 'X86_32':
checklist.append(OptCheck('MICROCODE', 'y', 'defconfig', 'self_protection')) # is needed for mitigating CPU bugs
checklist.append(OptCheck('RETPOLINE', 'y', 'defconfig', 'self_protection'))
if debug_mode or arch == 'ARM':
checklist.append(OptCheck('VMSPLIT_3G', 'y', 'defconfig', 'self_protection'))
checklist.append(OptCheck('CPU_SW_DOMAIN_PAN', 'y', 'defconfig', 'self_protection'))
+ checklist.append(OptCheck('STACKPROTECTOR_PER_TASK', 'y', 'defconfig', 'self_protection'))
if debug_mode or arch == 'ARM64' or arch == 'ARM':
checklist.append(OptCheck('REFCOUNT_FULL', 'y', 'defconfig', 'self_protection'))
checklist.append(OptCheck('HARDEN_BRANCH_PREDICTOR', 'y', 'defconfig', 'self_protection'))
checklist.append(OptCheck('SLAB_FREELIST_RANDOM', 'y', 'kspp', 'self_protection'))
checklist.append(OptCheck('SHUFFLE_PAGE_ALLOCATOR', 'y', 'kspp', 'self_protection'))
checklist.append(OptCheck('FORTIFY_SOURCE', 'y', 'kspp', 'self_protection'))
- checklist.append(OptCheck('GCC_PLUGINS', 'y', 'kspp', 'self_protection'))
randstruct_is_set = OptCheck('GCC_PLUGIN_RANDSTRUCT', 'y', 'kspp', 'self_protection')
checklist.append(randstruct_is_set)
checklist.append(OptCheck('GCC_PLUGIN_LATENT_ENTROPY', 'y', 'kspp', 'self_protection'))
checklist.append(OptCheck('DEBUG_SG', 'y', 'kspp', 'self_protection'))
checklist.append(OptCheck('DEBUG_CREDENTIALS', 'y', 'kspp', 'self_protection'))
checklist.append(OptCheck('DEBUG_NOTIFIERS', 'y', 'kspp', 'self_protection'))
- page_poisoning_is_set = OptCheck('PAGE_POISONING', 'y', 'kspp', 'self_protection')
- checklist.append(page_poisoning_is_set)
hardened_usercopy_is_set = OptCheck('HARDENED_USERCOPY', 'y', 'kspp', 'self_protection')
checklist.append(hardened_usercopy_is_set)
checklist.append(AND(OptCheck('HARDENED_USERCOPY_FALLBACK', 'is not set', 'kspp', 'self_protection'), \
checklist.append(OR(OptCheck('INIT_STACK_ALL', 'y', 'clipos', 'self_protection'), \
OptCheck('GCC_PLUGIN_STRUCTLEAK_BYREF_ALL', 'y', 'kspp', 'self_protection')))
checklist.append(OptCheck('INIT_ON_ALLOC_DEFAULT_ON', 'y', 'clipos', 'self_protection'))
- checklist.append(OptCheck('INIT_ON_FREE_DEFAULT_ON', 'y', 'clipos', 'self_protection'))
+ checklist.append(OR(OptCheck('INIT_ON_FREE_DEFAULT_ON', 'y', 'clipos', 'self_protection'), \
+ OptCheck('PAGE_POISONING', 'y', 'kspp', 'self_protection')))
checklist.append(OptCheck('SECURITY_DMESG_RESTRICT', 'y', 'clipos', 'self_protection'))
checklist.append(OptCheck('DEBUG_VIRTUAL', 'y', 'clipos', 'self_protection'))
checklist.append(OptCheck('STATIC_USERMODEHELPER', 'y', 'clipos', 'self_protection')) # needs userspace support (systemd)
checklist.append(OptCheck('SLUB_DEBUG_ON', 'y', 'my', 'self_protection'))
checklist.append(OptCheck('RESET_ATTACK_MITIGATION', 'y', 'my', 'self_protection')) # needs userspace support (systemd)
- checklist.append(AND(OptCheck('PAGE_POISONING_NO_SANITY', 'is not set', 'my', 'self_protection'), \
- page_poisoning_is_set))
- checklist.append(AND(OptCheck('PAGE_POISONING_ZERO', 'is not set', 'my', 'self_protection'), \
- page_poisoning_is_set))
if debug_mode or arch == 'X86_64':
checklist.append(AND(OptCheck('AMD_IOMMU_V2', 'y', 'my', 'self_protection'), \
iommu_support_is_set))
if debug_mode or arch == 'X86_32':
checklist.append(OptCheck('PAGE_TABLE_ISOLATION', 'y', 'my', 'self_protection'))
- if debug_mode or arch == 'ARM':
- checklist.append(OptCheck('STACKPROTECTOR_PER_TASK', 'y', 'my', 'self_protection'))
if debug_mode or arch == 'X86_64' or arch == 'ARM64' or arch == 'X86_32':
checklist.append(OptCheck('SECURITY', 'y', 'defconfig', 'security_policy')) # and choose your favourite LSM
if debug_mode or arch == 'ARM':
checklist.append(OptCheck('SECURITY', 'y', 'kspp', 'security_policy')) # and choose your favourite LSM
- checklist.append(OptCheck('SECURITY_WRITABLE_HOOKS', 'is not set', 'defconfig', 'security_policy'))
checklist.append(OptCheck('SECURITY_YAMA', 'y', 'kspp', 'security_policy'))
checklist.append(OptCheck('SECURITY_LOADPIN', 'y', 'my', 'security_policy')) # needs userspace support
checklist.append(OptCheck('SECURITY_LOCKDOWN_LSM', 'y', 'my', 'security_policy'))
checklist.append(OptCheck('SECURITY_LOCKDOWN_LSM_EARLY', 'y', 'my', 'security_policy'))
checklist.append(OptCheck('LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY', 'y', 'my', 'security_policy'))
checklist.append(OptCheck('SECURITY_SAFESETID', 'y', 'my', 'security_policy'))
+ checklist.append(OptCheck('SECURITY_WRITABLE_HOOKS', 'is not set', 'my', 'security_policy'))
checklist.append(OptCheck('SECCOMP', 'y', 'defconfig', 'cut_attack_surface'))
checklist.append(OptCheck('SECCOMP_FILTER', 'y', 'defconfig', 'cut_attack_surface'))
print()
-def get_option_state(options, name):
- return options.get(name, None)
-
-
def perform_checks(checklist, parsed_options):
for opt in checklist:
if hasattr(opt, 'opts'):
+ # prepare ComplexOptCheck
for o in opt.opts:
- o.state = get_option_state(parsed_options, o.name)
+ o.state = parsed_options.get(o.name, None)
else:
- opt.state = get_option_state(parsed_options, opt.name)
+ # prepare OptCheck
+ opt.state = parsed_options.get(opt.name, None)
opt.check()
elif not json_mode:
print('[+] Detected architecture: {}'.format(arch))
+ kernel_version, msg = detect_version(args.config)
+ if not kernel_version:
+ sys.exit('[!] ERROR: {}'.format(msg))
+ elif not json_mode:
+ print('[+] Detected kernel version: {}.{}'.format(kernel_version[0], kernel_version[1]))
+
construct_checklist(config_checklist, arch)
check_config_file(config_checklist, args.config)
error_count = len(list(filter(lambda opt: opt.result.startswith('FAIL'), config_checklist)))