any local user can shut clamd down via control socket

Bug #1930393 reported by Stephane Chazelas
260
This bug affects 1 person
Affects Status Importance Assigned to Milestone
ClamAV
Unknown
Unknown
clamav (Debian)
Confirmed
Unknown
clamav (Ubuntu)
Triaged
Medium
Unassigned

Bug Description

As the control socket is world read+writeable:

$ namei -l /run/clamav/clamd.ctl
f: /run/clamav/clamd.ctl
drwxr-xr-x root root /
drwxr-xr-x root root run
drwxr-xr-x clamav root clamav
srw-rw-rw- clamav clamav clamd.ctl

(and needs to be for users to be able to pass files to scan)

and clamd doesn't seem to be doing any access control itself either, any local user can shutdown clamd by sending the SHUTDOWN (aka QUIT) command there:

$ printf 'zSHUTDOWN\0' | socat - unix-connect:/run/clamav/clamd.ctl

For instance. Which makes it a DoS vulnerability.

Other commands such as RELOAD (clamdscan --reload) or STATS may also need to be restricted.

That's with clamav-daemon 0.103.2+dfsg-0ubuntu0.20.04.2 on Ubuntu 20.04, but I'd expect it would affect other versions of Ubuntu and other OSes than Ubuntu, and should probably be addressed upstreams by clamd checking the credentials of the incoming connection.

Revision history for this message
Seth Arnold (seth-arnold) wrote :

Hello Stephane, thanks for the report. I get the impression reading /usr/share/doc/clamav-daemon/README.Debian.gz that the software isn't generally expected to be useful without configuration. You can use the debconf interactive configuration tool with:

dpkg-reconfigure clamav-daemon

Which will prompt for user, group, and permissions to set on the socket among many other things. Different sites may need to allow different services to connect to the daemon via Unix sockets or via TCP sockets etc.

I believe this is "working as intended" even if it does strike me as silly for the 'please scan this file' socket to be the same as the 'please shut down' socket. (I'm even a bit surprised about that, since signals can do this job just fine, no matter how icky they are..)

I think we should open the bug report up to allow others to suggest the best way to use clamav in different environments.

Thanks

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

Hi Seth, thanks for getting back on this.

On the contrary, clamd works out of the box as a service to scan files on demand, with the README explaining the rationale behind how the default configuration is written.

AFAICT there's nothing in the README.Debian or dpkg-reconfigure prompts that suggest there's a risk in leaving the socket publicly available as long as clamd is running as an unprivileged user.

Restricting access to that socket means restricting access to the service. We wouldn't tell users to restrict access to apache2 or mysqld sockets for instance on the ground that there's no other way to preserve their integrity.

The only mention of restricting access to the socket in the README is for when clamav is configured to run as root which it is not by default (I even doubt the claim in that errata that it may be needed in that case as the client can get clamd to scan any file they have read access to by passing it a fd they have opened to it (or the contents of the file over the socket. fdpass or stream)).

Even if we can imagine deployment scenarios where clamd is only used by postfix or ftpd to scan incoming emails/files, granting the "postfix" or "ftp" user (which themselves should also have minimum privileges) permission to shutdown clamd would make little sense.

Here no question is asked upon installing clamav-daemon (even when reconfiguring debconf with "Ignore questions with a priority less than: low"), and clamd is enabled and started straight away.

If the aim was for clamd to be configured by the user before it could be used safely, then I'd expect either the server not being enabled/started upon install or configured with a safer default (socket only available to clamav group for instance), and at least some form of debconf interaction upon install to point users in the right direction.

I see clamav-daemon is listed as a dependency for e2guardian or clamsmtp, I've not tested those, but from their description, it seems plausible that they also come with a default configuration and unlikely that they would instruct users to go and reconfigure clamd from its unsafe default.

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

To clarify: I acknowledge and confirm that the first debconf dialog does tell you indeed that it won't work automatically out of the box. But in effect it does.

$ clamdscan --fdpass eicar.com
/tmp/eicar.com: Win.Test.EICAR_HDB-1 FOUND

----------- SCAN SUMMARY -----------
Infected files: 1
Time: 0.005 sec (0 m 0 s)
Start Date: 2021:06:04 11:21:37
End Date: 2021:06:04 11:21:37

After fresh install and reboot on a fresh 20.04 server VM here. And since those dialogs are not shown upon install, it makes it difficult for users to know they're there (there's a catch 22 in that you need to run dpkg-reconfigure to be told you need to run dpkg-reconfigure).

Even then, accepting the defaults in dpkg-reconfigure does leave clamd vulnerable.

See also https://github.com/extremeshok/clamav-unofficial-sigs/blob/master/guides/ubuntu-debian.md
instructions for installing and using clamav-unofficial-sigs on Ubuntu (there is an outdated package by the same name in the Ubuntu repos) which tells you how to install clamav, but doesn't mention running dpkg-reconfigure clamav-daemon, let alone fixing the permissions of the socket.

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

Also note that amavisd-new, often used in conjunction with postfix and clamav-daemon for spam+malware email filtering like in amavisd-new-postfix (Description: part of Ubuntu mail stack provided by Ubuntu server team) in its default configuration runs as the "amavis" user and "amavis" group.

If, to mitigate this vulnerability we reconfigure clamav-daemon for the socket to have

rw-rw---- clamav clamav

permissions.

Then amavisd-new can no longer connect to clamd via the socket. Adding amavis to the clamav group doesn't work as amavisd-new doesn't set supplementation gids. So, you're left with either reconfiguring amavis so it runs with clamav primary gid instead of amavis or change the group of the clamav socket to amavis (which means that if you need other services to be able to use clamd services, you need to add them to that group and by consequence give them access to some amavis data which they don't need otherwise).

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

Another problem is that the systemd service definition (on 20.04) defaults to "Type=simple", so clamav-daemon.service appears as active even though it's not ready to accept connections yet.

That can be fixed with:

--- /lib/systemd/system/clamav-daemon.service 2021-06-04 15:05:34.272466670 +0100
+++ /etc/systemd/system/clamav-daemon.service 2021-06-04 15:05:36.072489235 +0100
@@ -6,11 +6,11 @@
 ConditionPathExistsGlob=/var/lib/clamav/daily.{c[vl]d,inc}

 [Service]
-ExecStart=/usr/sbin/clamd --foreground=true
+Type=forking
+ExecStart=/usr/sbin/clamd
 # Reload the database
 ExecReload=/bin/kill -USR2 $MAINPID
-StandardOutput=syslog
-TimeoutStartSec=420
+TimeoutStartSec=7min

 [Install]
 WantedBy=multi-user.target

after which I can add a:

--- /dev/null 2021-06-04 15:21:19.232000000 +0100
+++ /etc/systemd/system/clamav-daemon.service.d/amavis.conf 2021-06-04 15:19:37.335686866 +0100
@@ -0,0 +1,10 @@
+[Unit]
+Before=amavis.service
+
+[Service]
+# clamd allows its clients to shut it down! So access to /run/clamav/clamd.ctl
+# is restricted to a strict minimum. That's only members of the clamav group.
+# The amavis process can only be in one group. It also doesn't need access to
+# any of clamav's private resources. So we're only granting it access to the
+# socket.
+ExecStartPost=/usr/bin/setfacl -m u:amavis:rw /run/clamav/clamd.ctl

(needs the "acl" package).

To grant access to the socket to amavis.

Changed in clamav (Ubuntu):
status: New → Confirmed
information type: Private Security → Public Security
Revision history for this message
Seth Arnold (seth-arnold) wrote :

Hmm, I thought the only 'reliable' way of addressing the 'not yet active' problem was to use the sd_notify(3) family of functions to let systemd know when a service is actually ready to handle requests. I suggest proposing your patch in a Debian bug to get the maintainer's feedback on it. (A test case to demonstrate why you're proposing the change would probably help.)

As for the socket accepting both user commands and administrative commands, I think that will require a discussion with the upstreams of the various projects. It's wild to me that those things are co-mingled into one socket, but perhaps that's intentional for good reasons.

Thanks

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

From systemd.service(5):

> Type=
> Configures the process start-up type for this service unit.
> One of simple, exec, forking, oneshot, dbus, notify or
> idle:
>
> • If set to simple (the default if ExecStart= is
> specified but neither Type= nor BusName= are), the
> service manager will consider the unit started
> immediately after the main service process has been
> forked off.
[...]
> • If set to forking, it is expected that the process
> configured with ExecStart= will call fork() as part of
> its start-up. The parent process is expected to exit
> when start-up is complete and all communication
> channels are set up. The child continues to run as the
> main service process, and the service manager will
> consider the unit started when the parent process
> exits. This is the behavior of traditional UNIX
> services. If this setting is used, it is recommended to
> also use the PIDFile= option, so that systemd can
> reliably identify the main process of the service.
> systemd will proceed with starting follow-up units as
> soon as the parent process exits.

So as long as the parent doesn't exit before the service is ready to accept connections, it should be reliable.

It seems to be the case here. Note that clamd can take quite a long time to start (hence the 7 minute timeout which btw I don't think makes sense with type=simple and --foreground), which might be why type=forking was abandoned?

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

> I suggest proposing your patch in a Debian bug to get the maintainer's feedback on it.

I've now raised https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989549

Should we carry on discussion over there?

Changed in clamav:
status: Unknown → New
Revision history for this message
Simon Déziel (sdeziel) wrote :

Hello Stephane, maybe joining the amavisd-new user's to the clamav group would be a simpler way around the stricter socket permissions you are proposing?

Revision history for this message
Stephane Chazelas (stephane-chazelas+lp) wrote :

> Hello Stephane, maybe joining the amavisd-new user's to the clamav group would be a simpler way around the stricter socket permissions you are proposing?

Hi Simon,

No, as I said in comment #4, that doesn't work as amavisd-new doesn't set supplementary IDs, just does a setuid() and setgid() with the configured user and group. Also we don't want to give it access to all of clamav's restricted resources (mailbox, logs...), only the socket (which we'd only restrict here to mitigate this vulnerability).

Revision history for this message
Bryce Harrington (bryce) wrote :

Thanks for filing the bug in debian, and I agree that's the right place to continue discussions. You also mentioned in the original bug some aspects (such as auth on incoming connections) should be addressed upstream, so you may want to also file bug reports there.

From that, if there come to be solutions in the form of backportable patches, definitely mention them on this bug report and we can consider SRUing them to focal's clamav if appropriate. (My guess is that any new auth functionality will be implemented as a new feature, and as such may not be suitable for SRU, but am setting Importance to Medium in hopes there'll be at least some backportable elements.)

Looking forward to seeing how the upstream discussions proceed, thanks again!

Changed in clamav (Ubuntu):
importance: Undecided → Medium
status: Confirmed → Triaged
Changed in clamav:
status: New → Confirmed
Revision history for this message
Sergio Durigan Junior (sergiodj) wrote :

The bug has been forwarded upstream, so I'm marking it as such.

Changed in clamav:
status: Confirmed → Unknown
Changed in clamav (Debian):
status: Unknown → Confirmed
Revision history for this message
Paride Legovini (paride) wrote :

No real movement happened upstream or in Debian. I'm not sure we should consider this Triaged, as strictly speaking this is not even a bug (as Seth noted in comment 1), and there's nothing we can actually do to make the situation better. Even upstream doesn't have clear plans or suggestions.

I'm leaving it Triaged for now, let's see what we think at the next "stale bugs triage" round :-)

Revision history for this message
Lucas Kanashiro (lucaskanashiro) wrote :

Still no updates in the upstream bug.

To post a comment you must log in.
This report contains Public Security information  
Everyone can see this security related information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.