Bug 1216277 - VUL-1: pdnsd: unsafe creation of /var/cache/pdnsd/pdnsd.cache via /usr/bin/install in service file
Summary: VUL-1: pdnsd: unsafe creation of /var/cache/pdnsd/pdnsd.cache via /usr/bin/in...
Status: IN_PROGRESS
Alias: None
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Normal
Target Milestone: ---
Assignee: Security Team bot
QA Contact: Security Team bot
URL: https://smash.suse.de/issue/381968/
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-10-16 10:42 UTC by Matthias Gerstner
Modified: 2024-04-19 10:05 UTC (History)
5 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Gerstner 2023-10-16 10:42:59 UTC
In a recent pdns update in Factory the following systemd service content
changed:

    RPM: pdnsd-1.2.9a-10.10.x86_64.rpm on x86_64
    Package: pdnsd
    Service path: /usr/lib/systemd/system/pdnsd.service
    Runs as: root:root
    Exec lines:
        ExecStartPre=/usr/bin/install -m0644 -o pdns -g pdns /dev/null /var/cache/pdnsd/pdnsd.cache
        ExecStart=/usr/sbin/pdnsd $PDNSD_ARGS
    
    Changes with regard to previous service file:
    
        --- old.service
        +++ new.service
        @@ -3,4 +3,5 @@
         Service path: /usr/lib/systemd/system/pdnsd.service
         Runs as: root:root
         Exec lines:
        -    ExecStart=/usr/sbin/pdnsd
        +    ExecStartPre=/usr/bin/install -m0644 -o pdns -g pdns /dev/null /var/cache/pdnsd/pdnsd.cache
        +    ExecStart=/usr/sbin/pdnsd $PDNSD_ARGS

This new `ExecStartPre=` line is problematic, since /var/cache/pdnsd is owned
by pdns:pdns:

    $ ls -lhd /var/cache/pdnsd
    drwxr-x--- 3 pdns pdns 4.0K Oct 16 12:31 /var/cache/pdnsd

Thus the directory is controlled by the `pdns` user.

The `install` program performs the following system calls on the path.

    openat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", O_RDONLY|O_PATH|O_DIRECTORY) = -1 ENOTDIR (Not a directory)
    newfstatat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", {st_mode=S_IFLNK|0777, st_size=11, ...}, AT_SYMLINK_NOFOLLOW)
    = 0
    unlinkat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", 0) = 0
    openat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4
    fchownat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", 449, 458, AT_SYMLINK_NOFOLLOW) = 0
    fchmodat(AT_FDCWD, "/var/cache/pdnsd/pdnsd.cache", 0644) = 0

Of these calls the `fchmodat()` is still vulnerable to symlink attacks. Since
the directory in question does not have a sticky bit set, there will also be
no kernel level symlink protection. A compromised "pdns" user account can
attempt to win a race condition, deleting the file and replacing it by a
symlink after `fchownat()` happens but before `fchmodat()` happens. Then the
mode of arbitrary files in the system can be changed to mode 0644.

This seems to be an openSUSE specific packaging error, since the service file
is checked into OBS.

To fix this I suggest to add "User=pdns", "Group=pdns" and if necessary run
`pdnsd` still as root by prefixing a "!" (see `man systemd.service`).
Comment 1 Matthias Gerstner 2023-10-16 10:43:42 UTC
I assigned this to the user that introduced the change. pdns as a package does
not seem to have a maintainer assigned currently.
Comment 2 Christian Wittmer 2023-10-17 07:55:44 UTC
Kindly tell me when I did change this because I am not aware of this change.
Especially not in the near past.
Comment 3 Matthias Gerstner 2023-10-17 08:43:47 UTC
(In reply to chris@computersalat.de from comment #2)
> Kindly tell me when I did change this because I am not aware of this change.
> Especially not in the near past.

It seems the change is already a year old but has only now made it actually
into Factory. It is this change entry from openSUSE:Factory/pdnsd:

> -------------------------------------------------------------------
> Thu Sep 15 14:54:23 UTC 2022 - chris@computersalat.de
> 
> - rework patches to be p0
> - add pdnsd_conf.patch
>   * mainly just beautification for better readability
> - add pdnsd.sysconfig file
>   * ability to pass ARGS
> - service files
>   * update pdnsd.service
>   * add pdnsd.service.sle12
> - add user/group pdns
Comment 5 Matthias Gerstner 2023-11-02 09:30:16 UTC
(In reply to Christian Wittmer from comment #2)
> Kindly tell me when I did change this because I am not aware of this change.
> Especially not in the near past.

It seems you've cut yourself off from further bug updates by assigning the bug to me.

Please find the answer to your question in comment 3.
Comment 6 Christian Wittmer 2023-11-02 14:37:10 UTC
OK, I think I get it. I do remember this workaround for making pdnsd start even when there is no cache file.
IMHO sadly the cache file is not created by the daemon on start. If there is no cache file then the daemon fails to start.
Do you have a better idea to create a cache file ? So it does exist on service start ?
Comment 7 Christian Wittmer 2023-11-02 15:44:03 UTC
problem fixed with a systemd tmpfile.
OBS SR created: https://build.opensuse.org/request/show/1122870
Comment 8 Matthias Gerstner 2023-11-03 09:48:28 UTC
Please don't close VUL- bugs on your own. The security team will do it.

The systemd-tmpfiles approach should fix this.

You can also try to approach upstream about this behaviour and ask them to
make the daemon behaviour more robust.

Sadly we don't have a dedicated pdns anymore so no one is properly taking care
of it.
Comment 9 Christian Wittmer 2023-11-03 13:26:46 UTC
(In reply to Matthias Gerstner from comment #8)
> Please don't close VUL- bugs on your own. The security team will do it.
> 
> The systemd-tmpfiles approach should fix this.
> 
> You can also try to approach upstream about this behaviour and ask them to
> make the daemon behaviour more robust.
> 
> Sadly we don't have a dedicated pdns anymore so no one is properly taking
> care
> of it.

sorry, won't do it again.

IMHO there is no upstream anymore ... looks orphaned/dead

I also don't know if it is really being used actively ...
Comment 10 Stefan Seyfried 2023-11-04 10:56:24 UTC
If wanted, I can take ownership of this package as I am using/maintaining a derivative of it in a commercial setting anyway.

I would rework the packaging quite a bit probably, though ;-)
Comment 11 Matthias Gerstner 2023-11-06 09:40:36 UTC
(In reply to seife@novell.slipkontur.de from comment #10)
> If wanted, I can take ownership of this package as I am using/maintaining a derivative of it in a commercial setting anyway.
> 
> I would rework the packaging quite a bit probably, though ;-)

If you feel up to the task then we would be happy of course. Otherwise, since
upstream is also not active anymore, we might need to drop.
Comment 12 Christian Wittmer 2023-11-06 19:27:25 UTC
(In reply to Stefan Seyfried from comment #10)
> If wanted, I can take ownership of this package as I am using/maintaining a
> derivative of it in a commercial setting anyway.
> 
> I would rework the packaging quite a bit probably, though ;-)

Please go ahead
Comment 13 Stefan Seyfried 2023-11-06 19:30:58 UTC
I requested maintainership in request 1123676.

(Even though I technically could just add myself as I am one of the network project maintainers for historical reasons, I don't like such overstepping of processes and self-elevation ;-)

The fix for this issue is on its way to factory as request 1123675
Comment 14 Stefan Seyfried 2023-11-07 17:40:46 UTC
Christian, for me pdnsd starts just fine without this cache file present. It only issues a warning once:
(I have removed the ExecStartPre line from the old in-factory version of the package).

strolchi:~ # rm /var/cache/pdnsd/pdnsd.cache 
strolchi:~ # systemctl start pdnsd.service
strolchi:~ # pdnsd-ctl server 0 up
Opening socket /var/cache/pdnsd/pdnsd.status
Succeeded
strolchi:~ # nslookup heise.de 127.1
Server:         127.1
Address:        127.0.0.1#53

Non-authoritative answer:
Name:   heise.de
Address: 193.99.144.80
Name:   heise.de
Address: 2a02:2e0:3fe:1001:302::

strolchi:~ # systemctl stop pdnsd.service
strolchi:~ # ls -l /var/cache/pdnsd/pdnsd.cache 
-rw------- 1 pdns pdns 91 Nov  7 18:39 /var/cache/pdnsd/pdnsd.cache
strolchi:~ # systemctl status pdnsd.service
○ pdnsd.service - Caching DNS proxy (pdns)
     Loaded: loaded (/usr/lib/systemd/system/pdnsd.service; disabled; preset: disabled)
     Active: inactive (dead)
       Docs: man:pdnsd(8)

Nov 07 18:38:21 strolchi systemd[1]: Stopping Caching DNS proxy (pdns)...
Nov 07 18:38:21 strolchi systemd[1]: pdnsd.service: Deactivated successfully.
Nov 07 18:38:21 strolchi systemd[1]: Stopped Caching DNS proxy (pdns).
Nov 07 18:39:01 strolchi systemd[1]: Started Caching DNS proxy (pdns).
Nov 07 18:39:01 strolchi pdnsd[18037]: * 11/07 18:39:01| pdnsd: info: pdnsd-1.2.9a-par starting.
Nov 07 18:39:01 strolchi pdnsd[18037]: * 11/07 18:39:01| pdnsd: warning: Could not open disk cache file /var/cache/pdnsd/pdnsd.cache:>
Nov 07 18:39:29 strolchi pdnsd[18037]: * 11/07 18:39:29| pdnsd: warning: Caught signal 15. Exiting.
Nov 07 18:39:29 strolchi systemd[1]: Stopping Caching DNS proxy (pdns)...
Nov 07 18:39:29 strolchi systemd[1]: pdnsd.service: Deactivated successfully.
Nov 07 18:39:29 strolchi systemd[1]: Stopped Caching DNS proxy (pdns).

So I think this whole "create the cache file upfront" thing is not needed at all, the message is just cosmetic and just appearing once.
Comment 15 Christian Wittmer 2023-11-07 18:42:06 UTC
Stefan, we had very often failed service start because of this in our test environment.
So my fix was to give the daemon its cache file before start. At that time I wasn't aware of this tmpfiles thing of systemd so I used this ugly ExecStartPre.
I never experienced pdnsd creating the cache file so I don't know if it is good to have a DNS caching service without cache file ...
It is your package. You decide.
Comment 16 Stefan Seyfried 2023-11-08 06:01:28 UTC
I'm obviously interested in a package which just works, so I was thinking about patching the daemon to just create the file instead of erroring out. Until I found that the deamon actually does not error out if the file is missing, it behaves the same as if it has read an empty cache file.
The file is created on the (controlled) shutdown.

Right now I don't see where pdnsd might fail if the file is not present, but I might be overlooking somehting.

Let's go for this "deal": I'll remove the cache file creation thing from the package (after again thoroughly looking at the code for paths where this might cause failure) and if you see failures to start up apparently linked to the missing cache file, we investigate and fix them? I think these startup failure are caused by some other bug which just get papered over if the file is created in advance.
Comment 17 Stefan Seyfried 2023-11-26 11:46:55 UTC
sr#1128893 to factory contains an update which should fix this vulnerability:
* no longer create the cache file from pdnsd.service
* do not ship a tmpfile config creating the cache
Comment 18 OBSbugzilla Bot 2023-11-26 12:15:02 UTC
This is an autogenerated message for OBS integration:
This bug (1216277) was mentioned in
https://build.opensuse.org/request/show/1128893 Factory / pdnsd
Comment 19 Matthias Gerstner 2023-11-27 09:35:13 UTC
Thanks for working on this. We will close the bug when we verified all updates
are available.
Comment 20 Stefan Seyfried 2023-11-28 06:17:54 UTC
Thanks.
And Christian: if you are seeing issues with the pdnsd not starting up when the cache file is missing, please create a bug and let's try to debug this and fix the root cause. Reading the code I cannot see what would make this happen, but I might of course be overlooking something.