- checklist.append(OptCheck('LEGACY_VSYSCALL_NONE', 'y', 'kspp', 'cut_attack_surface')) # 'vsyscall=none'
- checklist.append(OptCheck('ACPI_CUSTOM_METHOD', 'is not set', 'kspp', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('COMPAT_BRK', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('DEVKMEM', 'is not set', 'kspp', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('COMPAT_VDSO', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('BINFMT_MISC', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('INET_DIAG', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('KEXEC', 'is not set', 'kspp', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('PROC_KCORE', 'is not set', 'kspp', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('LEGACY_PTYS', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('HIBERNATION', 'is not set', 'kspp', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('IA32_EMULATION', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('X86_X32', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('MODIFY_LDT_SYSCALL', 'is not set', 'kspp', 'cut_attack_surface'))
- checklist.append(OptCheck('OABI_COMPAT', 'is not set', 'kspp', 'cut_attack_surface'))
-
- checklist.append(OptCheck('X86_PTDUMP', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('ZSMALLOC_STAT', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('PAGE_OWNER', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('DEBUG_KMEMLEAK', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('BINFMT_AOUT', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('KPROBES', 'is not set', 'grsecurity', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('UPROBES', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('GENERIC_TRACER', 'is not set', 'grsecurity', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('PROC_VMCORE', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('PROC_PAGE_MONITOR', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('USELIB', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('CHECKPOINT_RESTORE', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('USERFAULTFD', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('HWPOISON_INJECT', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('MEM_SOFT_DIRTY', 'is not set', 'grsecurity', 'cut_attack_surface'))
- checklist.append(OptCheck('DEVPORT', 'is not set', 'grsecurity', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('DEBUG_FS', 'is not set', 'grsecurity', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('NOTIFIER_ERROR_INJECTION','is not set', 'grsecurity', 'cut_attack_surface'))
-
- checklist.append(OptCheck('ACPI_TABLE_UPGRADE', 'is not set', 'lockdown', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('X86_IOPL_IOPERM', 'is not set', 'lockdown', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('EFI_TEST', 'is not set', 'lockdown', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('BPF_SYSCALL', 'is not set', 'lockdown', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('MMIOTRACE_TEST', 'is not set', 'lockdown', 'cut_attack_surface')) # refers to LOCKDOWN
-
- if arch == 'X86_64' or arch == 'X86_32':
- checklist.append(OptCheck('X86_INTEL_TSX_MODE_OFF', 'y', 'clipos', 'cut_attack_surface')) # tsx=off
- checklist.append(OptCheck('STAGING', 'is not set', 'clipos', 'cut_attack_surface'))
- checklist.append(OptCheck('KSM', 'is not set', 'clipos', 'cut_attack_surface')) # to prevent FLUSH+RELOAD attack
-# checklist.append(OptCheck('IKCONFIG', 'is not set', 'clipos', 'cut_attack_surface')) # no, this info is needed for this check :)
- checklist.append(OptCheck('KALLSYMS', 'is not set', 'clipos', 'cut_attack_surface'))
- checklist.append(OptCheck('X86_VSYSCALL_EMULATION', 'is not set', 'clipos', 'cut_attack_surface'))
- checklist.append(OptCheck('MAGIC_SYSRQ', 'is not set', 'clipos', 'cut_attack_surface'))
- checklist.append(OptCheck('KEXEC_FILE', 'is not set', 'clipos', 'cut_attack_surface')) # refers to LOCKDOWN (permissive)
- checklist.append(OptCheck('USER_NS', 'is not set', 'clipos', 'cut_attack_surface')) # user.max_user_namespaces=0
- checklist.append(OptCheck('X86_MSR', 'is not set', 'clipos', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('X86_CPUID', 'is not set', 'clipos', 'cut_attack_surface'))
- checklist.append(AND(OptCheck('LDISC_AUTOLOAD', 'is not set', 'clipos', 'cut_attack_surface'), \
- VerCheck((5, 1)))) # LDISC_AUTOLOAD can be disabled since v5.1
-
- checklist.append(OptCheck('AIO', 'is not set', 'grapheneos', 'cut_attack_surface'))
-
- checklist.append(OptCheck('MMIOTRACE', 'is not set', 'my', 'cut_attack_surface')) # refers to LOCKDOWN (permissive)
- checklist.append(OptCheck('LIVEPATCH', 'is not set', 'my', 'cut_attack_surface'))
- checklist.append(OptCheck('IP_DCCP', 'is not set', 'my', 'cut_attack_surface'))
- checklist.append(OptCheck('IP_SCTP', 'is not set', 'my', 'cut_attack_surface'))
- checklist.append(OptCheck('FTRACE', 'is not set', 'my', 'cut_attack_surface')) # refers to LOCKDOWN
- checklist.append(OptCheck('BPF_JIT', 'is not set', 'my', 'cut_attack_surface'))
- checklist.append(OptCheck('VIDEO_VIVID', 'is not set', 'my', 'cut_attack_surface'))
-
- checklist.append(OptCheck('INTEGRITY', 'y', 'defconfig', 'userspace_hardening'))
- if arch == 'ARM64':
- checklist.append(OptCheck('ARM64_PTR_AUTH', 'y', 'defconfig', 'userspace_hardening'))
- if arch == 'ARM' or arch == 'X86_32':
- checklist.append(OptCheck('VMSPLIT_3G', 'y', 'defconfig', 'userspace_hardening'))
- if arch == 'X86_64' or arch == 'ARM64':
- checklist.append(OptCheck('ARCH_MMAP_RND_BITS', '32', 'clipos', 'userspace_hardening'))
- if arch == 'X86_32' or arch == 'ARM':
- checklist.append(OptCheck('ARCH_MMAP_RND_BITS', '16', 'my', 'userspace_hardening'))
-
-# checklist.append(OptCheck('LKDTM', 'm', 'my', 'feature_test'))
-
-
-def print_checklist(checklist, with_results):
- if json_mode:
- opts = []
+ l += [KconfigCheck('cut_attack_surface', 'kspp', 'LEGACY_VSYSCALL_NONE', 'y')] # 'vsyscall=none'
+
+ # 'cut_attack_surface', 'grsec'
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'ZSMALLOC_STAT', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'PAGE_OWNER', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'DEBUG_KMEMLEAK', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'BINFMT_AOUT', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'KPROBE_EVENTS', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'UPROBE_EVENTS', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'GENERIC_TRACER', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'FUNCTION_TRACER', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'STACK_TRACER', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'HIST_TRIGGERS', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'BLK_DEV_IO_TRACE', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'PROC_VMCORE', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'PROC_PAGE_MONITOR', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'USELIB', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'CHECKPOINT_RESTORE', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'USERFAULTFD', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'HWPOISON_INJECT', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'MEM_SOFT_DIRTY', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'DEVPORT', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'DEBUG_FS', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'NOTIFIER_ERROR_INJECTION', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'FAIL_FUTEX', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'PUNIT_ATOM_DEBUG', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'ACPI_CONFIGFS', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'EDAC_DEBUG', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'DRM_I915_DEBUG', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'BCACHE_CLOSURES_DEBUG', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'DVB_C8SECTPFE', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'MTD_SLRAM', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'MTD_PHRAM', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'IO_URING', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'KCMP', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'RSEQ', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'LATENCYTOP', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'KCOV', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'PROVIDE_OHCI1394_DMA_INIT', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'grsec', 'SUNRPC_DEBUG', 'is not set')]
+ l += [AND(KconfigCheck('cut_attack_surface', 'grsec', 'PTDUMP_DEBUGFS', 'is not set'),
+ KconfigCheck('cut_attack_surface', 'grsec', 'X86_PTDUMP', 'is not set'))]
+
+ # 'cut_attack_surface', 'maintainer'
+ l += [KconfigCheck('cut_attack_surface', 'maintainer', 'DRM_LEGACY', 'is not set')] # recommended by Daniel Vetter in /issues/38
+ l += [KconfigCheck('cut_attack_surface', 'maintainer', 'FB', 'is not set')] # recommended by Daniel Vetter in /issues/38
+ l += [KconfigCheck('cut_attack_surface', 'maintainer', 'VT', 'is not set')] # recommended by Daniel Vetter in /issues/38
+ l += [KconfigCheck('cut_attack_surface', 'maintainer', 'BLK_DEV_FD', 'is not set')] # recommended by Denis Efremov in /pull/54
+ l += [KconfigCheck('cut_attack_surface', 'maintainer', 'BLK_DEV_FD_RAWCMD', 'is not set')] # recommended by Denis Efremov in /pull/62
+
+ # 'cut_attack_surface', 'grapheneos'
+ l += [KconfigCheck('cut_attack_surface', 'grapheneos', 'AIO', 'is not set')]
+
+ # 'cut_attack_surface', 'clipos'
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'STAGING', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'KSM', 'is not set')] # to prevent FLUSH+RELOAD attack
+# l += [KconfigCheck('cut_attack_surface', 'clipos', 'IKCONFIG', 'is not set')] # no, IKCONFIG is needed for this check :)
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'KALLSYMS', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'X86_VSYSCALL_EMULATION', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'MAGIC_SYSRQ', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'KEXEC_FILE', 'is not set')] # refers to LOCKDOWN (permissive)
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'USER_NS', 'is not set')] # user.max_user_namespaces=0
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'X86_CPUID', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'X86_IOPL_IOPERM', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'ACPI_TABLE_UPGRADE', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'EFI_CUSTOM_SSDT_OVERLAYS', 'is not set')]
+ l += [AND(KconfigCheck('cut_attack_surface', 'clipos', 'LDISC_AUTOLOAD', 'is not set'),
+ KconfigCheck('cut_attack_surface', 'clipos', 'LDISC_AUTOLOAD'))] # option presence check
+ if arch in ('X86_64', 'X86_32'):
+ l += [KconfigCheck('cut_attack_surface', 'clipos', 'X86_INTEL_TSX_MODE_OFF', 'y')] # tsx=off
+
+ # 'cut_attack_surface', 'lockdown'
+ l += [bpf_syscall_not_set] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'lockdown', 'EFI_TEST', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'lockdown', 'MMIOTRACE_TEST', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'lockdown', 'KPROBES', 'is not set')] # refers to LOCKDOWN
+
+ # 'cut_attack_surface', 'my'
+ l += [OR(KconfigCheck('cut_attack_surface', 'my', 'TRIM_UNUSED_KSYMS', 'y'),
+ modules_not_set)]
+ l += [KconfigCheck('cut_attack_surface', 'my', 'MMIOTRACE', 'is not set')] # refers to LOCKDOWN (permissive)
+ l += [KconfigCheck('cut_attack_surface', 'my', 'LIVEPATCH', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'my', 'IP_DCCP', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'my', 'IP_SCTP', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'my', 'FTRACE', 'is not set')] # refers to LOCKDOWN
+ l += [KconfigCheck('cut_attack_surface', 'my', 'VIDEO_VIVID', 'is not set')]
+ l += [KconfigCheck('cut_attack_surface', 'my', 'INPUT_EVBUG', 'is not set')] # Can be used as a keylogger
+ l += [KconfigCheck('cut_attack_surface', 'my', 'KGDB', 'is not set')]
+
+ # 'harden_userspace'
+ if arch in ('X86_64', 'ARM64', 'X86_32'):
+ l += [KconfigCheck('harden_userspace', 'defconfig', 'INTEGRITY', 'y')]
+ if arch == 'ARM':
+ l += [KconfigCheck('harden_userspace', 'my', 'INTEGRITY', 'y')]
+ if arch in ('ARM', 'X86_32'):
+ l += [KconfigCheck('harden_userspace', 'defconfig', 'VMSPLIT_3G', 'y')]
+ if arch in ('X86_64', 'ARM64'):
+ l += [KconfigCheck('harden_userspace', 'clipos', 'ARCH_MMAP_RND_BITS', '32')]
+ if arch in ('X86_32', 'ARM'):
+ l += [KconfigCheck('harden_userspace', 'my', 'ARCH_MMAP_RND_BITS', '16')]
+
+# l += [KconfigCheck('feature_test', 'my', 'LKDTM', 'm')] # only for debugging!
+
+
+def add_cmdline_checks(l, arch):
+ # Calling the CmdlineCheck class constructor:
+ # CmdlineCheck(reason, decision, name, expected)
+
+ if arch in ('X86_64', 'X86_32'):
+ l += [CmdlineCheck('self_protection', 'kspp', 'pti', 'on')]
+ # TODO: add other
+
+
+def print_unknown_options(checklist, parsed_options):
+ known_options = []
+
+ for o1 in checklist:
+ if o1.type != 'complex':
+ known_options.append(o1.name)
+ continue
+ for o2 in o1.opts:
+ if o2.type != 'complex':
+ if hasattr(o2, 'name'):
+ known_options.append(o2.name)
+ continue
+ for o3 in o2.opts:
+ if o3.type == 'complex':
+ sys.exit('[!] ERROR: unexpected ComplexOptCheck inside {}'.format(o2.name))
+ if hasattr(o3, 'name'):
+ known_options.append(o3.name)
+
+ for option, value in parsed_options.items():
+ if option not in known_options:
+ print('[?] No check for option {} ({})'.format(option, value))
+
+
+def print_checklist(mode, checklist, with_results):
+ if mode == 'json':
+ output = []