Bug#996927: Drop NSCD_SOCKET_OLD and harden systemd unit?

2021-10-20 Thread Trent W. Buck
Trent W. Buck wrote:
> RuntimeDirectory=unscd

That's a typo, it should be "RuntimeDirectory=nscd".
Testing didn't catch it until I did a reboot, because
the non-systemd doesn't remove /run/nscd when unscd stops.



Bug#996927: Drop NSCD_SOCKET_OLD and harden systemd unit?

2021-10-20 Thread Trent W. Buck
Package: unscd
Version: 0.54-1
Severity: wishlist

I wrote a hardening dropin (attached) for unscd.service.

$ systemd-analyze security
UNIT   EXPOSURE PREDICATE HAPPY
unscd.service   9.6 UNSAFE  # before
unscd.service   1.1 OK  # after

Please consider adding some/all of it to debian/unscd.service.
You may need to "dial back" the hardening a little, e.g.
PADL libnss-ldap (dead since 2016, but still in Debian 11) probably needs 
AF_INET AF_INET6.

Two further improvements require source code changes:

  * Removing NSCD_SOCKET_OLD from nscd.c.
I *think* glibc hasn't used this path for over a decade now!
Removing it will allow systemd to block write access to /run.

  * Make unscd only drop privileges if it starts as root (or so).
This will allow systemd to drop privileges before unscd starts, and
block CAP_SET[UG]ID and sete[ug]id(2).

I am using unscd with its default nscd.conf.
It provides a short-term cache for nss-pam-ldapd,
reducing the load on the LDAP server (slapd or samba-ad) by 90% to 99%.

My test case was to do this (testing passwd negative-ttl only) :

# for i in {1..}; do touch "$i"; chown -h 1234 "$i"; done
# time find -nouser -fprintf /dev/null .
real0m1.176s# unscd is stopped
real0m0.446s# unscd is running

With my dropin, this test still passes, so I think unscd is both running and 
working.


-- System Information:
Debian Release: 11.0
  APT prefers stable-updates
  APT policy: (990, 'stable-updates'), (990, 'stable-security'), (990, 
'stable'), (500, 'proposed-updates'), (500, 'unstable'), (500, 'testing'), (1, 
'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 5.10.0-8-amd64 (SMP w/8 CPU threads)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, 
TAINT_UNSIGNED_MODULE
Locale: LANG=en_AU.UTF-8, LC_CTYPE=en_AU.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
# This file goes in /etc/systemd/system/unscd.service.d/hardening.conf

[Service]
PrivateNetwork=yes
## We can't drop root privs before starting, because
## it wants to bind BOTH of these:
##
##define NSCD_SOCKET "/var/run/nscd/socket"
##define NSCD_SOCKET_OLD "/var/run/.nscd_socket"
##
## Probably the latter should just be removed from unscd.c entirely, since
## the implementations of glibc that use it are probably long gone.
# User=unscd
# DynamicUser=yes
RuntimeDirectory=unscd
WorkingDirectory=/run/nscd
CapabilityBoundingSet=
# FIXME: once we Users=unscd, tighten this up.
CapabilityBoundingSet=CAP_SETUID CAP_SETGID
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
DevicePolicy=closed
IPAddressDeny=any
NoNewPrivileges=yes
PrivateDevices=yes
PrivateMounts=yes
PrivateTmp=yes
# FIXME: once we Users=unscd, tighten this up.
# UPDATE: er, we probably need PrivateUsers=no anyway, because
# nscd's job is to see & cache users. :-)
#PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
# FIXME: once NSCD_SOCKET_OLD is gone, remove this.
ReadWritePaths=/run
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
# FIXME: once we Users=unscd, tighten this up.
#SystemCallFilter=~@privileged
SystemCallFilter=~@resources
RestrictRealtime=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
UMask=0077
ProtectHostname=yes
ProcSubset=pid