security updates

This commit is contained in:
Alexey Avramov 2019-10-05 16:51:39 +09:00
parent 77325b42d6
commit 2a3209ca72
5 changed files with 113 additions and 45 deletions

View File

@ -11,6 +11,7 @@ from sre_constants import error as invalid_re
from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
############################################################################### ###############################################################################
# define functions # define functions
@ -19,25 +20,27 @@ from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
def exe(cmd): def exe(cmd):
""" execute cmd in subprocess.Popen() """ execute cmd in subprocess.Popen()
""" """
cmd_list = shlex.split(cmd)
cmd_num_dict['cmd_num'] += 1 cmd_num_dict['cmd_num'] += 1
cmd_num = cmd_num_dict['cmd_num'] cmd_num = cmd_num_dict['cmd_num']
log('Execute the command({}) in {}: {}'.format(
log('Execute the command ({}) in {}: {}'.format(
cmd_num, cmd_num,
threading.current_thread().getName(), threading.current_thread().getName(),
cmd)) cmd_list))
t3 = monotonic() t3 = monotonic()
with Popen(cmd, shell=True) as proc: with Popen(cmd_list) as proc:
try: try:
proc.wait(timeout=exe_timeout) proc.wait(timeout=exe_timeout)
exit_status = proc.poll() exit_status = proc.poll()
t4 = monotonic() t4 = monotonic()
log('Command({}) execution completed in {} sec; exit status' \ log('Command ({}) execution completed in {} sec; exit status' \
': {}'.format(cmd_num, round(t4 - t3, 3), exit_status)) ': {}'.format(cmd_num, round(t4 - t3, 3), exit_status))
except TimeoutExpired: except TimeoutExpired:
proc.kill() proc.kill()
t4 = monotonic() t4 = monotonic()
log('TimeoutExpired for the command({}) in {} sec'.format( log('TimeoutExpired for the command ({}) in {} sec'.format(
cmd_num, round(t4 - t3, 3))) cmd_num, round(t4 - t3, 3)))
@ -61,9 +64,9 @@ def start_thread(func, *a, **k):
t2 = monotonic() t2 = monotonic()
if debug_threading: if debug_threading:
log('{} has started in {} ms, {} threads currently alive'.format( log('{} has started in {} ms, {} threads are ' \
th_name, round((t2 - t1) * 1000, 1), threading.active_count() 'currently alive'.format(th_name, round((
)) t2 - t1) * 1000, 1), threading.active_count()))
except RuntimeError: except RuntimeError:
@ -153,6 +156,17 @@ def pop(cmd, username):
""" run cmd in subprocess.Popen() """ run cmd in subprocess.Popen()
""" """
cmd_num_dict['cmd_num'] += 1
cmd_num = cmd_num_dict['cmd_num']
log('Execute the Command-{} {} in {}'.format(
cmd_num,
cmd,
threading.current_thread().getName()
))
if swap_total == 0: if swap_total == 0:
wait_time = 2 wait_time = 2
else: else:
@ -164,18 +178,15 @@ def pop(cmd, username):
try: try:
proc.wait(timeout=wait_time) proc.wait(timeout=wait_time)
err = proc.poll() err = proc.poll()
t4 = monotonic()
except TimeoutExpired: except TimeoutExpired:
proc.kill() proc.kill()
t4 = monotonic()
if debug_gui_notifications: if debug_gui_notifications:
log('TimeoutExpired: notify user: {}'.format(username)) log('TimeoutExpired: notify user: {}'.format(username))
t4 = monotonic()
err = 0
if debug_gui_notifications: if debug_gui_notifications:
pass
#log('Popen time: {} sec; exit status: {}; cmd: {}'.format(round(t4 - t3, 3), err, cmd))
log('Popen time: {} sec; exit status: {}; cmd: {}'.format(round(t4 - t3, 3), err, cmd)) log('Popen time: {} sec; exit status: {}; cmd: {}'.format(round(t4 - t3, 3), err, cmd))
@ -279,6 +290,10 @@ def send_notify(threshold, name, pid):
""" """
title = 'Freeze prevention' title = 'Freeze prevention'
if hide_corrective_action_type:
body = 'Corrective action applied'
else:
body = '<b>{}</b> [{}] <b>{}</b>'.format( body = '<b>{}</b> [{}] <b>{}</b>'.format(
notify_sig_dict[threshold], notify_sig_dict[threshold],
pid, pid,
@ -286,8 +301,7 @@ def send_notify(threshold, name, pid):
# symbol '&' can break notifications in some themes, # symbol '&' can break notifications in some themes,
# therefore it is replaced by '*' # therefore it is replaced by '*'
'&', '*' '&', '*'
) ))
)
start_thread(send_notification, title, body) start_thread(send_notification, title, body)
@ -301,9 +315,12 @@ def send_notify_etc(pid, name, command):
pid: str process pid pid: str process pid
""" """
title = 'Freeze prevention' title = 'Freeze prevention'
body = '<b>Victim is</b> [{}] <b>{}</b>\nExecute the co' \ if hide_corrective_action_type:
'mmand:\n<b>{}</b>'.format( body = 'Corrective action applied'
pid, name.replace('&', '*'), command.replace('&', '*')) else:
body = '<b>Victim is</b> [{}] <b>{}</b>\nExecute the command:\n<b>' \
'{}</b>'.format(pid, name.replace(
'&', '*'), command.replace('&', '*'))
start_thread(send_notification, title, body) start_thread(send_notification, title, body)
@ -3016,9 +3033,24 @@ print_victim_cmdline = conf_parse_bool('print_victim_cmdline')
print_config_at_startup = conf_parse_bool('print_config_at_startup') print_config_at_startup = conf_parse_bool('print_config_at_startup')
print_mem_check_results = conf_parse_bool('print_mem_check_results') print_mem_check_results = conf_parse_bool('print_mem_check_results')
debug_sleep = conf_parse_bool('debug_sleep') debug_sleep = conf_parse_bool('debug_sleep')
hide_corrective_action_type = conf_parse_bool('hide_corrective_action_type')
low_memory_warnings_enabled = conf_parse_bool('low_memory_warnings_enabled') low_memory_warnings_enabled = conf_parse_bool('low_memory_warnings_enabled')
post_action_gui_notifications = conf_parse_bool( post_action_gui_notifications = conf_parse_bool(
'post_action_gui_notifications') 'post_action_gui_notifications')
@ -3369,33 +3401,35 @@ if separate_log:
import logging import logging
log_dir = '/var/log/nohang' log_dir = '/var/log/nohang'
try:
os.mkdir(log_dir)
except PermissionError:
print('ERROR: can not create log dir')
except FileExistsError:
pass
logfile = log_dir + '/nohang.log' logfile = log_dir + '/nohang.log'
try: try:
with open(logfile, 'a') as f: os.mkdir(log_dir)
except FileExistsError:
pass pass
except FileNotFoundError:
print('ERROR: log FileNotFoundError')
except PermissionError: except PermissionError:
print('ERROR: log PermissionError') errprint('ERROR: cannot create {}'.format(log_dir))
try:
os.chmod(log_dir, mode=0o750)
except FileNotFoundError:
errprint('ERROR: file not found: {}'.format(log_dir))
except PermissionError:
errprint('ERROR: permission denied: {}'.format(log_dir))
try: try:
logging.basicConfig( logging.basicConfig(
filename=logfile, filename=logfile,
level=logging.INFO, level=logging.INFO,
format="%(asctime)s: %(message)s") format="%(asctime)s: %(message)s")
except PermissionError:
errprint('ERROR: Permission denied: {}'.format(logfile))
except FileNotFoundError: except FileNotFoundError:
errprint('ERROR: FileNotFoundError: {}'.format(logfile)) errprint('ERROR: file not found: {}'.format(logfile))
except PermissionError:
errprint('ERROR: permission denied: {}'.format(logfile))
if 'min_mem_report_interval' in config_dict: if 'min_mem_report_interval' in config_dict:
@ -3511,11 +3545,13 @@ if (low_memory_warnings_enabled or \
post_kill_exe != ''): post_kill_exe != ''):
import threading import threading
import shlex
from subprocess import Popen, TimeoutExpired from subprocess import Popen, TimeoutExpired
psi_support = os.path.exists(psi_path) psi_support = os.path.exists(psi_path)

View File

@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications 4. Warnings and notifications
4.1. GUI notifications after corrective actions
Description: Description:
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
@ -122,6 +124,14 @@ post_action_gui_notifications = True
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
hide_corrective_action_type = True
4.2. Low memory warnings
Description:
Type: boolean
Valid values: True and False
low_memory_warnings_enabled = True low_memory_warnings_enabled = True
Description: Description:

View File

@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications 4. Warnings and notifications
4.1. GUI notifications after corrective actions
Description: Description:
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
@ -122,6 +124,14 @@ post_action_gui_notifications = False
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
hide_corrective_action_type = True
4.2. Low memory warnings
Description:
Type: boolean
Valid values: True and False
low_memory_warnings_enabled = False low_memory_warnings_enabled = False
Description: Description:

View File

@ -8,18 +8,20 @@ ExecStart=:TARGET_BIN:/nohang --config :TARGET_CONF:/nohang/nohang.conf
Restart=always Restart=always
RestartSec=0 RestartSec=0
KillMode=mixed KillMode=mixed
TasksMax=100
Nice=-15 Nice=-15
CPUSchedulingResetOnFork=true CPUSchedulingResetOnFork=true
OOMScoreAdjust=-10 OOMScoreAdjust=-10
UMask=0027
PrivateTmp=true
RestrictRealtime=yes RestrictRealtime=yes
MemoryDenyWriteExecute=yes MemoryDenyWriteExecute=yes
ProtectKernelModules=true ProtectKernelModules=true
SystemCallArchitectures=native SystemCallArchitectures=native
ReadOnlyPaths=/ ReadOnlyPaths=/
ReadWritePaths=/tmp /var /run /dev/shm ReadWritePaths=/tmp /var /run /dev/shm
PrivateTmp=true CapabilityBoundingSet=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID
CapabilityBoundingSet=CAP_KILL CAP_AUDIT_WRITE CAP_DAC_READ_SEARCH CAP_IPC_LOCK CAP_SETGID CAP_SETUID CAP_SYS_PTRACE CAP_CHOWN AmbientCapabilities=CAP_KILL CAP_IPC_LOCK CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE CAP_SETUID CAP_SETGID
AmbientCapabilities=CAP_KILL CAP_AUDIT_WRITE CAP_DAC_READ_SEARCH CAP_IPC_LOCK CAP_SETGID CAP_SETUID CAP_SYS_PTRACE
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -112,6 +112,8 @@ over_sleep = 0.05
4. Warnings and notifications 4. Warnings and notifications
4.1. GUI notifications after corrective actions
Description: Description:
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
@ -122,6 +124,14 @@ post_action_gui_notifications = True
Type: boolean Type: boolean
Valid values: True and False Valid values: True and False
hide_corrective_action_type = False
4.2. Low memory warnings
Description:
Type: boolean
Valid values: True and False
low_memory_warnings_enabled = True low_memory_warnings_enabled = True
Description: Description: