]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #7820 from pieterlexis/systemd-no-setuid
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 7 Feb 2020 11:15:36 +0000 (12:15 +0100)
committerGitHub <noreply@github.com>
Fri, 7 Feb 2020 11:15:36 +0000 (12:15 +0100)
dnsdist: don't start as root within a systemd environment

13 files changed:
builder-support/debian/dnsdist/debian-buster/dnsdist.postinst
builder-support/debian/dnsdist/debian-buster/rules
builder-support/debian/dnsdist/debian-jessie/dnsdist.postinst
builder-support/debian/dnsdist/debian-jessie/rules
builder-support/debian/dnsdist/debian-stretch/dnsdist.postinst
builder-support/debian/dnsdist/debian-stretch/rules
pdns/dnsdist.cc
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/dnsdist-systemd.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-systemd.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist.service.in
pdns/dnsdistdist/m4/pdns_with_service_user.m4 [new symlink]

index 319a26406a4ff8a367cc228ed1953382f706791c..7bbf10b16b81f26892692cfe5b1a8623e3d29654 100644 (file)
@@ -18,6 +18,12 @@ case "$1" in
 
     adduser --force-badname --system --home /nonexistent --group \
         --no-create-home --quiet _dnsdist || true
+
+    if [ "`stat -c '%U:%G' /etc/powerdns/dnsdist.conf`" = "root:root" ]; then
+      chown root:_dnsdist /etc/powerdns/dnsdist.conf
+      # Make sure that dnsdist can read it; the default used to be 0600
+      chmod g+r /etc/powerdns/dnsdist.conf
+    fi
   ;;
 
   abort-upgrade|abort-remove|abort-deconfigure)
index 9f49e0b6ce063374c1d3fa2520750b3e21acf79f..31d234e4ead403e419795cc5fd759e87076c6619 100755 (executable)
@@ -51,6 +51,8 @@ override_dh_auto_configure:
          --with-ebpf \
          --with-lua=luajit \
          --with-protobuf \
+         --with-service-user='_dnsdist' \
+         --with-service-group='_dnsdist' \
          $(CONFIGURE_ARGS)
 
 override_dh_auto_build-arch:
@@ -58,8 +60,6 @@ override_dh_auto_build-arch:
 
 override_dh_install:
        dh_auto_install
-       echo Patching uid and git into debian/dnsdist/lib/systemd/system/*.service
-       perl -pi -e 's/(^ExecStart=.*)/$$1 -u _dnsdist -g _dnsdist/' debian/dnsdist/lib/systemd/system/*.service
 ifeq ($(DEB_HOST_ARCH_BITS),32)
        echo RestrictAddressFamilies is broken on 32bit, removing it from service file
        perl -ni -e 'print unless /RestrictAddressFamilies/' debian/dnsdist/lib/systemd/system/*.service
@@ -75,3 +75,7 @@ override_dh_installexamples:
 override_dh_installinit:
        # do nothing here. avoids referencing a non-existant init script.
 
+override_dh_fixperms:
+       dh_fixperms
+        # these files often contain passwords. 640 as it is chowned to root:_dnsdist
+       chmod 0640 debian/dnsdist/etc/dnsdist/dnsdist.conf
index 319a26406a4ff8a367cc228ed1953382f706791c..7bbf10b16b81f26892692cfe5b1a8623e3d29654 100644 (file)
@@ -18,6 +18,12 @@ case "$1" in
 
     adduser --force-badname --system --home /nonexistent --group \
         --no-create-home --quiet _dnsdist || true
+
+    if [ "`stat -c '%U:%G' /etc/powerdns/dnsdist.conf`" = "root:root" ]; then
+      chown root:_dnsdist /etc/powerdns/dnsdist.conf
+      # Make sure that dnsdist can read it; the default used to be 0600
+      chmod g+r /etc/powerdns/dnsdist.conf
+    fi
   ;;
 
   abort-upgrade|abort-remove|abort-deconfigure)
index e0f70b6c9a0ae74bca3f8e97ae607b60f1f60274..989562eb9369cd05aee5929355bf8d3fab1773fa 100755 (executable)
@@ -47,6 +47,8 @@ override_dh_auto_configure:
          --with-ebpf \
          --with-lua=luajit \
          --with-protobuf \
+         --with-service-user='_dnsdist' \
+         --with-service-group='_dnsdist' \
          $(CONFIGURE_ARGS)
 
 override_dh_auto_build-arch:
@@ -54,8 +56,6 @@ override_dh_auto_build-arch:
 
 override_dh_install:
        dh_install
-       echo Patching uid and git into debian/dnsdist/lib/systemd/system/*.service
-       perl -pi -e 's/(^ExecStart=.*)/$$1 -u _dnsdist -g _dnsdist/' debian/dnsdist/lib/systemd/system/*.service
 ifeq ($(DEB_HOST_ARCH_BITS),32)
        echo RestrictAddressFamilies is broken on 32bit, removing it from service file
        perl -ni -e 'print unless /RestrictAddressFamilies/' debian/dnsdist/lib/systemd/system/*.service
@@ -74,3 +74,8 @@ override_dh_strip:
 override_dh_installinit:
        dh_installinit
        dh_systemd_start -pdnsdist --restart-after-upgrade dnsdist.service
+
+override_dh_fixperms:
+       dh_fixperms
+        # these files often contain passwords. 640 as it is chowned to root:_dnsdist
+       chmod 0640 debian/dnsdist/etc/dnsdist/dnsdist.conf
index 319a26406a4ff8a367cc228ed1953382f706791c..7bbf10b16b81f26892692cfe5b1a8623e3d29654 100644 (file)
@@ -18,6 +18,12 @@ case "$1" in
 
     adduser --force-badname --system --home /nonexistent --group \
         --no-create-home --quiet _dnsdist || true
+
+    if [ "`stat -c '%U:%G' /etc/powerdns/dnsdist.conf`" = "root:root" ]; then
+      chown root:_dnsdist /etc/powerdns/dnsdist.conf
+      # Make sure that dnsdist can read it; the default used to be 0600
+      chmod g+r /etc/powerdns/dnsdist.conf
+    fi
   ;;
 
   abort-upgrade|abort-remove|abort-deconfigure)
index 4ae2ee8a810c18eaa88726d3301b6f610248ab89..dafe4957e14bddfa8c18b3a637787a9295fd4db2 100755 (executable)
@@ -50,6 +50,8 @@ override_dh_auto_configure:
          --with-ebpf \
          --with-lua=luajit \
          --with-protobuf \
+         --with-service-user='_dnsdist' \
+         --with-service-group='_dnsdist' \
          $(CONFIGURE_ARGS)
 
 override_dh_auto_build-arch:
@@ -57,8 +59,6 @@ override_dh_auto_build-arch:
 
 override_dh_install:
        dh_auto_install
-       echo Patching uid and git into debian/dnsdist/lib/systemd/system/*.service
-       perl -pi -e 's/(^ExecStart=.*)/$$1 -u _dnsdist -g _dnsdist/' debian/dnsdist/lib/systemd/system/*.service
 ifeq ($(DEB_HOST_ARCH_BITS),32)
        echo RestrictAddressFamilies is broken on 32bit, removing it from service file
        perl -ni -e 'print unless /RestrictAddressFamilies/' debian/dnsdist/lib/systemd/system/*.service
@@ -74,3 +74,7 @@ override_dh_installexamples:
 override_dh_installinit:
        # do nothing here. avoids referencing a non-existant init script.
 
+override_dh_fixperms:
+       dh_fixperms
+        # these files often contain passwords. 640 as it is chowned to root:_dnsdist
+       chmod 0640 debian/dnsdist/etc/dnsdist/dnsdist.conf
index eaf15e542cd904f7a220eccbd912cfde99d97390..7e93aa67702bbfaa48356f83852d68910c7940d8 100644 (file)
@@ -37,6 +37,7 @@
 #include <editline/readline.h>
 #endif
 
+#include "dnsdist-systemd.hh"
 #ifdef HAVE_SYSTEMD
 #include <systemd/sd-daemon.h>
 #endif
@@ -2590,8 +2591,8 @@ try
   }
 #endif
 
-  uid_t newgid=0;
-  gid_t newuid=0;
+  uid_t newgid=getegid();
+  gid_t newuid=geteuid();
 
   if(!g_cmdLine.gid.empty())
     newgid = strToGID(g_cmdLine.gid.c_str());
@@ -2599,8 +2600,22 @@ try
   if(!g_cmdLine.uid.empty())
     newuid = strToUID(g_cmdLine.uid.c_str());
 
-  dropGroupPrivs(newgid);
-  dropUserPrivs(newuid);
+  if (getegid() != newgid) {
+    if (running_in_service_mgr()) {
+      errlog("--gid/-g set on command-line, but dnsdist was started as a systemd service. Use the 'Group' setting in the systemd unit file to set the group to run as");
+      _exit(EXIT_FAILURE);
+    }
+    dropGroupPrivs(newgid);
+  }
+
+  if (geteuid() != newuid) {
+    if (running_in_service_mgr()) {
+      errlog("--uid/-u set on command-line, but dnsdist was started as a systemd service. Use the 'User' setting in the systemd unit file to set the user to run as");
+      _exit(EXIT_FAILURE);
+    }
+    dropUserPrivs(newuid);
+  }
+
   try {
     /* we might still have capabilities remaining,
        for example if we have been started as root
index a4982f27bd79c7ed39974759074521c60cf0a7c1..73e329c5da2ef279a6df449d1ae0be149e930a30 100644 (file)
@@ -144,6 +144,7 @@ dnsdist_SOURCES = \
        dnsdist-rules.hh \
        dnsdist-secpoll.cc dnsdist-secpoll.hh \
        dnsdist-snmp.cc dnsdist-snmp.hh \
+       dnsdist-systemd.cc dnsdist-systemd.hh \
        dnsdist-tcp.cc \
        dnsdist-web.cc \
        dnsdist-xpf.cc dnsdist-xpf.hh \
@@ -399,7 +400,7 @@ endif
 
 if HAVE_SYSTEMD
 dnsdist.service: dnsdist.service.in
-       $(AM_V_GEN)sed -e 's![@]bindir[@]!$(bindir)!' < $< > $@
+       $(AM_V_GEN)sed -e 's![@]bindir[@]!$(bindir)!' -e 's![@]service_user[@]!$(service_user)!' -e 's![@]service_group[@]!$(service_group)!' < $< > $@
 if !HAVE_SYSTEMD_LOCK_PERSONALITY
        $(AM_V_GEN)perl -ni -e 'print unless /^LockPersonality/' $@
 endif
index e0109dc2843772162d6e92a1ea583852460ffdc9..89bb865e19c3ad0126eb4d1a4addd1b7275fae98 100644 (file)
@@ -47,6 +47,7 @@ PDNS_WITH_LIBCAP
 AX_AVAILABLE_SYSTEMD
 AX_CHECK_SYSTEMD_FEATURES
 AM_CONDITIONAL([HAVE_SYSTEMD], [ test x"$systemd" = "xy" ])
+PDNS_WITH_SERVICE_USER([dnsdist])
 
 dnl the *_r functions are in posix so we can use them unconditionally, but the ext/yahttp code is
 dnl using the defines.
diff --git a/pdns/dnsdistdist/dnsdist-systemd.cc b/pdns/dnsdistdist/dnsdist-systemd.cc
new file mode 100644 (file)
index 0000000..6f9f890
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "config.h"
+#include "dnsdist-systemd.hh"
+#include <cstdlib>
+
+bool running_in_service_mgr() {
+#ifdef HAVE_SYSTEMD
+  char *c;
+  c = getenv("NOTIFY_SOCKET"); // XXX Ideally we'd check for INVOCATION_ID (systemd.exec(5)), but that was introduced in systemd 232, and Debian Jessie has 215
+  if (c != nullptr) {
+    return true;
+  }
+#endif
+  return false;
+}
diff --git a/pdns/dnsdistdist/dnsdist-systemd.hh b/pdns/dnsdistdist/dnsdist-systemd.hh
new file mode 100644 (file)
index 0000000..046905c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+bool running_in_service_mgr();
index 85de6f951e60afefcc73c455152ff44c64dc79e3..c96c37c168ee21283dccb3f34af0dec2fcff33bf 100644 (file)
@@ -9,6 +9,8 @@ After=network-online.target
 ExecStartPre=@bindir@/dnsdist --check-config
 # Note: when editing the ExecStart command, keep --supervised and --disable-syslog
 ExecStart=@bindir@/dnsdist --supervised --disable-syslog
+User=@service_user@
+Group=@service_group@
 Type=notify
 Restart=on-failure
 RestartSec=2
@@ -20,7 +22,8 @@ LimitNOFILE=16384
 TasksMax=8192
 
 # Sandboxing
-CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID
+CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+AmbientCapabilities=CAP_NET_BIND_SERVICE
 LockPersonality=true
 NoNewPrivileges=true
 PrivateDevices=true
diff --git a/pdns/dnsdistdist/m4/pdns_with_service_user.m4 b/pdns/dnsdistdist/m4/pdns_with_service_user.m4
new file mode 120000 (symlink)
index 0000000..bc72a6e
--- /dev/null
@@ -0,0 +1 @@
+../../../m4/pdns_with_service_user.m4
\ No newline at end of file