Skip to content

Commit

Permalink
hardened and made more reliable monitor.service file:
Browse files Browse the repository at this point in the history
since the service depends on bluetooth daemon, start after it ( After= )
since the daemon fails to work properly without bluetooth, don't start it if blueetooth fails ( Requires= )
shut down the service when bluetooth fails ( BindsTo= )

since the daemon isn't necessary for networking, don't install it network target

set restart mode on-failure so that if the user accidentally sets a one-shot setting manually in the service, it doesn't keep re-launching it

don't fork the process in the background so that systemd can track the pids of all the programs spawned and kill them if they hang to ensure a proper shutdown


split re-writable file with environment to a separate optional file $service_config_path which equals to "/etc/default/monitor", the daemon file shouldn't re-write it's own service file for both security and bug prevention

since the daemon runs with ultimate priviledges and it's networked, removing the unnecessary ones can prevent system disruption in the case of a bug or a flyby scripted attack:

LockPersonality ensures kenel personality(2) is enforced
NoNewPrivileges fixes process privileges as the one set in the srvice
PrivateMounts makes any mount point created by the service private to the service itself
ProtectClock prevents the system clock to be altered by the service
ProtectControlGroups prevents the system to access the kernel control groups ( and override the security settings )
ProteectKernelLogs prevents the access to the kernel logs
ProtectKernelModules prevents load/unload kernel modules; bluetooth modules will be loadeed as necessary anyway from the bluetooth.service
ProtectKernelTunables denies accceess to the kernel runtime config
ProtectHostname prevents hostname changes from the service
ProtectHome prevents writing files to the home dir of the user
ProtectProc=invisible makes the service be able to see only its own process tree and no further
ProtectSystem=strict makes the whole filesystem read-only except for the paths specified in ReadWritePaths
RestrictNamespaces denies altering the process namespace, useful to prevent bypassing protections
RestrictAddressFamilies limits the types of sockets that can be read/written by the procss
RestrictSUIDSGID prevents setting SUID and GID bits on files
RestrictRealtime prevents acquiring realtime scheduling priority
SystemCallArchitectures ensures that only native binaries are used ( eg only 64 bit in a mixed 32-64 bit environment; 32 bit ISA is often full of security pitholes )
SystemCallFilter=~@mount denies access to the mount functionality to prevent bypassing most of the security settings

ReadWritePaths=/sys/class/bluetooth allows raw access to the bluetoot devices
ReadWritePaths=$base_directory allows the service to overwrite itself / its config ( dangerous, but fixing it is not in the scope of this patch )
ReadWritePaths=$service_config_path allows the sevice to overwrite the execution args of the daemon

daemon-reload is not necessary to reload the environment file, so it's only executed for service installation

all the features used are documented in systemd.exec(5) systemd.unit(5) systemd.service(5)
  • Loading branch information
BrainDamage authored and BrainDamage committed Dec 9, 2020
1 parent ec0496b commit 826b686
Showing 1 changed file with 46 additions and 13 deletions.
59 changes: 46 additions & 13 deletions support/init
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#FIND DEPENDENCY PATHS, ELSE MANUALLY SET
service_path="/etc/systemd/system/monitor.service"
service_config_path="/etc/default/monitor"
mosquitto_pub_path=$(which mosquitto_pub)
mosquitto_sub_path=$(which mosquitto_sub)
hcidump_path=$(which hcidump)
Expand Down Expand Up @@ -203,14 +204,11 @@ fi
#----------------------------------------------------------------------------------------
# CHECK MONITOR.SERVICE (IF APPLICABLE)
#
# CREDITS & CONTRIBUTIONS: x99percent
# CREDITS & CONTRIBUTIONS: x99percent, BrainDamage
# ----------------------------------------------------------------------------------------

#FILTER THE ARGV FROM THE PARENT SCRIPT TO REMOVE ONE-TIME USE VARIABLES
FILTERED_ARGS=$(printf '%s\n' "$(IFS=' '; echo "${RUNTIME_ARGS[*]}")" | sed 's/ \?-d//gi;s/ \?-V//gi;s/ \?-F//gi;s/ \?-u//gi;s/&//g;s/ */ /gi')

#CHECK FOR CORRECT SERVICE;
if [ "$should_install" == "y" ] || [ "$PREF_UPDATE_SERVICE" == true ] ; then
#CHECK FOR CORRECT SERVICE;
if [ "$should_install" == "y" ]; then
#REMOVE ALL INSTANCES
if [ -f "$service_path" ]; then
rm "$service_path" 2>&1 >/dev/null
Expand All @@ -222,26 +220,61 @@ if [ "$should_install" == "y" ] || [ "$PREF_UPDATE_SERVICE" == true ] ; then
printf "%s\n" "[Unit]
Description=Monitor Service
After=network.target
After=bluetooth.service
BindsTo=bluetooth.service
Requires=bluetooth.service
[Service]
User=root
ExecStart=/bin/bash $base_directory/$(basename $0) $FILTERED_ARGS &
ExecStart=/bin/bash $base_directory/$(basename $0) \${MONITOR_ARGS}
WorkingDirectory=$base_directory
Restart=always
EnvironmentFile=-$service_config_path
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target network.target" > "$service_path"
LockPersonality=True
NoNewPrivileges=True
PrivateMounts=True
ProtectClock=True
ProtectControlGroups=True
ProtectKernelLogs=True
ProtectKernelModules=True
ProtectKernelTunables=True
ProtectHostname=True
ProtectHome=True
ProtectProc=invisible
ProtectSystem=strict
RestrictNamespaces=True
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_BLUETOOTH
RestrictSUIDSGID=True
RestrictRealtime=True
SystemCallArchitectures=native
SystemCallFilter=~@mount
ReadWritePaths=/sys/class/bluetooth
ReadWritePaths=$base_directory
ReadWritePaths=$service_config_path
#PRINT RESULTS
[ "$PREF_UPDATE_SERVICE" == true ] && printf "%s\n" "> monitor.service updated with arguments: $FILTERED_ARGS"
[Install]
WantedBy=multi-user.target" > "$service_path"

sleep 3

#RELOAD DAEMON AND ENABLE SERVICE
systemctl daemon-reload
systemctl enable monitor.service
fi
fi

#FILTER THE ARGV FROM THE PARENT SCRIPT TO REMOVE ONE-TIME USE VARIABLES
FILTERED_ARGS=$(printf '%s\n' "$(IFS=' '; echo "${RUNTIME_ARGS[*]}")" | sed 's/ \?-d//gi;s/ \?-V//gi;s/ \?-F//gi;s/ \?-u//gi;s/&//g;s/ */ /gi')

if [ "$should_install" == "y" ] || [ "$PREF_UPDATE_SERVICE" == true ]; then
printf "%s\n" "MONITOR_ARGS=$FILTERED_ARGS" > "$service_path"

#PRINT RESULTS
[ "$PREF_UPDATE_SERVICE" == true ] && printf "%s\n" "> monitor.service updated with arguments: $FILTERED_ARGS"
fi


#----------------------------------------------------------------------------------------
# BEFORE WE ECHO PREFERENCES, EXIT IF WE NEED TO
Expand Down

0 comments on commit 826b686

Please sign in to comment.