Commit 6b72b6c1 by Alexander Popov

Merge branch 'json-support'

Thanks to @adrianopol
parents a5535b23 4fdae670
...@@ -28,8 +28,8 @@ Please don't cry if my Python code looks like C. I'm just a kernel developer. ...@@ -28,8 +28,8 @@ Please don't cry if my Python code looks like C. I'm just a kernel developer.
### Usage ### Usage
``` ```
#usage: kconfig-hardened-check.py [-h] [-p {X86_64,X86_32,ARM64,ARM}] usage: kconfig-hardened-check.py [-h] [-p {X86_64,X86_32,ARM64,ARM}]
[-c CONFIG] [--debug] [-c CONFIG] [--debug] [--json]
Checks the hardening options in the Linux kernel config Checks the hardening options in the Linux kernel config
...@@ -40,6 +40,7 @@ optional arguments: ...@@ -40,6 +40,7 @@ optional arguments:
-c CONFIG, --config CONFIG -c CONFIG, --config CONFIG
check the config_file against these preferences check the config_file against these preferences
--debug enable internal debug mode --debug enable internal debug mode
--json print results in JSON format
``` ```
......
...@@ -42,6 +42,7 @@ from collections import OrderedDict ...@@ -42,6 +42,7 @@ from collections import OrderedDict
import re import re
debug_mode = False # set it to True to print the unknown options from the config debug_mode = False # set it to True to print the unknown options from the config
json_mode = False # if True, print results in JSON format
supported_archs = [ 'X86_64', 'X86_32', 'ARM64', 'ARM' ] supported_archs = [ 'X86_64', 'X86_32', 'ARM64', 'ARM' ]
...@@ -148,6 +149,7 @@ def detect_arch(fname): ...@@ -148,6 +149,7 @@ def detect_arch(fname):
arch_pattern = re.compile("CONFIG_[a-zA-Z0-9_]*=y") arch_pattern = re.compile("CONFIG_[a-zA-Z0-9_]*=y")
arch = None arch = None
msg = None msg = None
if not json_mode:
print('[+] Trying to detect architecture in "{}"...'.format(fname)) print('[+] Trying to detect architecture in "{}"...'.format(fname))
for line in f.readlines(): for line in f.readlines():
if arch_pattern.match(line): if arch_pattern.match(line):
...@@ -373,24 +375,34 @@ def construct_checklist(arch): ...@@ -373,24 +375,34 @@ def construct_checklist(arch):
# checklist.append(OptCheck('LKDTM', 'm', 'my', 'feature_test')) # checklist.append(OptCheck('LKDTM', 'm', 'my', 'feature_test'))
def print_checklist(arch): def print_checks(arch=None):
if json_mode:
opts = []
for o in checklist:
opt = ['CONFIG_'+o.name, o.expected, o.decision, o.reason]
if not arch:
opt.append(o.result)
opts.append(opt)
print(opts)
else:
if arch:
print('[+] Printing kernel hardening preferences for {}...'.format(arch)) print('[+] Printing kernel hardening preferences for {}...'.format(arch))
print('{:^40}|{:^13}|{:^10}|{:^20}'.format(
'option name', 'desired val', 'decision', 'reason')) # header
print('=' * 87) print('{:^40}|{:^13}|{:^10}|{:^20}'.format('option name', 'desired val', 'decision', 'reason'), end='')
for opt in checklist: sep_line_len = 87
print('CONFIG_{:<33}|{:^13}|{:^10}|{:^20}'.format( if not arch:
opt.name, opt.expected, opt.decision, opt.reason)) print('||{:^28}'.format('check result'), end='')
sep_line_len = 116
print() print()
print('=' * sep_line_len)
def print_check_results():
print('{:^40}|{:^13}|{:^10}|{:^20}||{:^28}'.format(
'option name', 'desired val', 'decision', 'reason', 'check result'))
print('=' * 116)
for opt in checklist: for opt in checklist:
print('CONFIG_{:<33}|{:^13}|{:^10}|{:^20}||{:^28}'.format( print('CONFIG_{:<33}|{:^13}|{:^10}|{:^20}'.format(opt.name, opt.expected, opt.decision, opt.reason), end='')
opt.name, opt.expected, opt.decision, opt.reason, opt.result)) if not arch:
print('||{:^28}'.format(opt.result), end='')
print()
print() print()
...@@ -414,6 +426,7 @@ def check_config_file(fname): ...@@ -414,6 +426,7 @@ def check_config_file(fname):
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_\"]*")
opt_is_off = re.compile("# CONFIG_[a-zA-Z0-9_]* is not set") opt_is_off = re.compile("# CONFIG_[a-zA-Z0-9_]* is not set")
if not json_mode:
print('[+] Checking "{}" against hardening preferences...'.format(fname)) print('[+] Checking "{}" against hardening preferences...'.format(fname))
for line in f.readlines(): for line in f.readlines():
line = line.strip() line = line.strip()
...@@ -441,7 +454,7 @@ def check_config_file(fname): ...@@ -441,7 +454,7 @@ def check_config_file(fname):
if option not in known_options: if option not in known_options:
print("DEBUG: dunno about option {} ({})".format(option, value)) print("DEBUG: dunno about option {} ({})".format(option, value))
print_check_results() print_checks()
if __name__ == '__main__': if __name__ == '__main__':
...@@ -452,16 +465,22 @@ if __name__ == '__main__': ...@@ -452,16 +465,22 @@ if __name__ == '__main__':
help='check the config_file against these preferences') help='check the config_file against these preferences')
parser.add_argument('--debug', action='store_true', parser.add_argument('--debug', action='store_true',
help='enable internal debug mode') help='enable internal debug mode')
parser.add_argument('--json', action='store_true',
help='print results in JSON format')
args = parser.parse_args() args = parser.parse_args()
if args.debug: if args.debug:
debug_mode = True debug_mode = True
if args.json:
json_mode = True
if debug_mode and json_mode:
sys.exit('[!] ERROR: options --debug and --json cannot be used simultaneously')
if args.config: if args.config:
arch, msg = detect_arch(args.config) arch, msg = detect_arch(args.config)
if not arch: if not arch:
sys.exit('[!] ERROR: {}'.format(msg)) sys.exit('[!] ERROR: {}'.format(msg))
else: elif not json_mode:
print('[+] Detected architecture: {}'.format(arch)) print('[+] Detected architecture: {}'.format(arch))
construct_checklist(arch) construct_checklist(arch)
...@@ -470,13 +489,14 @@ if __name__ == '__main__': ...@@ -470,13 +489,14 @@ if __name__ == '__main__':
ok_count = len(list(filter(lambda opt: opt.result.startswith('OK'), checklist))) ok_count = len(list(filter(lambda opt: opt.result.startswith('OK'), checklist)))
if debug_mode: if debug_mode:
sys.exit(0) sys.exit(0)
if not json_mode:
print('[+] config check is finished: \'OK\' - {} / \'FAIL\' - {}'.format(ok_count, error_count)) print('[+] config check is finished: \'OK\' - {} / \'FAIL\' - {}'.format(ok_count, error_count))
sys.exit(0) sys.exit(0)
if args.print: if args.print:
arch = args.print arch = args.print
construct_checklist(arch) construct_checklist(arch)
print_checklist(arch) print_checks(arch)
sys.exit(0) sys.exit(0)
parser.print_help() parser.print_help()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment