Skip to content

Commit

Permalink
Improve SystemD service file settings
Browse files Browse the repository at this point in the history
Service user:
Added explicit user and group settings for service files. Clamd and
Freshclam now run as clamav user. Per documentation, the service forks
off process that runs as user specfied in the config. This change makes
that explicit.

Clamonacc still runs as root since it needs to access files that are not
owned by the default clamav user. An alternative approach is to use the
--fdpass to pass the file descriptor perms to Clamd instead of having to
stream the entire file.

Other changes:
- [gen] Added explicit service types. Forking type for ClamD failed even
  without foreground switch. So the service runs as a simple daemon.
- [doc] Updated comment strings to make them concise and unambiguous.
- [sec] Added a safer permission mode for quarantine directory.
- [sec] Added several new security settings to protect the system. Since
  unknown settings are safely ignored by older versions of SystemD, the
  settings should automatically apply when SystemD version is bumped.
- [sec] Added new network security settings. Clamd and OnAcc are not
   allowed to use the networkr; only Freshclam is.
- [sec] Added restrictions to several system calls and Linux
  capabilities

TODO / Known issues:
- PreStart tasks need root user access - for example, to create the
  quarantine directory. The current approach is unreliable.
- Some settings such as PrivateUsers=yes break the service file.
- We need CMAKE/Automake substitution strings to add (multi-arch and
  arch dependent) LIBDIR to certain settings.
- ExecPaths and ReadWritePaths need locking down.
- Parameterize DATADIR - e.g. /var/log/quarantine
  • Loading branch information
eternaltyro committed Jan 29, 2024
1 parent bc62f25 commit a694172
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 34 deletions.
52 changes: 40 additions & 12 deletions clamd/clamav-daemon.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,65 @@ ConditionPathExistsGlob=@DATADIR@/main.{c[vl]d,inc}
ConditionPathExistsGlob=@DATADIR@/daily.{c[vl]d,inc}

[Service]
Type=simple
# WARNING: Must match clamd.conf directive
User=clamav
Group=clamav
;DynamicUser=yes
;ExecStartPre=/usr/bin/install --owner=root --group=root --mode=640 --directory /var/local/quarantine
ExecStart=@prefix@/sbin/clamd --foreground=true
# Reload the database
ExecReload=/bin/kill -USR2 $MAINPID
TimeoutStartSec=420
LogsDirectory=clamav
ConfigurationDirectory=clamav

##
## Security Hardening Options
##
#============================#
# Security Hardening Options #
#============================#
NoNewPrivileges=yes
;PrivateUsers=no

# Remove `ProtectSystem`, `ProtectHome`, and `ReadWritePaths`
# if you want ClamAV to be able to remove infected files.
# if you want ClamAV to be able to quarantine (`--move`) infected files.
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/var/log/clamav /run /var/run
PrivateTmp=yes
PrivateDevices=yes
ReadWritePaths=/var/log/clamav /run/clamav /var/run/clamav /var/local/quarantine

NoExecPaths=/
# If you want to run commands or execute binaries on event,
# append the full path of the binary or executable to `ExecPaths`
# Commonly, this is used for `VirusEvent` in clamd.conf or `VirusAction`
# in clamav-milter.conf.The binaries must be space separated like so:
;ExecPaths=@prefix@/sbin/clamd /bin/kill /usr/local/bin/send_sms /usr/local/bin/my_infected_message_handler
ExecPaths=@prefix@/sbin/clamd @CMAKE_INSTALL_FULL_LIBDIR@ /bin/kill
# WARNING: To execute targets of `VirusEvent` and `VirusAction` directives
# in the configuration, whitelist them in ExecPaths.
;ExecPaths=@prefix@/sbin/clamd /usr/local/bin/send_sms /usr/local/bin/my_infected_message_handler
ExecPaths=@prefix@/sbin/clamd @CMAKE_INSTALL_FULL_LIBDIR@ /bin/kill /usr/bin/install

ProtectClock=yes
ProtectHostname=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
PrivateTmp=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes

PrivateNetwork=yes
IPAddressDeny=any
RestrictAddressFamilies=none

# ProtectProc is only effective if:
# (1) Service is a system service and not a user service.
# (2) CAP_SYS_PTRACE is restricted and
# (3) Service user is non-root.
ProtectProc=invisible
ProcSubset=pid

CapabilityBoundingSet=CAP_CHOWN CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE CAP_MKNOD
RestrictNamespaces=yes
SystemCallFilter=~@clock @cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @resources @swap

[Install]
WantedBy=multi-user.target
Expand Down
54 changes: 43 additions & 11 deletions clamonacc/clamav-clamonacc.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,63 @@ After=clamav-daemon.service syslog.target network.target

[Service]
Type=simple
# WARNING: Must match clamd.conf directive
User=root
ExecStartPre=/usr/bin/install --owner=root --group=root --directory /var/local/quarantine
Group=root
;DynamicUser=yes
ExecStartPre=/usr/bin/install --owner=root --group=root --mode=640 --directory /var/local/quarantine
ExecStart=@prefix@/sbin/clamonacc --foreground --log=/var/log/clamav/clamonacc.log --move=/var/local/quarantine --ping 120 --wait
ExecReload=/bin/kill -SIGHUP $MAINPID
ExecStop=/bin/kill -SIGTERM $MAINPID
LogsDirectory=clamav
ConfigurationDirectory=clamav

##
## Security Hardening Options
##
ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
NoExecPaths=/
ExecPaths=@prefix@/sbin/clamonacc @CMAKE_INSTALL_FULL_LIBDIR@ /bin/kill /usr/bin/install
#============================#
# Security Hardening Options #
#============================#
NoNewPrivileges=yes
;PrivateUsers=no

# Remove `ProtectSystem`, `ProtectHome`, and `ReadWritePaths` if you
# want ClamAV to be able to quarantine or remove infected files.
ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
ReadWritePaths=/var/log/clamav /var/local/quarantine

NoExecPaths=/
# WARNING: To execute targets of `VirusEvent` and `VirusAction` directives
# in the cofiguration, whitelist them in ExecPaths.
ExecPaths=@prefix@/sbin/clamonacc @CMAKE_INSTALL_FULL_LIBDIR@ /bin/kill /usr/bin/install

ProtectClock=yes
ProtectHostname=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes

PrivateNetwork=yes
IPAddressDeny=any
RestrictAddressFamilies=none

# ProtectProc is only effective if:
# (1) Service is a system service and not a user service.
# (2) CAP_SYS_PTRACE is restricted and
# (3) Service user is non-root.
ProtectProc=invisible
ProcSubset=pid

CapabilityBoundingset=CAP_CHOWN CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE CAP_MKNOD
RestrictNamespaces=yes
SystemCallFilter=~@clock @cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @resources @swap

[Install]
WantedBy=multi-user.target
Alias=clamonacc.service
48 changes: 37 additions & 11 deletions freshclam/clamav-freshclam.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,55 @@ Wants=network-online.target
After=network-online.target

[Service]
Type=simple
# WARNING: Must match clamd.conf directive
User=clamav
Group=clamav
;DynamicUser=yes
ExecStart=@prefix@/bin/freshclam -d --foreground=true
LogsDirectory=clamav
ConfigurationDirectory=clamav

##
## Security Hardening Options
##
#============================#
# Security Hardening Options #
#============================#
NoNewPrivileges=yes
;PrivateUsers=no

ProtectSystem=full
ProtectHome=tmpfs
PrivateTmp=yes
PrivateDevices=yes
ReadWritePaths=@DATADIR@ /var/log/clamav

NoExecPaths=/
# WARNING: To execute targets of `OnUpdateExecute`, `OnErrorExecute` and `OnOutdatedExecute`
# directives in freshclam.conf, whitelist them in ExecPaths.
;ExecPaths=@prefix@/sbin/freshclam /usr/local/bin/OnOutdated.sh /usr/local/bin/OnErrorExecute.sh
ExecPaths=@prefix@/bin/freshclam

ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes

NoExecPaths=/
# If you want to run commands on event, append the full path of the command or
# executable to `ExecPaths`. Commonly, this is used for `OnUpdateExecute`,
# `OnErrorExecute`, and `OnOutdatedExecute` options in freshclam.conf. Make sure
# there is only one `ExecPaths` option. The binaries must be space separated like so:
;ExecPaths=@prefix@/sbin/freshclam /usr/local/bin/OnOutdated.sh /usr/local/bin/OnErrorExecute.sh
ExecPaths=@prefix@/bin/freshclam
ReadWritePaths=@DATADIR@ /var/log/clamav
PrivateNetwork=no
IPAddressAllow=any
RestrictAddressFamilies=AF_INET AF_INET6

ProtectProc=noaccess
ProcSubset=pid

CapabilityBoundingSet=CAP_CHOWN CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE CAP_MKNOD
RestrictNamespaces=yes
SystemCallFilter=~@clock @cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @resources @swap

[Install]
WantedBy=multi-user.target
Alias=freshclam.service

0 comments on commit a694172

Please sign in to comment.