Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
kernel-hardening-checker
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fact-depend
kernel-hardening-checker
Commits
328a89c7
Commit
328a89c7
authored
2 years ago
by
Alexander Popov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split into Python modules
parent
7799d8cf
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
860 additions
and
840 deletions
+860
-840
__init__.py
kconfig_hardened_check/__init__.py
+2
-840
checks.py
kconfig_hardened_check/checks.py
+578
-0
engine.py
kconfig_hardened_check/engine.py
+280
-0
No files found.
kconfig_hardened_check/__init__.py
View file @
328a89c7
#!/usr/bin/python3
#!/usr/bin/python3
#
# This tool helps me to check Linux kernel options against
# This tool helps me to check Linux kernel options against
# my security hardening preferences for X86_64, ARM64, X86_32, and ARM.
# my security hardening preferences for X86_64, ARM64, X86_32, and ARM.
# Let the computers do their job!
# Let the computers do their job!
...
@@ -8,274 +7,18 @@
...
@@ -8,274 +7,18 @@
# Author: Alexander Popov <alex.popov@linux.com>
# Author: Alexander Popov <alex.popov@linux.com>
#
#
# Please don't cry if my Python code looks like C.
# Please don't cry if my Python code looks like C.
#
#
# N.B. Hardening sysctls:
# kernel.kptr_restrict=2 (or 1?)
# kernel.dmesg_restrict=1 (also see the kconfig option)
# kernel.perf_event_paranoid=2 (or 3 with a custom patch, see https://lwn.net/Articles/696216/)
# kernel.kexec_load_disabled=1
# kernel.yama.ptrace_scope=3
# user.max_user_namespaces=0
# what about bpf_jit_enable?
# kernel.unprivileged_bpf_disabled=1
# net.core.bpf_jit_harden=2
# vm.unprivileged_userfaultfd=0
# (at first, it disabled unprivileged userfaultfd,
# and since v5.11 it enables unprivileged userfaultfd for user-mode only)
# vm.mmap_min_addr has a good value
# dev.tty.ldisc_autoload=0
# fs.protected_symlinks=1
# fs.protected_hardlinks=1
# fs.protected_fifos=2
# fs.protected_regular=2
# fs.suid_dumpable=0
# kernel.modules_disabled=1
# kernel.randomize_va_space = 2
# nosmt sysfs control file
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
# pylint: disable=line-too-long,invalid-name,too-many-branches,too-many-statements
# pylint: disable=line-too-long,invalid-name,too-many-branches,too-many-statements
import
sys
import
sys
from
argparse
import
ArgumentParser
from
argparse
import
ArgumentParser
from
collections
import
OrderedDict
from
collections
import
OrderedDict
import
re
import
re
import
json
import
json
from
.__about__
import
__version__
from
.__about__
import
__version__
from
.checks
import
add_kconfig_checks
,
add_cmdline_checks
,
normalize_cmdline_options
SIMPLE_OPTION_TYPES
=
(
'kconfig'
,
'version'
,
'cmdline'
)
from
.engine
import
populate_with_data
,
perform_checks
class
OptCheck
:
def
__init__
(
self
,
reason
,
decision
,
name
,
expected
):
assert
(
name
and
name
==
name
.
strip
()
and
len
(
name
.
split
())
==
1
),
\
f
'invalid name "{name}" for {self.__class__.__name__}'
self
.
name
=
name
assert
(
decision
and
decision
==
decision
.
strip
()
and
len
(
decision
.
split
())
==
1
),
\
f
'invalid decision "{decision}" for "{name}" check'
self
.
decision
=
decision
assert
(
reason
and
reason
==
reason
.
strip
()
and
len
(
reason
.
split
())
==
1
),
\
f
'invalid reason "{reason}" for "{name}" check'
self
.
reason
=
reason
assert
(
expected
and
expected
==
expected
.
strip
()),
\
f
'invalid expected value "{expected}" for "{name}" check (1)'
val_len
=
len
(
expected
.
split
())
if
val_len
==
3
:
assert
(
expected
in
(
'is not set'
,
'is not off'
)),
\
f
'invalid expected value "{expected}" for "{name}" check (2)'
elif
val_len
==
2
:
assert
(
expected
==
'is present'
),
\
f
'invalid expected value "{expected}" for "{name}" check (3)'
else
:
assert
(
val_len
==
1
),
\
f
'invalid expected value "{expected}" for "{name}" check (4)'
self
.
expected
=
expected
self
.
state
=
None
self
.
result
=
None
@property
def
type
(
self
):
return
None
def
check
(
self
):
# handle the 'is present' check
if
self
.
expected
==
'is present'
:
if
self
.
state
is
None
:
self
.
result
=
'FAIL: is not present'
else
:
self
.
result
=
'OK: is present'
return
# handle the 'is not off' option check
if
self
.
expected
==
'is not off'
:
if
self
.
state
==
'off'
:
self
.
result
=
'FAIL: is off'
if
self
.
state
==
'0'
:
self
.
result
=
'FAIL: is off, "0"'
elif
self
.
state
is
None
:
self
.
result
=
'FAIL: is off, not found'
else
:
self
.
result
=
'OK: is not off, "'
+
self
.
state
+
'"'
return
# handle the option value check
if
self
.
expected
==
self
.
state
:
self
.
result
=
'OK'
elif
self
.
state
is
None
:
if
self
.
expected
==
'is not set'
:
self
.
result
=
'OK: is not found'
else
:
self
.
result
=
'FAIL: is not found'
else
:
self
.
result
=
'FAIL: "'
+
self
.
state
+
'"'
def
table_print
(
self
,
_mode
,
with_results
):
print
(
f
'{self.name:<40}|{self.type:^7}|{self.expected:^12}|{self.decision:^10}|{self.reason:^18}'
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
def
json_dump
(
self
,
with_results
):
dump
=
[
self
.
name
,
self
.
type
,
self
.
expected
,
self
.
decision
,
self
.
reason
]
if
with_results
:
dump
.
append
(
self
.
result
)
return
dump
class
KconfigCheck
(
OptCheck
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
name
=
'CONFIG_'
+
self
.
name
@property
def
type
(
self
):
return
'kconfig'
class
CmdlineCheck
(
OptCheck
):
@property
def
type
(
self
):
return
'cmdline'
class
VersionCheck
:
def
__init__
(
self
,
ver_expected
):
assert
(
ver_expected
and
isinstance
(
ver_expected
,
tuple
)
and
len
(
ver_expected
)
==
2
),
\
f
'invalid version "{ver_expected}" for VersionCheck'
self
.
ver_expected
=
ver_expected
self
.
ver
=
()
self
.
result
=
None
@property
def
type
(
self
):
return
'version'
def
check
(
self
):
if
self
.
ver
[
0
]
>
self
.
ver_expected
[
0
]:
self
.
result
=
'OK: version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
if
self
.
ver
[
0
]
<
self
.
ver_expected
[
0
]:
self
.
result
=
'FAIL: version < '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
if
self
.
ver
[
1
]
>=
self
.
ver_expected
[
1
]:
self
.
result
=
'OK: version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
self
.
result
=
'FAIL: version < '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
def
table_print
(
self
,
_mode
,
with_results
):
ver_req
=
'kernel version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
print
(
f
'{ver_req:<91}'
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
class
ComplexOptCheck
:
def
__init__
(
self
,
*
opts
):
self
.
opts
=
opts
assert
(
self
.
opts
),
\
f
'empty {self.__class__.__name__} check'
assert
(
len
(
self
.
opts
)
!=
1
),
\
f
'useless {self.__class__.__name__} check: {opts}'
assert
(
isinstance
(
opts
[
0
],
(
KconfigCheck
,
CmdlineCheck
))),
\
f
'invalid {self.__class__.__name__} check: {opts}'
self
.
result
=
None
@property
def
type
(
self
):
return
'complex'
@property
def
name
(
self
):
return
self
.
opts
[
0
]
.
name
@property
def
expected
(
self
):
return
self
.
opts
[
0
]
.
expected
def
table_print
(
self
,
mode
,
with_results
):
if
mode
==
'verbose'
:
print
(
f
" {'<<< ' + self.__class__.__name__ + ' >>>':87}"
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
for
o
in
self
.
opts
:
print
()
o
.
table_print
(
mode
,
with_results
)
else
:
o
=
self
.
opts
[
0
]
o
.
table_print
(
mode
,
False
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
def
json_dump
(
self
,
with_results
):
dump
=
self
.
opts
[
0
]
.
json_dump
(
False
)
if
with_results
:
dump
.
append
(
self
.
result
)
return
dump
class
OR
(
ComplexOptCheck
):
# self.opts[0] is the option that this OR-check is about.
# Use cases:
# OR(<X_is_hardened>, <X_is_disabled>)
# OR(<X_is_hardened>, <old_X_is_hardened>)
def
check
(
self
):
for
i
,
opt
in
enumerate
(
self
.
opts
):
opt
.
check
()
if
opt
.
result
.
startswith
(
'OK'
):
self
.
result
=
opt
.
result
# Add more info for additional checks:
if
i
!=
0
:
if
opt
.
result
==
'OK'
:
self
.
result
=
f
'OK: {opt.name} is "{opt.expected}"'
elif
opt
.
result
==
'OK: is not found'
:
self
.
result
=
f
'OK: {opt.name} is not found'
elif
opt
.
result
==
'OK: is present'
:
self
.
result
=
f
'OK: {opt.name} is present'
elif
opt
.
result
.
startswith
(
'OK: is not off'
):
self
.
result
=
f
'OK: {opt.name} is not off'
else
:
# VersionCheck provides enough info
assert
(
opt
.
result
.
startswith
(
'OK: version'
)),
\
f
'unexpected OK description "{opt.result}"'
return
self
.
result
=
self
.
opts
[
0
]
.
result
class
AND
(
ComplexOptCheck
):
# self.opts[0] is the option that this AND-check is about.
# Use cases:
# AND(<suboption>, <main_option>)
# Suboption is not checked if checking of the main_option is failed.
# AND(<X_is_disabled>, <old_X_is_disabled>)
def
check
(
self
):
for
i
,
opt
in
reversed
(
list
(
enumerate
(
self
.
opts
))):
opt
.
check
()
if
i
==
0
:
self
.
result
=
opt
.
result
return
if
not
opt
.
result
.
startswith
(
'OK'
):
# This FAIL is caused by additional checks,
# and not by the main option that this AND-check is about.
# Describe the reason of the FAIL.
if
opt
.
result
.
startswith
(
'FAIL:
\"
'
)
or
opt
.
result
==
'FAIL: is not found'
:
self
.
result
=
f
'FAIL: {opt.name} is not "{opt.expected}"'
elif
opt
.
result
==
'FAIL: is not present'
:
self
.
result
=
f
'FAIL: {opt.name} is not present'
elif
opt
.
result
in
(
'FAIL: is off'
,
'FAIL: is off, "0"'
):
self
.
result
=
f
'FAIL: {opt.name} is off'
elif
opt
.
result
==
'FAIL: is off, not found'
:
self
.
result
=
f
'FAIL: {opt.name} is off, not found'
else
:
# VersionCheck provides enough info
self
.
result
=
opt
.
result
assert
(
opt
.
result
.
startswith
(
'FAIL: version'
)),
\
f
'unexpected FAIL description "{opt.result}"'
return
def
detect_arch
(
fname
,
archs
):
def
detect_arch
(
fname
,
archs
):
...
@@ -331,491 +74,6 @@ def detect_compiler(fname):
...
@@ -331,491 +74,6 @@ def detect_compiler(fname):
sys
.
exit
(
f
'[!] ERROR: invalid GCC_VERSION and CLANG_VERSION: {gcc_version} {clang_version}'
)
sys
.
exit
(
f
'[!] ERROR: invalid GCC_VERSION and CLANG_VERSION: {gcc_version} {clang_version}'
)
def
add_kconfig_checks
(
l
,
arch
):
# Calling the KconfigCheck class constructor:
# KconfigCheck(reason, decision, name, expected)
#
# [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results
# when the tool doesn't check the cmdline.
efi_not_set
=
KconfigCheck
(
'-'
,
'-'
,
'EFI'
,
'is not set'
)
cc_is_gcc
=
KconfigCheck
(
'-'
,
'-'
,
'CC_IS_GCC'
,
'y'
)
# exists since v4.18
cc_is_clang
=
KconfigCheck
(
'-'
,
'-'
,
'CC_IS_CLANG'
,
'y'
)
# exists since v4.18
modules_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'MODULES'
,
'is not set'
)
devmem_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'DEVMEM'
,
'is not set'
)
# refers to LOCKDOWN
bpf_syscall_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'lockdown'
,
'BPF_SYSCALL'
,
'is not set'
)
# refers to LOCKDOWN
# 'self_protection', 'defconfig'
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'BUG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'SLUB_DEBUG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'THREAD_INFO_IN_TASK'
,
'y'
)]
gcc_plugins_support_is_set
=
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'GCC_PLUGINS'
,
'y'
)
l
+=
[
gcc_plugins_support_is_set
]
iommu_support_is_set
=
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_SUPPORT'
,
'y'
)
l
+=
[
iommu_support_is_set
]
# is needed for mitigating DMA attacks
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_REGULAR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_AUTO'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_STRONG'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR_STRONG'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_STRONG'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STRICT_KERNEL_RWX'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_RODATA'
,
'y'
))]
# before v4.11
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STRICT_MODULE_RWX'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_SET_MODULE_RONX'
,
'y'
),
modules_not_set
)]
# DEBUG_SET_MODULE_RONX was before v4.11
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'REFCOUNT_FULL'
,
'y'
),
VersionCheck
((
5
,
5
)))]
# REFCOUNT_FULL is enabled by default since v5.5
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_BASE'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'VMAP_STACK'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_WX'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'WERROR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE_INTEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE_AMD'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'MICROCODE'
,
'y'
)]
# is needed for mitigating CPU bugs
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RETPOLINE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'SYN_COOKIES'
,
'y'
)]
# another reason?
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_SMAP'
,
'y'
),
VersionCheck
((
5
,
19
)))]
# X86_SMAP is enabled by default since v5.19
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_UMIP'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_INTEL_UMIP'
,
'y'
))]
if
arch
in
(
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
)]
# true if IOMMU_DEFAULT_DMA_STRICT is set
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR_PER_TASK'
,
'y'
)]
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'PAGE_TABLE_ISOLATION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_MEMORY'
,
'y'
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'INTEL_IOMMU'
,
'y'
),
iommu_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'AMD_IOMMU'
,
'y'
),
iommu_support_is_set
)]
if
arch
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_EPAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'UNMAP_KERNEL_AT_EL0'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_E0PD'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RODATA_FULL_DEFAULT_ENABLED'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_PTR_AUTH_KERNEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_BTI_KERNEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'MITIGATE_SPECTRE_BRANCH_HISTORY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_MTE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_MODULE_REGION_FULL'
,
'y'
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_EL2_VECTORS'
,
'y'
),
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_BASE'
,
'y'
),
VersionCheck
((
5
,
9
))))]
# HARDEN_EL2_VECTORS was included in RANDOMIZE_BASE in v5.9
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_PREDICTOR'
,
'y'
),
VersionCheck
((
5
,
10
)))]
# HARDEN_BRANCH_PREDICTOR is enabled by default since v5.10
if
arch
==
'ARM'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CPU_SW_DOMAIN_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_PREDICTOR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_HISTORY'
,
'y'
)]
# 'self_protection', 'kspp'
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'BUG_ON_DATA_CORRUPTION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SCHED_STACK_END_CHECK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLAB_FREELIST_HARDENED'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLAB_FREELIST_RANDOM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SHUFFLE_PAGE_ALLOCATOR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'FORTIFY_SOURCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_LIST'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_VIRTUAL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_SG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_CREDENTIALS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_NOTIFIERS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_ALLOC_DEFAULT_ON'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'KFENCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'ZERO_CALL_USED_REGS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HW_RANDOM_TPM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STATIC_USERMODEHELPER'
,
'y'
)]
# needs userspace support
randstruct_is_set
=
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDSTRUCT_FULL'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_RANDSTRUCT'
,
'y'
))
l
+=
[
randstruct_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDSTRUCT_PERFORMANCE'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_RANDSTRUCT_PERFORMANCE'
,
'is not set'
),
randstruct_is_set
)]
hardened_usercopy_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY'
,
'y'
)
l
+=
[
hardened_usercopy_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_FALLBACK'
,
'is not set'
),
hardened_usercopy_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_PAGESPAN'
,
'is not set'
),
hardened_usercopy_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_LATENT_ENTROPY'
,
'y'
),
gcc_plugins_support_is_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_ALL'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_SHA512'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_FORCE'
,
'y'
),
modules_not_set
)]
# refers to LOCKDOWN
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_STACK_ALL_ZERO'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_STRUCTLEAK_BYREF_ALL'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_FREE_DEFAULT_ON'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_POISONING_ZERO'
,
'y'
))]
# CONFIG_INIT_ON_FREE_DEFAULT_ON was added in v5.3.
# CONFIG_PAGE_POISONING_ZERO was removed in v5.11.
# Starting from v5.11 CONFIG_PAGE_POISONING unconditionally checks
# the 0xAA poison pattern on allocation.
# That brings higher performance penalty.
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'EFI_DISABLE_PCI_DMA'
,
'y'
),
efi_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RESET_ATTACK_MITIGATION'
,
'y'
),
efi_not_set
)]
# needs userspace support (systemd)
ubsan_bounds_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_BOUNDS'
,
'y'
)
l
+=
[
ubsan_bounds_is_set
]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_LOCAL_BOUNDS'
,
'y'
),
AND
(
ubsan_bounds_is_set
,
cc_is_gcc
))]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_TRAP'
,
'y'
),
ubsan_bounds_is_set
,
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_SHIFT'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_DIV_ZERO'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_UNREACHABLE'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_BOOL'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_ENUM'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_ALIGNMENT'
,
'is not set'
))]
# only array index bounds checking with traps
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_SANITIZE_ALL'
,
'y'
),
ubsan_bounds_is_set
)]
# ARCH_HAS_UBSAN_SANITIZE_ALL is not enabled for ARM
stackleak_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_STACKLEAK'
,
'y'
)
l
+=
[
AND
(
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STACKLEAK_METRICS'
,
'is not set'
),
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STACKLEAK_RUNTIME_DISABLE'
,
'is not set'
),
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDOMIZE_KSTACK_OFFSET_DEFAULT'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'ARM64'
):
cfi_clang_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'CFI_CLANG'
,
'y'
)
l
+=
[
cfi_clang_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'CFI_PERMISSIVE'
,
'is not set'
),
cfi_clang_is_set
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SCHED_CORE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEFAULT_MMAP_MIN_ADDR'
,
'65536'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
)]
# true if IOMMU_DEFAULT_DMA_STRICT is set
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU_DEFAULT_ON'
,
'y'
),
iommu_support_is_set
)]
if
arch
in
(
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_WX'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'WERROR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEFAULT_MMAP_MIN_ADDR'
,
'32768'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SYN_COOKIES'
,
'y'
)]
# another reason?
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLS'
,
'y'
)]
# vs CVE-2021-26341 in Straight-Line-Speculation
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU_SVM'
,
'y'
),
iommu_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'AMD_IOMMU_V2'
,
'y'
),
iommu_support_is_set
)]
if
arch
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'ARM64_SW_TTBR0_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SHADOW_CALL_STACK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'KASAN_HW_TAGS'
,
'y'
)]
# see also: kasan=on, kasan.stacktrace=off, kasan.fault=panic
if
arch
==
'X86_32'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_TABLE_ISOLATION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HIGHMEM64G'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'X86_PAE'
,
'y'
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU'
,
'y'
),
iommu_support_is_set
)]
# 'self_protection', 'clipos'
l
+=
[
KconfigCheck
(
'self_protection'
,
'clipos'
,
'SLAB_MERGE_DEFAULT'
,
'is not set'
)]
# 'security_policy'
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'security_policy'
,
'defconfig'
,
'SECURITY'
,
'y'
)]
# and choose your favourite LSM
if
arch
==
'ARM'
:
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY'
,
'y'
)]
# and choose your favourite LSM
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_YAMA'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LANDLOCK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_DISABLE'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_BOOTPARAM'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_DEVELOP'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LOCKDOWN_LSM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LOCKDOWN_LSM_EARLY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_WRITABLE_HOOKS'
,
'is not set'
)]
# refers to SECURITY_SELINUX_DISABLE
# 'cut_attack_surface', 'defconfig'
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'SECCOMP'
,
'y'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'SECCOMP_FILTER'
,
'y'
)]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'BPF_UNPRIV_DEFAULT_OFF'
,
'y'
),
bpf_syscall_not_set
)]
# see unprivileged_bpf_disabled
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'X86_INTEL_TSX_MODE_OFF'
,
'y'
)]
# tsx=off
# 'cut_attack_surface', 'kspp'
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'SECURITY_DMESG_RESTRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'ACPI_CUSTOM_METHOD'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT_BRK'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'DEVKMEM'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT_VDSO'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'BINFMT_MISC'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'INET_DIAG'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'KEXEC'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'PROC_KCORE'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_PTYS'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'HIBERNATION'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'IA32_EMULATION'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_X32'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_X32_ABI'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'MODIFY_LDT_SYSCALL'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'OABI_COMPAT'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_MSR'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
modules_not_set
]
l
+=
[
devmem_not_set
]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'IO_STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
l
+=
[
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LDISC_AUTOLOAD'
,
'is not set'
),
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LDISC_AUTOLOAD'
,
'is present'
))]
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_VSYSCALL_NONE'
,
'y'
)]
# 'vsyscall=none'
if
arch
==
'ARM'
:
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
# '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
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'maintainer'
,
'NOUVEAU_LEGACY_CTX_SUPPORT'
,
'is not set'
)]
# recommended by Dave Airlie in kernel commit b30a43ac7132cdda
# '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'
,
'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
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'clipos'
,
'COREDUMP'
,
'is not set'
)]
# cut userspace attack surface
# l += [KconfigCheck('cut_attack_surface', 'clipos', 'IKCONFIG', 'is not set')] # no, IKCONFIG is needed for this check :)
# 'cut_attack_surface', '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
l
+=
[
bpf_syscall_not_set
]
# refers to LOCKDOWN
# 'cut_attack_surface', 'my'
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'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'my'
,
'AIO'
,
'is not set'
)]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'my'
,
'TRIM_UNUSED_KSYMS'
,
'y'
),
modules_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
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'harden_userspace'
,
'defconfig'
,
'ARM64_PTR_AUTH'
,
'y'
)]
l
+=
[
KconfigCheck
(
'harden_userspace'
,
'defconfig'
,
'ARM64_BTI'
,
'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'
)]
def
add_cmdline_checks
(
l
,
arch
):
# Calling the CmdlineCheck class constructor:
# CmdlineCheck(reason, decision, name, expected)
#
# [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results
# when the tool doesn't check the cmdline.
#
# [!] Make sure that values of the options in CmdlineChecks need normalization.
# For more info see normalize_cmdline_options().
#
# A common pattern for checking the 'param_x' cmdline parameter
# that __overrides__ the 'PARAM_X_DEFAULT' kconfig option:
# l += [OR(CmdlineCheck(reason, decision, 'param_x', '1'),
# AND(KconfigCheck(reason, decision, 'PARAM_X_DEFAULT_ON', 'y'),
# CmdlineCheck(reason, decision, 'param_x, 'is not set')))]
#
# Here we don't check the kconfig options or minimal kernel version
# required for the cmdline parameters. That would make the checks
# very complex and not give a 100% guarantee anyway.
# 'self_protection', 'defconfig'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nosmep'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nosmap'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nokaslr'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nopti'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_v1'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_v2'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_bhb'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospec_store_bypass_disable'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nobti'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nopauth'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nomte'
,
'is not set'
)]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2_user'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2_user'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spec_store_bypass_disable'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spec_store_bypass_disable'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'l1tf'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'l1tf'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mds'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mds'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'tsx_async_abort'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'tsx_async_abort'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'srbds'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'srbds'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mmio_stale_data'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mmio_stale_data'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'retbleed'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'retbleed'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kpti'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kpti'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kvm.nx_huge_pages'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kvm.nx_huge_pages'
,
'is not set'
))]
if
arch
==
'ARM64'
:
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'ssbd'
,
'kernel'
),
CmdlineCheck
(
'self_protection'
,
'my'
,
'ssbd'
,
'force-on'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'ssbd'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'full'
),
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RODATA_FULL_DEFAULT_ENABLED'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'is not set'
)))]
else
:
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'1'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'is not set'
))]
# 'self_protection', 'kspp'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'nosmt'
,
'is present'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'mitigations'
,
'auto,nosmt'
)]
# 'nosmt' by kspp + 'auto' by defconfig
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_alloc'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_ALLOC_DEFAULT_ON'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_alloc'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_free'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_FREE_DEFAULT_ON'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_free'
,
'is not set'
)),
AND
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'page_poison'
,
'1'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_POISONING_ZERO'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slub_debug'
,
'P'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_nomerge'
,
'is present'
),
AND
(
KconfigCheck
(
'self_protection'
,
'clipos'
,
'SLAB_MERGE_DEFAULT'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_merge'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'slub_merge'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.strict'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.strict'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.passthrough'
,
'0'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.passthrough'
,
'is not set'
)))]
# The cmdline checks compatible with the kconfig recommendations of the KSPP project...
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'hardened_usercopy'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'hardened_usercopy'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_common.usercopy_fallback'
,
'0'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_FALLBACK'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_common.usercopy_fallback'
,
'is not set'
)))]
# ... the end
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'randomize_kstack_offset'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDOMIZE_KSTACK_OFFSET_DEFAULT'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'randomize_kstack_offset'
,
'is not set'
)))]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
AND
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'pti'
,
'on'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nopti'
,
'is not set'
))]
# 'self_protection', 'clipos'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'page_alloc.shuffle'
,
'1'
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'iommu'
,
'force'
)]
# 'cut_attack_surface', 'defconfig'
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'defconfig'
,
'tsx'
,
'off'
),
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'X86_INTEL_TSX_MODE_OFF'
,
'y'
),
CmdlineCheck
(
'cut_attack_surface'
,
'defconfig'
,
'tsx'
,
'is not set'
)))]
# 'cut_attack_surface', 'kspp'
if
arch
==
'X86_64'
:
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'kspp'
,
'vsyscall'
,
'none'
),
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_VSYSCALL_NONE'
,
'y'
),
CmdlineCheck
(
'cut_attack_surface'
,
'kspp'
,
'vsyscall'
,
'is not set'
)))]
# 'cut_attack_surface', 'grsec'
# The cmdline checks compatible with the kconfig options disabled by grsecurity...
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'grsec'
,
'debugfs'
,
'off'
),
KconfigCheck
(
'cut_attack_surface'
,
'grsec'
,
'DEBUG_FS'
,
'is not set'
))]
# ... the end
# 'cut_attack_surface', 'my'
l
+=
[
CmdlineCheck
(
'cut_attack_surface'
,
'my'
,
'sysrq_always_enabled'
,
'is not set'
)]
def
print_unknown_options
(
checklist
,
parsed_options
):
def
print_unknown_options
(
checklist
,
parsed_options
):
known_options
=
[]
known_options
=
[]
...
@@ -887,49 +145,6 @@ def print_checklist(mode, checklist, with_results):
...
@@ -887,49 +145,6 @@ def print_checklist(mode, checklist, with_results):
print
(
f
'[+] Config check is finished:
\'
OK
\'
- {ok_count}{ok_suppressed} /
\'
FAIL
\'
- {fail_count}{fail_suppressed}'
)
print
(
f
'[+] Config check is finished:
\'
OK
\'
- {ok_count}{ok_suppressed} /
\'
FAIL
\'
- {fail_count}{fail_suppressed}'
)
def
populate_simple_opt_with_data
(
opt
,
data
,
data_type
):
assert
(
opt
.
type
!=
'complex'
),
\
f
'unexpected ComplexOptCheck "{opt.name}"'
assert
(
opt
.
type
in
SIMPLE_OPTION_TYPES
),
\
f
'invalid opt type "{opt.type}"'
assert
(
data_type
in
SIMPLE_OPTION_TYPES
),
\
f
'invalid data type "{data_type}"'
if
data_type
!=
opt
.
type
:
return
if
data_type
in
(
'kconfig'
,
'cmdline'
):
opt
.
state
=
data
.
get
(
opt
.
name
,
None
)
else
:
assert
(
data_type
==
'version'
),
\
f
'unexpected data type "{data_type}"'
opt
.
ver
=
data
def
populate_opt_with_data
(
opt
,
data
,
data_type
):
if
opt
.
type
==
'complex'
:
for
o
in
opt
.
opts
:
if
o
.
type
==
'complex'
:
# Recursion for nested ComplexOptCheck objects
populate_opt_with_data
(
o
,
data
,
data_type
)
else
:
populate_simple_opt_with_data
(
o
,
data
,
data_type
)
else
:
assert
(
opt
.
type
in
(
'kconfig'
,
'cmdline'
)),
\
f
'bad type "{opt.type}" for a simple check'
populate_simple_opt_with_data
(
opt
,
data
,
data_type
)
def
populate_with_data
(
checklist
,
data
,
data_type
):
for
opt
in
checklist
:
populate_opt_with_data
(
opt
,
data
,
data_type
)
def
perform_checks
(
checklist
):
for
opt
in
checklist
:
opt
.
check
()
def
parse_kconfig_file
(
parsed_options
,
fname
):
def
parse_kconfig_file
(
parsed_options
,
fname
):
with
open
(
fname
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
with
open
(
fname
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
opt_is_on
=
re
.
compile
(
"CONFIG_[a-zA-Z0-9_]*=[a-zA-Z0-9_
\"
]*"
)
opt_is_on
=
re
.
compile
(
"CONFIG_[a-zA-Z0-9_]*=[a-zA-Z0-9_
\"
]*"
)
...
@@ -956,59 +171,6 @@ def parse_kconfig_file(parsed_options, fname):
...
@@ -956,59 +171,6 @@ def parse_kconfig_file(parsed_options, fname):
parsed_options
[
option
]
=
value
parsed_options
[
option
]
=
value
def
normalize_cmdline_options
(
option
,
value
):
# Don't normalize the cmdline option values if
# the Linux kernel doesn't use kstrtobool() for them
if
option
==
'debugfs'
:
# See debugfs_kernel() in fs/debugfs/inode.c
return
value
if
option
==
'mitigations'
:
# See mitigations_parse_cmdline() in kernel/cpu.c
return
value
if
option
==
'pti'
:
# See pti_check_boottime_disable() in arch/x86/mm/pti.c
return
value
if
option
==
'spectre_v2'
:
# See spectre_v2_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'spectre_v2_user'
:
# See spectre_v2_parse_user_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'spec_store_bypass_disable'
:
# See ssb_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'l1tf'
:
# See l1tf_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'mds'
:
# See mds_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'tsx_async_abort'
:
# See tsx_async_abort_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'srbds'
:
# See srbds_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'mmio_stale_data'
:
# See mmio_stale_data_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'retbleed'
:
# See retbleed_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'tsx'
:
# See tsx_init() in arch/x86/kernel/cpu/tsx.c
return
value
# Implement a limited part of the kstrtobool() logic
if
value
in
(
'1'
,
'on'
,
'On'
,
'ON'
,
'y'
,
'Y'
,
'yes'
,
'Yes'
,
'YES'
):
return
'1'
if
value
in
(
'0'
,
'off'
,
'Off'
,
'OFF'
,
'n'
,
'N'
,
'no'
,
'No'
,
'NO'
):
return
'0'
# Preserve unique values
return
value
def
parse_cmdline_file
(
parsed_options
,
fname
):
def
parse_cmdline_file
(
parsed_options
,
fname
):
with
open
(
fname
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
with
open
(
fname
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
line
=
f
.
readline
()
line
=
f
.
readline
()
...
...
This diff is collapsed.
Click to expand it.
kconfig_hardened_check/checks.py
0 → 100644
View file @
328a89c7
#!/usr/bin/python3
# N.B. Hardening sysctls:
# kernel.kptr_restrict=2 (or 1?)
# kernel.dmesg_restrict=1 (also see the kconfig option)
# kernel.perf_event_paranoid=2 (or 3 with a custom patch, see https://lwn.net/Articles/696216/)
# kernel.kexec_load_disabled=1
# kernel.yama.ptrace_scope=3
# user.max_user_namespaces=0
# what about bpf_jit_enable?
# kernel.unprivileged_bpf_disabled=1
# net.core.bpf_jit_harden=2
# vm.unprivileged_userfaultfd=0
# (at first, it disabled unprivileged userfaultfd,
# and since v5.11 it enables unprivileged userfaultfd for user-mode only)
# vm.mmap_min_addr has a good value
# dev.tty.ldisc_autoload=0
# fs.protected_symlinks=1
# fs.protected_hardlinks=1
# fs.protected_fifos=2
# fs.protected_regular=2
# fs.suid_dumpable=0
# kernel.modules_disabled=1
# kernel.randomize_va_space = 2
# nosmt sysfs control file
#
# Think of these boot params:
# module.sig_enforce=1
# lockdown=confidentiality
# mce=0
# nosmt=force
# intel_iommu=on
# amd_iommu=on
# efi=disable_early_pci_dma
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
# pylint: disable=line-too-long,invalid-name,too-many-branches,too-many-statements
from
.engine
import
KconfigCheck
,
CmdlineCheck
,
VersionCheck
,
OR
,
AND
def
add_kconfig_checks
(
l
,
arch
):
# Calling the KconfigCheck class constructor:
# KconfigCheck(reason, decision, name, expected)
#
# [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results
# when the tool doesn't check the cmdline.
efi_not_set
=
KconfigCheck
(
'-'
,
'-'
,
'EFI'
,
'is not set'
)
cc_is_gcc
=
KconfigCheck
(
'-'
,
'-'
,
'CC_IS_GCC'
,
'y'
)
# exists since v4.18
cc_is_clang
=
KconfigCheck
(
'-'
,
'-'
,
'CC_IS_CLANG'
,
'y'
)
# exists since v4.18
modules_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'MODULES'
,
'is not set'
)
devmem_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'DEVMEM'
,
'is not set'
)
# refers to LOCKDOWN
bpf_syscall_not_set
=
KconfigCheck
(
'cut_attack_surface'
,
'lockdown'
,
'BPF_SYSCALL'
,
'is not set'
)
# refers to LOCKDOWN
# 'self_protection', 'defconfig'
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'BUG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'SLUB_DEBUG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'THREAD_INFO_IN_TASK'
,
'y'
)]
gcc_plugins_support_is_set
=
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'GCC_PLUGINS'
,
'y'
)
l
+=
[
gcc_plugins_support_is_set
]
iommu_support_is_set
=
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_SUPPORT'
,
'y'
)
l
+=
[
iommu_support_is_set
]
# is needed for mitigating DMA attacks
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_REGULAR'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_AUTO'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_STRONG'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR_STRONG'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CC_STACKPROTECTOR_STRONG'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STRICT_KERNEL_RWX'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_RODATA'
,
'y'
))]
# before v4.11
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STRICT_MODULE_RWX'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_SET_MODULE_RONX'
,
'y'
),
modules_not_set
)]
# DEBUG_SET_MODULE_RONX was before v4.11
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'REFCOUNT_FULL'
,
'y'
),
VersionCheck
((
5
,
5
)))]
# REFCOUNT_FULL is enabled by default since v5.5
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_BASE'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'VMAP_STACK'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'DEBUG_WX'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'WERROR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE_INTEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_MCE_AMD'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'MICROCODE'
,
'y'
)]
# is needed for mitigating CPU bugs
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RETPOLINE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'SYN_COOKIES'
,
'y'
)]
# another reason?
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_SMAP'
,
'y'
),
VersionCheck
((
5
,
19
)))]
# X86_SMAP is enabled by default since v5.19
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_UMIP'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'X86_INTEL_UMIP'
,
'y'
))]
if
arch
in
(
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
)]
# true if IOMMU_DEFAULT_DMA_STRICT is set
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'STACKPROTECTOR_PER_TASK'
,
'y'
)]
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'PAGE_TABLE_ISOLATION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_MEMORY'
,
'y'
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'INTEL_IOMMU'
,
'y'
),
iommu_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'AMD_IOMMU'
,
'y'
),
iommu_support_is_set
)]
if
arch
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_EPAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'UNMAP_KERNEL_AT_EL0'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_E0PD'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RODATA_FULL_DEFAULT_ENABLED'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_PTR_AUTH_KERNEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_BTI_KERNEL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'MITIGATE_SPECTRE_BRANCH_HISTORY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'ARM64_MTE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_MODULE_REGION_FULL'
,
'y'
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_EL2_VECTORS'
,
'y'
),
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RANDOMIZE_BASE'
,
'y'
),
VersionCheck
((
5
,
9
))))]
# HARDEN_EL2_VECTORS was included in RANDOMIZE_BASE in v5.9
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_PREDICTOR'
,
'y'
),
VersionCheck
((
5
,
10
)))]
# HARDEN_BRANCH_PREDICTOR is enabled by default since v5.10
if
arch
==
'ARM'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'CPU_SW_DOMAIN_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_PREDICTOR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'HARDEN_BRANCH_HISTORY'
,
'y'
)]
# 'self_protection', 'kspp'
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'BUG_ON_DATA_CORRUPTION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SCHED_STACK_END_CHECK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLAB_FREELIST_HARDENED'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLAB_FREELIST_RANDOM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SHUFFLE_PAGE_ALLOCATOR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'FORTIFY_SOURCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_LIST'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_VIRTUAL'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_SG'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_CREDENTIALS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_NOTIFIERS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_ALLOC_DEFAULT_ON'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'KFENCE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'ZERO_CALL_USED_REGS'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HW_RANDOM_TPM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STATIC_USERMODEHELPER'
,
'y'
)]
# needs userspace support
randstruct_is_set
=
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDSTRUCT_FULL'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_RANDSTRUCT'
,
'y'
))
l
+=
[
randstruct_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDSTRUCT_PERFORMANCE'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_RANDSTRUCT_PERFORMANCE'
,
'is not set'
),
randstruct_is_set
)]
hardened_usercopy_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY'
,
'y'
)
l
+=
[
hardened_usercopy_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_FALLBACK'
,
'is not set'
),
hardened_usercopy_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_PAGESPAN'
,
'is not set'
),
hardened_usercopy_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_LATENT_ENTROPY'
,
'y'
),
gcc_plugins_support_is_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_ALL'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_SHA512'
,
'y'
),
modules_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'MODULE_SIG_FORCE'
,
'y'
),
modules_not_set
)]
# refers to LOCKDOWN
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_STACK_ALL_ZERO'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_STRUCTLEAK_BYREF_ALL'
,
'y'
))]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_FREE_DEFAULT_ON'
,
'y'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_POISONING_ZERO'
,
'y'
))]
# CONFIG_INIT_ON_FREE_DEFAULT_ON was added in v5.3.
# CONFIG_PAGE_POISONING_ZERO was removed in v5.11.
# Starting from v5.11 CONFIG_PAGE_POISONING unconditionally checks
# the 0xAA poison pattern on allocation.
# That brings higher performance penalty.
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'EFI_DISABLE_PCI_DMA'
,
'y'
),
efi_not_set
)]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RESET_ATTACK_MITIGATION'
,
'y'
),
efi_not_set
)]
# needs userspace support (systemd)
ubsan_bounds_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_BOUNDS'
,
'y'
)
l
+=
[
ubsan_bounds_is_set
]
l
+=
[
OR
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_LOCAL_BOUNDS'
,
'y'
),
AND
(
ubsan_bounds_is_set
,
cc_is_gcc
))]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_TRAP'
,
'y'
),
ubsan_bounds_is_set
,
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_SHIFT'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_DIV_ZERO'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_UNREACHABLE'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_BOOL'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_ENUM'
,
'is not set'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_ALIGNMENT'
,
'is not set'
))]
# only array index bounds checking with traps
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'UBSAN_SANITIZE_ALL'
,
'y'
),
ubsan_bounds_is_set
)]
# ARCH_HAS_UBSAN_SANITIZE_ALL is not enabled for ARM
stackleak_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'GCC_PLUGIN_STACKLEAK'
,
'y'
)
l
+=
[
AND
(
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STACKLEAK_METRICS'
,
'is not set'
),
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'STACKLEAK_RUNTIME_DISABLE'
,
'is not set'
),
stackleak_is_set
,
gcc_plugins_support_is_set
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDOMIZE_KSTACK_OFFSET_DEFAULT'
,
'y'
)]
if
arch
in
(
'X86_64'
,
'ARM64'
):
cfi_clang_is_set
=
KconfigCheck
(
'self_protection'
,
'kspp'
,
'CFI_CLANG'
,
'y'
)
l
+=
[
cfi_clang_is_set
]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'CFI_PERMISSIVE'
,
'is not set'
),
cfi_clang_is_set
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SCHED_CORE'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEFAULT_MMAP_MIN_ADDR'
,
'65536'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
)]
# true if IOMMU_DEFAULT_DMA_STRICT is set
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU_DEFAULT_ON'
,
'y'
),
iommu_support_is_set
)]
if
arch
in
(
'ARM64'
,
'ARM'
):
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEBUG_WX'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'WERROR'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'DEFAULT_MMAP_MIN_ADDR'
,
'32768'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SYN_COOKIES'
,
'y'
)]
# another reason?
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SLS'
,
'y'
)]
# vs CVE-2021-26341 in Straight-Line-Speculation
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU_SVM'
,
'y'
),
iommu_support_is_set
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'AMD_IOMMU_V2'
,
'y'
),
iommu_support_is_set
)]
if
arch
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'ARM64_SW_TTBR0_PAN'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'SHADOW_CALL_STACK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'KASAN_HW_TAGS'
,
'y'
)]
# see also: kasan=on, kasan.stacktrace=off, kasan.fault=panic
if
arch
==
'X86_32'
:
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_TABLE_ISOLATION'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HIGHMEM64G'
,
'y'
)]
l
+=
[
KconfigCheck
(
'self_protection'
,
'kspp'
,
'X86_PAE'
,
'y'
)]
l
+=
[
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INTEL_IOMMU'
,
'y'
),
iommu_support_is_set
)]
# 'self_protection', 'clipos'
l
+=
[
KconfigCheck
(
'self_protection'
,
'clipos'
,
'SLAB_MERGE_DEFAULT'
,
'is not set'
)]
# 'security_policy'
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'security_policy'
,
'defconfig'
,
'SECURITY'
,
'y'
)]
# and choose your favourite LSM
if
arch
==
'ARM'
:
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY'
,
'y'
)]
# and choose your favourite LSM
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_YAMA'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LANDLOCK'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_DISABLE'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_BOOTPARAM'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_SELINUX_DEVELOP'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LOCKDOWN_LSM'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_LOCKDOWN_LSM_EARLY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY'
,
'y'
)]
l
+=
[
KconfigCheck
(
'security_policy'
,
'kspp'
,
'SECURITY_WRITABLE_HOOKS'
,
'is not set'
)]
# refers to SECURITY_SELINUX_DISABLE
# 'cut_attack_surface', 'defconfig'
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'SECCOMP'
,
'y'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'SECCOMP_FILTER'
,
'y'
)]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'BPF_UNPRIV_DEFAULT_OFF'
,
'y'
),
bpf_syscall_not_set
)]
# see unprivileged_bpf_disabled
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'X86_INTEL_TSX_MODE_OFF'
,
'y'
)]
# tsx=off
# 'cut_attack_surface', 'kspp'
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'SECURITY_DMESG_RESTRICT'
,
'y'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'ACPI_CUSTOM_METHOD'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT_BRK'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'DEVKMEM'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT_VDSO'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'BINFMT_MISC'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'INET_DIAG'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'KEXEC'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'PROC_KCORE'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_PTYS'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'HIBERNATION'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'COMPAT'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'IA32_EMULATION'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_X32'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_X32_ABI'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'MODIFY_LDT_SYSCALL'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'OABI_COMPAT'
,
'is not set'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'X86_MSR'
,
'is not set'
)]
# refers to LOCKDOWN
l
+=
[
modules_not_set
]
l
+=
[
devmem_not_set
]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'IO_STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
l
+=
[
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LDISC_AUTOLOAD'
,
'is not set'
),
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LDISC_AUTOLOAD'
,
'is present'
))]
if
arch
==
'X86_64'
:
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_VSYSCALL_NONE'
,
'y'
)]
# 'vsyscall=none'
if
arch
==
'ARM'
:
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'STRICT_DEVMEM'
,
'y'
),
devmem_not_set
)]
# refers to LOCKDOWN
# '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
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'maintainer'
,
'NOUVEAU_LEGACY_CTX_SUPPORT'
,
'is not set'
)]
# recommended by Dave Airlie in kernel commit b30a43ac7132cdda
# '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'
,
'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
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'clipos'
,
'COREDUMP'
,
'is not set'
)]
# cut userspace attack surface
# l += [KconfigCheck('cut_attack_surface', 'clipos', 'IKCONFIG', 'is not set')] # no, IKCONFIG is needed for this check :)
# 'cut_attack_surface', '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
l
+=
[
bpf_syscall_not_set
]
# refers to LOCKDOWN
# 'cut_attack_surface', 'my'
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'
)]
l
+=
[
KconfigCheck
(
'cut_attack_surface'
,
'my'
,
'AIO'
,
'is not set'
)]
l
+=
[
OR
(
KconfigCheck
(
'cut_attack_surface'
,
'my'
,
'TRIM_UNUSED_KSYMS'
,
'y'
),
modules_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
==
'ARM64'
:
l
+=
[
KconfigCheck
(
'harden_userspace'
,
'defconfig'
,
'ARM64_PTR_AUTH'
,
'y'
)]
l
+=
[
KconfigCheck
(
'harden_userspace'
,
'defconfig'
,
'ARM64_BTI'
,
'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'
)]
def
add_cmdline_checks
(
l
,
arch
):
# Calling the CmdlineCheck class constructor:
# CmdlineCheck(reason, decision, name, expected)
#
# [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results
# when the tool doesn't check the cmdline.
#
# [!] Make sure that values of the options in CmdlineChecks need normalization.
# For more info see normalize_cmdline_options().
#
# A common pattern for checking the 'param_x' cmdline parameter
# that __overrides__ the 'PARAM_X_DEFAULT' kconfig option:
# l += [OR(CmdlineCheck(reason, decision, 'param_x', '1'),
# AND(KconfigCheck(reason, decision, 'PARAM_X_DEFAULT_ON', 'y'),
# CmdlineCheck(reason, decision, 'param_x, 'is not set')))]
#
# Here we don't check the kconfig options or minimal kernel version
# required for the cmdline parameters. That would make the checks
# very complex and not give a 100% guarantee anyway.
# 'self_protection', 'defconfig'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nosmep'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nosmap'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nokaslr'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nopti'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_v1'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_v2'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospectre_bhb'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nospec_store_bypass_disable'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nobti'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nopauth'
,
'is not set'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'arm64.nomte'
,
'is not set'
)]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2_user'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spectre_v2_user'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spec_store_bypass_disable'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'spec_store_bypass_disable'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'l1tf'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'l1tf'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mds'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mds'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'tsx_async_abort'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'tsx_async_abort'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'srbds'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'srbds'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mmio_stale_data'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'mmio_stale_data'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'retbleed'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'retbleed'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kpti'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kpti'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kvm.nx_huge_pages'
,
'is not off'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'kvm.nx_huge_pages'
,
'is not set'
))]
if
arch
==
'ARM64'
:
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'ssbd'
,
'kernel'
),
CmdlineCheck
(
'self_protection'
,
'my'
,
'ssbd'
,
'force-on'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'ssbd'
,
'is not set'
))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'full'
),
AND
(
KconfigCheck
(
'self_protection'
,
'defconfig'
,
'RODATA_FULL_DEFAULT_ENABLED'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'is not set'
)))]
else
:
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'1'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'rodata'
,
'is not set'
))]
# 'self_protection', 'kspp'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'nosmt'
,
'is present'
)]
l
+=
[
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'mitigations'
,
'auto,nosmt'
)]
# 'nosmt' by kspp + 'auto' by defconfig
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_alloc'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_ALLOC_DEFAULT_ON'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_alloc'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_free'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'INIT_ON_FREE_DEFAULT_ON'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'init_on_free'
,
'is not set'
)),
AND
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'page_poison'
,
'1'
),
KconfigCheck
(
'self_protection'
,
'kspp'
,
'PAGE_POISONING_ZERO'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slub_debug'
,
'P'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_nomerge'
,
'is present'
),
AND
(
KconfigCheck
(
'self_protection'
,
'clipos'
,
'SLAB_MERGE_DEFAULT'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_merge'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'slub_merge'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.strict'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_DMA_STRICT'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.strict'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.passthrough'
,
'0'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'IOMMU_DEFAULT_PASSTHROUGH'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'iommu.passthrough'
,
'is not set'
)))]
# The cmdline checks compatible with the kconfig recommendations of the KSPP project...
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'hardened_usercopy'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'hardened_usercopy'
,
'is not set'
)))]
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_common.usercopy_fallback'
,
'0'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'HARDENED_USERCOPY_FALLBACK'
,
'is not set'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'slab_common.usercopy_fallback'
,
'is not set'
)))]
# ... the end
if
arch
in
(
'X86_64'
,
'ARM64'
,
'X86_32'
):
l
+=
[
OR
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'randomize_kstack_offset'
,
'1'
),
AND
(
KconfigCheck
(
'self_protection'
,
'kspp'
,
'RANDOMIZE_KSTACK_OFFSET_DEFAULT'
,
'y'
),
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'randomize_kstack_offset'
,
'is not set'
)))]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
AND
(
CmdlineCheck
(
'self_protection'
,
'kspp'
,
'pti'
,
'on'
),
CmdlineCheck
(
'self_protection'
,
'defconfig'
,
'nopti'
,
'is not set'
))]
# 'self_protection', 'clipos'
l
+=
[
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'page_alloc.shuffle'
,
'1'
)]
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
CmdlineCheck
(
'self_protection'
,
'clipos'
,
'iommu'
,
'force'
)]
# 'cut_attack_surface', 'defconfig'
if
arch
in
(
'X86_64'
,
'X86_32'
):
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'defconfig'
,
'tsx'
,
'off'
),
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'defconfig'
,
'X86_INTEL_TSX_MODE_OFF'
,
'y'
),
CmdlineCheck
(
'cut_attack_surface'
,
'defconfig'
,
'tsx'
,
'is not set'
)))]
# 'cut_attack_surface', 'kspp'
if
arch
==
'X86_64'
:
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'kspp'
,
'vsyscall'
,
'none'
),
AND
(
KconfigCheck
(
'cut_attack_surface'
,
'kspp'
,
'LEGACY_VSYSCALL_NONE'
,
'y'
),
CmdlineCheck
(
'cut_attack_surface'
,
'kspp'
,
'vsyscall'
,
'is not set'
)))]
# 'cut_attack_surface', 'grsec'
# The cmdline checks compatible with the kconfig options disabled by grsecurity...
l
+=
[
OR
(
CmdlineCheck
(
'cut_attack_surface'
,
'grsec'
,
'debugfs'
,
'off'
),
KconfigCheck
(
'cut_attack_surface'
,
'grsec'
,
'DEBUG_FS'
,
'is not set'
))]
# ... the end
# 'cut_attack_surface', 'my'
l
+=
[
CmdlineCheck
(
'cut_attack_surface'
,
'my'
,
'sysrq_always_enabled'
,
'is not set'
)]
def
normalize_cmdline_options
(
option
,
value
):
# Don't normalize the cmdline option values if
# the Linux kernel doesn't use kstrtobool() for them
if
option
==
'debugfs'
:
# See debugfs_kernel() in fs/debugfs/inode.c
return
value
if
option
==
'mitigations'
:
# See mitigations_parse_cmdline() in kernel/cpu.c
return
value
if
option
==
'pti'
:
# See pti_check_boottime_disable() in arch/x86/mm/pti.c
return
value
if
option
==
'spectre_v2'
:
# See spectre_v2_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'spectre_v2_user'
:
# See spectre_v2_parse_user_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'spec_store_bypass_disable'
:
# See ssb_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'l1tf'
:
# See l1tf_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'mds'
:
# See mds_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'tsx_async_abort'
:
# See tsx_async_abort_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'srbds'
:
# See srbds_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'mmio_stale_data'
:
# See mmio_stale_data_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'retbleed'
:
# See retbleed_parse_cmdline() in arch/x86/kernel/cpu/bugs.c
return
value
if
option
==
'tsx'
:
# See tsx_init() in arch/x86/kernel/cpu/tsx.c
return
value
# Implement a limited part of the kstrtobool() logic
if
value
in
(
'1'
,
'on'
,
'On'
,
'ON'
,
'y'
,
'Y'
,
'yes'
,
'Yes'
,
'YES'
):
return
'1'
if
value
in
(
'0'
,
'off'
,
'Off'
,
'OFF'
,
'n'
,
'N'
,
'no'
,
'No'
,
'NO'
):
return
'0'
# Preserve unique values
return
value
This diff is collapsed.
Click to expand it.
kconfig_hardened_check/engine.py
0 → 100644
View file @
328a89c7
#!/usr/bin/python3
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
# pylint: disable=line-too-long,invalid-name,too-many-branches,too-many-statements
class
OptCheck
:
def
__init__
(
self
,
reason
,
decision
,
name
,
expected
):
assert
(
name
and
name
==
name
.
strip
()
and
len
(
name
.
split
())
==
1
),
\
f
'invalid name "{name}" for {self.__class__.__name__}'
self
.
name
=
name
assert
(
decision
and
decision
==
decision
.
strip
()
and
len
(
decision
.
split
())
==
1
),
\
f
'invalid decision "{decision}" for "{name}" check'
self
.
decision
=
decision
assert
(
reason
and
reason
==
reason
.
strip
()
and
len
(
reason
.
split
())
==
1
),
\
f
'invalid reason "{reason}" for "{name}" check'
self
.
reason
=
reason
assert
(
expected
and
expected
==
expected
.
strip
()),
\
f
'invalid expected value "{expected}" for "{name}" check (1)'
val_len
=
len
(
expected
.
split
())
if
val_len
==
3
:
assert
(
expected
in
(
'is not set'
,
'is not off'
)),
\
f
'invalid expected value "{expected}" for "{name}" check (2)'
elif
val_len
==
2
:
assert
(
expected
==
'is present'
),
\
f
'invalid expected value "{expected}" for "{name}" check (3)'
else
:
assert
(
val_len
==
1
),
\
f
'invalid expected value "{expected}" for "{name}" check (4)'
self
.
expected
=
expected
self
.
state
=
None
self
.
result
=
None
@property
def
type
(
self
):
return
None
def
check
(
self
):
# handle the 'is present' check
if
self
.
expected
==
'is present'
:
if
self
.
state
is
None
:
self
.
result
=
'FAIL: is not present'
else
:
self
.
result
=
'OK: is present'
return
# handle the 'is not off' option check
if
self
.
expected
==
'is not off'
:
if
self
.
state
==
'off'
:
self
.
result
=
'FAIL: is off'
if
self
.
state
==
'0'
:
self
.
result
=
'FAIL: is off, "0"'
elif
self
.
state
is
None
:
self
.
result
=
'FAIL: is off, not found'
else
:
self
.
result
=
'OK: is not off, "'
+
self
.
state
+
'"'
return
# handle the option value check
if
self
.
expected
==
self
.
state
:
self
.
result
=
'OK'
elif
self
.
state
is
None
:
if
self
.
expected
==
'is not set'
:
self
.
result
=
'OK: is not found'
else
:
self
.
result
=
'FAIL: is not found'
else
:
self
.
result
=
'FAIL: "'
+
self
.
state
+
'"'
def
table_print
(
self
,
_mode
,
with_results
):
print
(
f
'{self.name:<40}|{self.type:^7}|{self.expected:^12}|{self.decision:^10}|{self.reason:^18}'
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
def
json_dump
(
self
,
with_results
):
dump
=
[
self
.
name
,
self
.
type
,
self
.
expected
,
self
.
decision
,
self
.
reason
]
if
with_results
:
dump
.
append
(
self
.
result
)
return
dump
class
KconfigCheck
(
OptCheck
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
name
=
'CONFIG_'
+
self
.
name
@property
def
type
(
self
):
return
'kconfig'
class
CmdlineCheck
(
OptCheck
):
@property
def
type
(
self
):
return
'cmdline'
class
VersionCheck
:
def
__init__
(
self
,
ver_expected
):
assert
(
ver_expected
and
isinstance
(
ver_expected
,
tuple
)
and
len
(
ver_expected
)
==
2
),
\
f
'invalid version "{ver_expected}" for VersionCheck'
self
.
ver_expected
=
ver_expected
self
.
ver
=
()
self
.
result
=
None
@property
def
type
(
self
):
return
'version'
def
check
(
self
):
if
self
.
ver
[
0
]
>
self
.
ver_expected
[
0
]:
self
.
result
=
'OK: version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
if
self
.
ver
[
0
]
<
self
.
ver_expected
[
0
]:
self
.
result
=
'FAIL: version < '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
if
self
.
ver
[
1
]
>=
self
.
ver_expected
[
1
]:
self
.
result
=
'OK: version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
return
self
.
result
=
'FAIL: version < '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
def
table_print
(
self
,
_mode
,
with_results
):
ver_req
=
'kernel version >= '
+
str
(
self
.
ver_expected
[
0
])
+
'.'
+
str
(
self
.
ver_expected
[
1
])
print
(
f
'{ver_req:<91}'
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
class
ComplexOptCheck
:
def
__init__
(
self
,
*
opts
):
self
.
opts
=
opts
assert
(
self
.
opts
),
\
f
'empty {self.__class__.__name__} check'
assert
(
len
(
self
.
opts
)
!=
1
),
\
f
'useless {self.__class__.__name__} check: {opts}'
assert
(
isinstance
(
opts
[
0
],
(
KconfigCheck
,
CmdlineCheck
))),
\
f
'invalid {self.__class__.__name__} check: {opts}'
self
.
result
=
None
@property
def
type
(
self
):
return
'complex'
@property
def
name
(
self
):
return
self
.
opts
[
0
]
.
name
@property
def
expected
(
self
):
return
self
.
opts
[
0
]
.
expected
def
table_print
(
self
,
mode
,
with_results
):
if
mode
==
'verbose'
:
print
(
f
" {'<<< ' + self.__class__.__name__ + ' >>>':87}"
,
end
=
''
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
for
o
in
self
.
opts
:
print
()
o
.
table_print
(
mode
,
with_results
)
else
:
o
=
self
.
opts
[
0
]
o
.
table_print
(
mode
,
False
)
if
with_results
:
print
(
f
'| {self.result}'
,
end
=
''
)
def
json_dump
(
self
,
with_results
):
dump
=
self
.
opts
[
0
]
.
json_dump
(
False
)
if
with_results
:
dump
.
append
(
self
.
result
)
return
dump
class
OR
(
ComplexOptCheck
):
# self.opts[0] is the option that this OR-check is about.
# Use cases:
# OR(<X_is_hardened>, <X_is_disabled>)
# OR(<X_is_hardened>, <old_X_is_hardened>)
def
check
(
self
):
for
i
,
opt
in
enumerate
(
self
.
opts
):
opt
.
check
()
if
opt
.
result
.
startswith
(
'OK'
):
self
.
result
=
opt
.
result
# Add more info for additional checks:
if
i
!=
0
:
if
opt
.
result
==
'OK'
:
self
.
result
=
f
'OK: {opt.name} is "{opt.expected}"'
elif
opt
.
result
==
'OK: is not found'
:
self
.
result
=
f
'OK: {opt.name} is not found'
elif
opt
.
result
==
'OK: is present'
:
self
.
result
=
f
'OK: {opt.name} is present'
elif
opt
.
result
.
startswith
(
'OK: is not off'
):
self
.
result
=
f
'OK: {opt.name} is not off'
else
:
# VersionCheck provides enough info
assert
(
opt
.
result
.
startswith
(
'OK: version'
)),
\
f
'unexpected OK description "{opt.result}"'
return
self
.
result
=
self
.
opts
[
0
]
.
result
class
AND
(
ComplexOptCheck
):
# self.opts[0] is the option that this AND-check is about.
# Use cases:
# AND(<suboption>, <main_option>)
# Suboption is not checked if checking of the main_option is failed.
# AND(<X_is_disabled>, <old_X_is_disabled>)
def
check
(
self
):
for
i
,
opt
in
reversed
(
list
(
enumerate
(
self
.
opts
))):
opt
.
check
()
if
i
==
0
:
self
.
result
=
opt
.
result
return
if
not
opt
.
result
.
startswith
(
'OK'
):
# This FAIL is caused by additional checks,
# and not by the main option that this AND-check is about.
# Describe the reason of the FAIL.
if
opt
.
result
.
startswith
(
'FAIL:
\"
'
)
or
opt
.
result
==
'FAIL: is not found'
:
self
.
result
=
f
'FAIL: {opt.name} is not "{opt.expected}"'
elif
opt
.
result
==
'FAIL: is not present'
:
self
.
result
=
f
'FAIL: {opt.name} is not present'
elif
opt
.
result
in
(
'FAIL: is off'
,
'FAIL: is off, "0"'
):
self
.
result
=
f
'FAIL: {opt.name} is off'
elif
opt
.
result
==
'FAIL: is off, not found'
:
self
.
result
=
f
'FAIL: {opt.name} is off, not found'
else
:
# VersionCheck provides enough info
self
.
result
=
opt
.
result
assert
(
opt
.
result
.
startswith
(
'FAIL: version'
)),
\
f
'unexpected FAIL description "{opt.result}"'
return
SIMPLE_OPTION_TYPES
=
(
'kconfig'
,
'version'
,
'cmdline'
)
def
populate_simple_opt_with_data
(
opt
,
data
,
data_type
):
assert
(
opt
.
type
!=
'complex'
),
\
f
'unexpected ComplexOptCheck "{opt.name}"'
assert
(
opt
.
type
in
SIMPLE_OPTION_TYPES
),
\
f
'invalid opt type "{opt.type}"'
assert
(
data_type
in
SIMPLE_OPTION_TYPES
),
\
f
'invalid data type "{data_type}"'
if
data_type
!=
opt
.
type
:
return
if
data_type
in
(
'kconfig'
,
'cmdline'
):
opt
.
state
=
data
.
get
(
opt
.
name
,
None
)
else
:
assert
(
data_type
==
'version'
),
\
f
'unexpected data type "{data_type}"'
opt
.
ver
=
data
def
populate_opt_with_data
(
opt
,
data
,
data_type
):
if
opt
.
type
==
'complex'
:
for
o
in
opt
.
opts
:
if
o
.
type
==
'complex'
:
# Recursion for nested ComplexOptCheck objects
populate_opt_with_data
(
o
,
data
,
data_type
)
else
:
populate_simple_opt_with_data
(
o
,
data
,
data_type
)
else
:
assert
(
opt
.
type
in
(
'kconfig'
,
'cmdline'
)),
\
f
'bad type "{opt.type}" for a simple check'
populate_simple_opt_with_data
(
opt
,
data
,
data_type
)
def
populate_with_data
(
checklist
,
data
,
data_type
):
for
opt
in
checklist
:
populate_opt_with_data
(
opt
,
data
,
data_type
)
def
perform_checks
(
checklist
):
for
opt
in
checklist
:
opt
.
check
()
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment