Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package clamav for openSUSE:Factory checked 
in at 2025-07-06 17:07:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/clamav (Old)
 and      /work/SRC/openSUSE:Factory/.clamav.new.1903 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "clamav"

Sun Jul  6 17:07:59 2025 rev:135 rq:1290236 version:1.4.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/clamav/clamav.changes    2025-06-20 
16:54:27.856813241 +0200
+++ /work/SRC/openSUSE:Factory/.clamav.new.1903/clamav.changes  2025-07-06 
17:10:46.934086719 +0200
@@ -1,0 +2,6 @@
+Mon Jun 30 16:13:30 UTC 2025 - Reinhard Max <m...@suse.com>
+
+- bsc#1240363, clamav-disable-administrative-commands.patch: clamd:
+  Add an option to toggle SHUTDOWN, RELOAD, STATS and VERSION.
+
+-------------------------------------------------------------------

New:
----
  clamav-disable-administrative-commands.patch

----------(New B)----------
  New:
- bsc#1240363, clamav-disable-administrative-commands.patch: clamd:
  Add an option to toggle SHUTDOWN, RELOAD, STATS and VERSION.
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ clamav.spec ++++++
--- /var/tmp/diff_new_pack.CWe8MA/_old  2025-07-06 17:10:48.634157065 +0200
+++ /var/tmp/diff_new_pack.CWe8MA/_new  2025-07-06 17:10:48.634157065 +0200
@@ -53,6 +53,7 @@
 Source65:       system-user-vscan.conf
 Patch1:         clamav-conf.patch
 Patch2:         clamav-freshclam_test.patch
+Patch3:         clamav-disable-administrative-commands.patch
 Patch5:         clamav-obsolete-config.patch
 Patch12:        clamav-fips.patch
 Patch14:        clamav-document-maxsize.patch
@@ -184,6 +185,7 @@
 %setup -q
 %patch -P 1
 %patch -P 2
+%patch -P 3
 %patch -P 5
 %patch -P 12
 %patch -P 14


++++++ clamav-disable-administrative-commands.patch ++++++
>From a3be0d2d452023e367f3a5425f88179c732a50cd Mon Sep 17 00:00:00 2001
From: ChaoticByte <j...@keemail.me>
Date: Wed, 4 Jun 2025 16:47:57 +0200
Subject: [PATCH] clamd: Add options to toggle SHUTDOWN, RELOAD, STATS and
 VERSION (#1502)

The `clamd` protocol lacks authentication or authorization controls
needed to limit access to more administrative commands.
Depending on your use case, disabling some commands like `SHUTDOWN`
may improve the security of the scanning daemon.

This commit adds options to enable/disable the `SHUTDOWN`, `RELOAD`,
`STATS` and `VERSION` commands in `clamd.conf`.
When a client sends one of the following commands but it is disabled,
`clamd` will respond with "COMMAND UNAVAILABLE".

The new `clamd.conf` options are:

- `EnableShutdownCommand`: Enable the `SHUTDOWN` command.
  Setting this to no prevents a client to stop `clamd` via the
  protocol.
  Default: yes

- `EnableReloadCommand` Enable the `RELOAD` command.
  Setting this to no prevents a client to reload the database.
  This disables Freshclam's `NotifyClamd` option.
  `clamd` monitors for database directory changes, so this should
  Default: yes

- `EnableStatsCommand` Enable the `STATS` command.
  Setting this to no prevents a client from querying statistics.
  This disables the `clamdtop` program.
  Default: yes

- `EnableVersionCommand` Enable the `VERSION` command.
  Setting this to no prevents a client from querying version
  information.
  This disables the `clamdtop` program and will cause `clamdscan` to
  display a warning when using the `--version` option.
  Default: yes

Resolves: https://github.com/Cisco-Talos/clamav/issues/922
Resolves: https://github.com/Cisco-Talos/clamav/issues/1169
Related: https://github.com/Cisco-Talos/clamav/pull/347
---
 clamd/session.c                       | 47 +++++++++++++++++++--------
 clamdscan/client.c                    |  9 +++++
 clamdtop/clamdtop.c                   | 32 ++++++++++++++++--
 common/optparser.c                    |  8 +++++
 docs/man/clamd.conf.5.in              | 28 ++++++++++++++++
 etc/clamd.conf.sample                 | 25 ++++++++++++++
 freshclam/notify.c                    | 11 +++++++
 win32/conf_examples/clamd.conf.sample | 25 ++++++++++++++
 8 files changed, 169 insertions(+), 16 deletions(-)

--- clamd/session.c.orig
+++ clamd/session.c
@@ -551,17 +551,24 @@ int execute_or_dispatch_command(client_c
 
     switch (cmd) {
         case COMMAND_SHUTDOWN:
-            pthread_mutex_lock(&exit_mutex);
-            progexit = 1;
-            pthread_mutex_unlock(&exit_mutex);
+            if (optget(conn->opts, "EnableShutdownCommand")->enabled) {
+                pthread_mutex_lock(&exit_mutex);
+                progexit = 1;
+                pthread_mutex_unlock(&exit_mutex);
+            } else {
+                conn_reply_single(conn, NULL, "COMMAND UNAVAILABLE");
+            }
             return 1;
         case COMMAND_RELOAD:
-            pthread_mutex_lock(&reload_mutex);
-            reload = 1;
-            pthread_mutex_unlock(&reload_mutex);
-            mdprintf(desc, "RELOADING%c", term);
-            /* we set reload flag, and we'll reload before closing the
-             * connection */
+            if (optget(conn->opts, "EnableReloadCommand")->enabled) {
+                pthread_mutex_lock(&reload_mutex);
+                reload = 1;
+                pthread_mutex_unlock(&reload_mutex);
+                mdprintf(desc, "RELOADING%c", term);
+                /* we set reload flag, and we'll reload before closing the 
connection */
+            } else {
+                conn_reply_single(conn, NULL, "COMMAND UNAVAILABLE");
+            }
             return 1;
         case COMMAND_PING:
             if (conn->group)
@@ -570,10 +577,15 @@ int execute_or_dispatch_command(client_c
                 mdprintf(desc, "PONG%c", term);
             return conn->group ? 0 : 1;
         case COMMAND_VERSION: {
-            if (conn->group)
-                mdprintf(desc, "%u: ", conn->id);
-            print_ver(desc, conn->term, engine);
-            return conn->group ? 0 : 1;
+            if (optget(conn->opts, "EnableVersionCommand")->enabled) {
+                if (conn->group)
+                    mdprintf(desc, "%u: ", conn->id);
+                print_ver(desc, conn->term, engine);
+                return conn->group ? 0 : 1;
+            } else {
+                conn_reply_single(conn, NULL, "COMMAND UNAVAILABLE");
+                return 1;
+            }
         }
         case COMMAND_COMMANDS: {
             if (conn->group)
@@ -598,9 +610,16 @@ int execute_or_dispatch_command(client_c
             conn->mode  = MODE_STREAM;
             return 0;
         }
+        case COMMAND_STATS: {
+            if (optget(conn->opts, "EnableStatsCommand")->enabled) {
+                return dispatch_command(conn, cmd, argument);
+            } else {
+                conn_reply_single(conn, NULL, "COMMAND UNAVAILABLE");
+                return 1;
+            }
+        }
         case COMMAND_MULTISCAN:
         case COMMAND_CONTSCAN:
-        case COMMAND_STATS:
         case COMMAND_FILDES:
         case COMMAND_SCAN:
         case COMMAND_INSTREAMSCAN:
--- clamdscan/client.c.orig
+++ clamdscan/client.c
@@ -357,6 +357,15 @@ int get_clamd_version(const struct optst
             logg(LOGG_ERROR, "Error occurred while receiving version 
information.\n");
             break;
         }
+
+        /* Check if the response was "COMMAND UNAVAILABLE", which means that
+           clamd has the VERSION command disabled. */
+        if (len >= 19 && memcmp(buff, "COMMAND UNAVAILABLE", 19) == 0) {
+            logg(LOGG_WARNING, "VERSION command disabled in clamd, printing 
the local version.\n");
+            closesocket(sockd);
+            return 2;
+        }
+
         printf("%s\n", buff);
     }
 
--- clamdtop/clamdtop.c.orig
+++ clamdtop/clamdtop.c
@@ -110,6 +110,7 @@ static void cleanup(void);
 static int send_string_noreconn(conn_t *conn, const char *cmd);
 static void send_string(conn_t *conn, const char *cmd);
 static int read_version(conn_t *conn);
+static int check_stats_available(conn_t *conn);
 char *get_ip(const char *ip);
 char *get_port(const char *ip);
 char *make_ip(const char *host, const char *port);
@@ -790,6 +791,7 @@ done:
 static int make_connection(const char *soname, conn_t *conn)
 {
     int rc;
+    int rv;
 
     if (!soname) {
         return -1;
@@ -801,8 +803,20 @@ static int make_connection(const char *s
     send_string(conn, "nIDSESSION\nnVERSION\n");
     free(conn->version);
     conn->version = NULL;
-    if (!read_version(conn))
-        return 0;
+
+    rv = read_version(conn);
+    if (rv == -3) {
+        print_con_info(conn, "VERSION command unavailable, consider enabling 
it in the clamd configuration.\n");
+        EXIT_PROGRAM(FAIL_INITIAL_CONN);
+    } else if (!rv) {
+        // check if STATS command is available
+        if (check_stats_available(conn)) {
+            return 0;
+        } else {
+            print_con_info(conn, "STATS command unavailable, consider enabling 
it in the clamd configuration.\n");
+            EXIT_PROGRAM(FAIL_INITIAL_CONN);
+        }
+    }
 
     /* clamd < 0.95 */
     if ((rc = make_connection_real(soname, conn)))
@@ -1328,6 +1342,9 @@ static int read_version(conn_t *conn)
         return -1;
     if (!strcmp(buf, "UNKNOWN COMMAND\n"))
         return -2;
+    // check if VERSION command is available
+    if (!strcmp(strchr(buf, ':'), ": COMMAND UNAVAILABLE\n"))
+        return -3;
 
     conn->version = strdup(buf);
     OOM_CHECK(conn->version);
@@ -1337,6 +1354,17 @@ static int read_version(conn_t *conn)
     return 0;
 }
 
+static int check_stats_available(conn_t *conn)
+{
+    char buf[1024];
+    send_string(conn, "nSTATS\n");
+    if (!recv_line(conn, buf, sizeof(buf)))
+        return 0;
+    if (!strcmp(strchr(buf, ':'), ": COMMAND UNAVAILABLE\n"))
+        return 0;
+    return 1;
+}
+
 static void sigint(int a)
 {
     UNUSEDPARAM(a);
--- common/optparser.c.orig
+++ common/optparser.c
@@ -296,6 +296,14 @@ const struct clam_option __clam_options[
 
     {"TCPSocket", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, 0, 
OPT_CLAMD, "A TCP port number the daemon will listen on.", "3310"},
 
+    {"EnableShutdownCommand", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 
0, OPT_CLAMD, "Enables the SHUTDOWN command for clamd", "no"},
+
+    {"EnableReloadCommand", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, 
OPT_CLAMD, "Enables the RELOAD command for clamd", "no"},
+
+    {"EnableVersionCommand", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, 
OPT_CLAMD, "Enables the VERSION command for clamd", "yes"},
+
+    {"EnableStatsCommand", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, 
OPT_CLAMD, "Enables the STATS command for clamd", "yes"},
+
     /* FIXME: add a regex for IP addr */
     {"TCPAddr", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, 
OPT_CLAMD, "By default clamd binds to INADDR_ANY.\nThis option allows you to 
restrict the TCP address and provide\nsome degree of protection from the 
outside world.", "localhost"},
 
--- docs/man/clamd.conf.5.in.orig
+++ docs/man/clamd.conf.5.in
@@ -139,6 +139,34 @@ This option allows you to restrict the T
 .br
 Default: disabled
 .TP
+\fBEnableShutdownCommand BOOL\fR
+Enables the SHUTDOWN command. Setting this to no prevents a client to stop 
clamd via the protocol.
+.br
+When disabled, clamd responds to this command with COMMAND UNAVAILABLE.
+.br
+Default: yes
+.TP
+\fBEnableReloadCommand BOOL\fR
+Enables the RELOAD command. Setting this to no prevents a client to reload the 
database.
+.br
+When disabled, clamd responds to this command with COMMAND UNAVAILABLE.
+.br
+Default: yes
+.TP
+\fBEnableVersionCommand BOOL\fR
+Enables the VERSION command. Setting this to no prevents a client from 
querying version information.
+.br
+When disabled, clamd responds to this command with COMMAND UNAVAILABLE.
+.br
+Default: yes
+.TP
+\fBEnableStatsCommand BOOL\fR
+Enables the STATS command. Setting this to no prevents a client from querying 
statistics.
+.br
+When disabled, clamd responds to this command with COMMAND UNAVAILABLE.
+.br
+Default: yes
+.TP
 \fBMaxConnectionQueueLength NUMBER\fR
 Maximum length the queue of pending connections may grow to.
 .br
--- etc/clamd.conf.sample.orig
+++ etc/clamd.conf.sample
@@ -121,6 +121,31 @@ LocalSocket /run/clamav/clamd.sock
 # Default: no
 #TCPAddr localhost
 
+# Enable or disable certain commands.
+# Disabling some commands like SHUTDOWN may improve the security of the daemon.
+# When a client sends one of the following commands but it is disabled,
+# clamd responds with COMMAND UNAVAILABLE.
+#
+# Enable the SHUTDOWN command.
+# Setting this to no prevents a client to stop clamd via the protocol.
+# Default: yes
+#EnableShutdownCommand no
+#
+# Enable the RELOAD command
+# Setting this to no prevents a client to reload the database.
+# Default: yes
+#EnableReloadCommand no
+#
+# Enable the STATS command
+# Setting this to no prevents a client from querying statistics.
+# Default: yes
+#EnableStatsCommand no
+#
+# Enable the VERSION command
+# Setting this to no prevents a client from querying version information.
+# Default: yes
+#EnableVersionCommand no
+
 # Maximum length the queue of pending connections may grow to.
 # Default: 200
 #MaxConnectionQueueLength 30
--- freshclam/notify.c.orig
+++ freshclam/notify.c
@@ -62,6 +62,11 @@ int clamd_connect(const char *cfgfile, c
         return -11;
     }
 
+    if (!optget(opts, "EnableReloadCommand")->enabled) {
+        logg(LOGG_WARNING, "Clamd was NOT notified: The RELOAD command is 
disabled. Consider enabling it in the clamd configuration!\n");
+        return -1;
+    }
+
 #ifndef _WIN32
     if ((opt = optget(opts, "LocalSocket"))->enabled) {
         memset(&server, 0x00, sizeof(server));
@@ -163,6 +168,12 @@ int notify(const char *cfgfile)
 
     memset(buff, 0, sizeof(buff));
     if ((bread = recv(sockd, buff, sizeof(buff), 0)) > 0) {
+        if (strstr(buff, "COMMAND UNAVAILABLE")) {
+            // this will only happen when the running clamd instance has 
EnableReloadCommand set to no,
+            // but the config on disk differs (e.g. after a config change 
without clamd restart)
+            logg(LOGG_ERROR, "NotifyClamd: RELOAD command unavailable, 
consider enabling it in the clamd configuration and restarting clamd.\n");
+            return -1;
+        }
         if (!strstr(buff, "RELOADING")) {
             logg(LOGG_ERROR, "NotifyClamd: Unknown answer from clamd: '%s'\n", 
buff);
             closesocket(sockd);
--- win32/conf_examples/clamd.conf.sample.orig
+++ win32/conf_examples/clamd.conf.sample
@@ -97,6 +97,31 @@ TCPSocket 3310
 # Default: no
 TCPAddr localhost
 
+# Enable or disable certain commands.
+# Disabling some commands like SHUTDOWN may improve the security of the daemon.
+# When a client sends one of the following commands but it is disabled,
+# clamd responds with COMMAND UNAVAILABLE.
+#
+# Enable the SHUTDOWN command.
+# Setting this to no prevents a client to stop clamd via the protocol.
+# Default: yes
+#EnableShutdownCommand no
+#
+# Enable the RELOAD command
+# Setting this to no prevents a client to reload the database.
+# Default: yes
+#EnableReloadCommand no
+#
+# Enable the STATS command
+# Setting this to no prevents a client from querying statistics.
+# Default: yes
+#EnableStatsCommand no
+#
+# Enable the VERSION command
+# Setting this to no prevents a client from querying version information.
+# Default: yes
+#EnableVersionCommand no
+
 # Maximum length the queue of pending connections may grow to.
 # Default: 200
 #MaxConnectionQueueLength 30

Reply via email to