PowerDNS / pdns

PowerDNS Authoritative, PowerDNS Recursor, dnsdist
https://www.powerdns.com/
GNU General Public License v2.0
3.73k stars 915 forks source link

DynListener created before dropping privileges; results in fail on Capabilities perms check, unless CAP_DAC_OVERRIDE is added #4826

Closed ghost closed 6 years ago

ghost commented 7 years ago

Originally posted on ML as:

"socket-dir perms for pdns UID/GID not sufficient : "Unable to bind to control socket ... reason: Permission denied". 'o+w' dir perms required?"

This post

[Pdns-users] control socket permissions
 https://mailman.powerdns.com/pipermail/pdns-users/2011-September/020182.html

suggests that

If 'setgid' _is_ present, powerdns will run with that group ID; the socket will be set to that group ID too and permissions on the socket will be changed to 660.

I've installed

dig chaos txt version.bind @127.0.0.1 -p 15301 +short
    "PowerDNS Authoritative Server 4.0.1-264-g50e4ab365 (built Dec 29 2016 09:49:29 by adm@dns.example.com)"

My config includes

cat /usr/local/etc/powerdns/pdns.conf
    ...
    #chroot=/var/pdns
    socket-dir=/var/pdns
    setgid=pdns
    setuid=pdns
    ...

I've set

chmod 0775 /var/pdns
chown pdns:pdns /var/pdns
ls -ld /var/pdns
    drwxrwxr-x 2 pdns pdns 4.0K Dec 29 15:52 /var/pdns/

On exec

rm -f /var/pdns/pdns.controlsocket
systemctl start pdns

it fails. Logs report,

...
Dec 29 15:53:45 dns pdns[12445]: This is a standalone pdns
Dec 29 15:53:45 dns pdns[12445]: Unable to bind to control socket at '/var/pdns/pdns.controlsocket', reason: Permission denied
...

Otoh, if

rm -f /var/pdns/pdns.controlsocket
chmod o+w /var/pdns
ls -ld /var/pdns
    drwxrwxrwx 2 pdns pdns 4.0K Dec 29 15:52 /var/pdns/
systemctl start pdns

it's successful

tail -f /var/log/pdns/pdns.log
    ...
    Dec 29 15:44:24 dns pdns[31649]: Creating backend connection for TCP
    Dec 29 15:44:24 dns pdns[31649]: Master/slave communicator launching
    Dec 29 15:44:24 dns pdns[31649]: No new unfresh slave domains, 0 queued for AXFR already, 0 in progress
    Dec 29 15:44:24 dns pdns[31649]: No master domains need notifications
    Dec 29 15:44:24 dns pdns[31649]: About to create 3 backend threads for UDP
    Dec 29 15:44:24 dns pdns[31649]: Done launching threads, ready to distribute questions
ls -al /var/pdns/
    total 40K
    drwxrwxrwx  2 pdns pdns 4.0K Dec 29 15:44 ./
    drwxr-xr-x 27 root root 4.0K Dec 29 10:13 ../
    srw-rw----  1 root pdns    0 Dec 29 15:44 pdns.controlsocket=
    -rw-------  1 pdns pdns  26K Dec 29 10:14 powerdns.sqlite3

Why are o+w perms required for the socket directory? Shouldn't 'pdns' uid/gid be sufficient?

[08:55] <Habbie> i don't think it's the reason, but can you test while temporarily disabling all protection/security in the systemd unit file?
[08:55] <PGNd> sure ... sec
[09:00] <PGNd> Habbie: Apparently, it's related ... disable all protections in unit file, chmod socket-dir -> 0770, and launch is OK -- chroot'd or not.
[09:00] <Habbie> ok
[09:04] <PGNd> Habbie: It's the 'CapabilityBoundingSet=' line ... disable just THAT and all's OK.  Now , what specifically ...
[09:27] <PGNd> Habbie:  The *addition* of CAP_DAC_OVERRIDE to the CapabilityBoundingSet seems to fix the issue.  cref: similar behavior/solution @ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=847598
[09:29] <PGNd> hm, that works, but isn't ideal: "CAP_DAC_OVERRIDE: Bypass file read, write, and execute permission checks"
[09:37] <rgacogne> if we need cap_dac_override, it means we are trying to access it might be that we try to access it before dropping privileges
[09:37] <rgacogne> whoops
[09:38] <rgacogne> if we need cap_dac_override, it might be that we try to access it before dropping privileges
[09:38] <rgacogne> because root needs cap_dac_override if pdns is the only user allowed to access it
[09:51] <Habbie> ah
[09:56] <PGNd> rgacogne: Even root is subject to the perms check?  Did not realize that ...
[09:58] <rgacogne> root is a normal user with every capability
[09:59] rgacogne raatti rcmc-ronny remorse renchap rendar Respawner Robe Robin roxer ruupert rvdm RyanKnack 
[09:59] <PGNd> rgacogne: Fair enuf!
[10:00] <PGNd> So, sounds like a code change in pdns?  I assume that the ideal solution is NOT to add the CAP_DAC_OVERRIDE ...
[10:01] <rgacogne> well we need to check if that's the correct explanation first :)
[10:01] <PGNd> ah, "it might be ..." .  got it.
[10:13] <rgacogne> so yes
[10:14] <rgacogne> we create the DynListener before dropping privileges
[10:18] <PGNd> rgacogne: aha, so you've convinced yourself
[10:21] <rgacogne> it even looks like we carefully create the socket before dropping privileges by creating the DynListeners, dropping privileges and only then creating the corresponding DynListener threads by calling DynListener::go()
[10:22] <rgacogne> so we probably had a reason at the time
[10:23] <rgacogne> we probably need to think this through before moving the socket creation after privileges have been dropped
[10:35] <PGNd> rgacogne: Any more output needed from me?  Sounds like you see where the issue is ...
[10:37] <rgacogne> if we don't already have one, would you mind opening an issue at https://github.com/PowerDNS/pdns/issues/new so that we don't forget to fix it? I don't think I will be able to work on this before monday
rgacogne commented 7 years ago

We should probably create the unix local sockets after dropping privileges, but we need to keep in mind that the DynListener might be configured to listen on TCP sockets, and obviously these need to be opened before dropping privileges.

zeha commented 7 years ago

Maybe the tcp socket stuff should go away? Is anyone using it?

AdamMajer commented 7 years ago

There seems to be another case for CAP_DAC_OVERRIDE.

situation:

/var/lib/pdns            pdns:pdns 750
/var/lib/pdns/sqlite3.db pdns:pdns 640

during start up it seems pdns tries to open the file as root which fails because of the permissions, internally it tries to open it with dac override capability, which fails as it isn't in the capability set.

Adding CAP_DAC_OVERRIDE fixes the start problems.