treewide: Remove ineffective capability grants.

Systemd units with `PrivateUsers` set get their capabilities within the user namespace only [1].
As a result they do cannot bind to privileged ports even though they *appear* like they should be able to.

The units in this commit [2] set `PrivateUsers` unconditionally so binding to privileged ports is currently impossible.
Granting them CAP_NET_BIND_SERVICE is useless and misleading any reader of those modules.
Technically, this commit also hardens these modules ever so slightly.

(There are corner cases where this could make sense (e.g. across units, using `JoinsNamspaceOf`) but this is arcane enough to not to be present in nixpkgs.)

[1]: systemd.exec(5): PrivateUsers
[2]: found using `rg -e 'PrivateUsers.?=\s+[^f][^a]' -l | xargs rg -e '\bCAP_' -l`
This commit is contained in:
Eduard Bachmakov 2024-08-09 22:17:11 +02:00
parent cb9a96f23c
commit cb10fe8aaf
12 changed files with 2 additions and 27 deletions

View File

@ -1,7 +1,7 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) getExe mkIf mkOption mkEnableOption optionals types;
inherit (lib) getExe mkIf mkOption mkEnableOption types;
cfg = config.services.mollysocket;
configuration = format.generate "mollysocket.conf" cfg.settings;
@ -85,9 +85,7 @@ in {
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
environment.RUST_LOG = cfg.logLevel;
serviceConfig = let
capabilities = [ "" ] ++ optionals (cfg.settings.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
in {
serviceConfig = {
EnvironmentFile = cfg.environmentFile;
ExecStart = "${getExe package} server";
KillSignal = "SIGINT";
@ -97,8 +95,6 @@ in {
WorkingDirectory = "/var/lib/mollysocket";
# hardening
AmbientCapabilities = capabilities;
CapabilityBoundingSet = capabilities;
DevicePolicy = "closed";
DynamicUser = true;
LockPersonality = true;

View File

@ -364,9 +364,6 @@ in
SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "@setuid mbind" ];
# Needs to serve web page
PrivateNetwork = false;
} // lib.optionalAttrs (cfg.port < 1024) {
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
};
environment = env // {
PYTHONPATH = "${cfg.package.python.pkgs.makePythonPath cfg.package.propagatedBuildInputs}:${cfg.package}/lib/paperless-ngx/src";

View File

@ -119,9 +119,6 @@ in
# gunicorn needs setuid
SystemCallFilter = [ "@system-service" "~@privileged" "@resources" "@setuid" "@keyring" ];
UMask = "0066";
} // lib.optionalAttrs (cfg.port < 1024) {
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
};
wantedBy = [ "multi-user.target" ];

View File

@ -69,7 +69,6 @@ in
wantedBy = [ "multi-user.target" ];
environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
serviceConfig = {
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
DevicePolicy = "closed";
DynamicUser = true;
ExecStart = "${getExe cfg.package} --provider ${cfg.provider}";

View File

@ -126,7 +126,6 @@ in
wantedBy = [ "multi-user.target" ];
environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
serviceConfig = {
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
DevicePolicy = "closed";
DynamicUser = true;
ExecStart = "${getExe cfg.package}";

View File

@ -1811,8 +1811,6 @@ in
StateDirectory = cfg.stateDir;
StateDirectoryMode = "0700";
# Hardening
AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = if (cfg.port < 1024) then [ "CAP_NET_BIND_SERVICE" ] else [ "" ];
DeviceAllow = [ "/dev/null rw" ];
DevicePolicy = "strict";
LockPersonality = true;

View File

@ -80,7 +80,6 @@ in
];
RuntimeDirectory = "dex";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
BindReadOnlyPaths = [
"/nix/store"
"-/etc/dex"
@ -91,7 +90,6 @@ in
"-/etc/ssl/certs/ca-certificates.crt"
];
BindPaths = optional (cfg.settings.storage.type == "postgres") "/var/run/postgresql";
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
# ProtectClock= adds DeviceAllow=char-rtc r
DeviceAllow = "";
DynamicUser = true;

View File

@ -164,7 +164,6 @@ in
let
defaultServiceConfig = {
ReadWritePaths = "${cfg.dataDir}";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
DeviceAllow = "";
LockPersonality = true;
NoNewPrivileges = true;

View File

@ -61,7 +61,6 @@ in
wantedBy = [ "multi-user.target" ];
environment = lib.mapAttrs (_: v: if lib.isBool v then lib.boolToString v else toString v) cfg.settings;
serviceConfig = {
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
DevicePolicy = "closed";
DynamicUser = true;
EnvironmentFile = lib.optional (cfg.passwordFile != null) cfg.passwordFile;

View File

@ -109,7 +109,6 @@ in
LoadCredential = lib.optionalString (cfg.passwordFile != null)
"PHOTOPRISM_ADMIN_PASSWORD:${cfg.passwordFile}";
CapabilityBoundingSet = "";
LockPersonality = true;
PrivateDevices = true;
PrivateUsers = true;
@ -126,9 +125,6 @@ in
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@setuid @keyring" ];
UMask = "0066";
} // lib.optionalAttrs (cfg.port < 1024) {
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
};
wantedBy = [ "multi-user.target" ];

View File

@ -87,7 +87,6 @@ in
User = "powerdnsadmin";
Group = "powerdnsadmin";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
BindReadOnlyPaths = [
"/nix/store"
"-/etc/resolv.conf"
@ -97,7 +96,6 @@ in
]
++ (optional (cfg.secretKeyFile != null) cfg.secretKeyFile)
++ (optional (cfg.saltFile != null) cfg.saltFile);
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
# ProtectClock= adds DeviceAllow=char-rtc r
DeviceAllow = "";
# Implies ProtectSystem=strict, which re-mounts all paths

View File

@ -90,7 +90,6 @@ in {
"/var/run/mysqld";
CapabilityBoundingSet = "";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
DeviceAllow = "";