]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: reject wall messages containing control characters
authorLuca Boccassi <luca.boccassi@gmail.com>
Mon, 13 Apr 2026 19:26:22 +0000 (20:26 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 14 Apr 2026 16:32:02 +0000 (17:32 +0100)
method_set_wall_message() and the property setter only checked the
message length but not its content. Since wall messages are broadcast
to all TTYs, control characters in the message could interfere with
terminal state. Reject messages containing control characters other
than newline and tab.

Follow-up for 9ef15026c0e7e6600372056c43442c99ec53746e
Follow-up for e2fa5721c3ee5ea400b99a6463e8c1c257e20415

(cherry picked from commit 4bf9db731445ba72a9e5097561e1883dfe1183d8)

src/login/logind-dbus.c

index 14ec1f90ab400577d16e6e613c5b940510788e05..8ffe0cfbc3e3c3d95472e22361ee8fd901f78f72 100644 (file)
@@ -58,6 +58,7 @@
 #include "signal-util.h"
 #include "sleep-config.h"
 #include "stdio-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
@@ -3731,6 +3732,46 @@ static int property_get_boot_loader_entries(
         return sd_bus_message_close_container(reply);
 }
 
+static int wall_message_validate(const char *wall_message, sd_bus_error *error) {
+        if (strlen(wall_message) > WALL_MESSAGE_MAX)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Wall message too long, maximum permitted length is %u characters.",
+                                         WALL_MESSAGE_MAX);
+
+        if (string_has_cc(wall_message, /* ok= */ "\n\t"))
+                return sd_bus_error_set(error,
+                                        SD_BUS_ERROR_INVALID_ARGS,
+                                        "Wall message contains control characters, refusing.");
+
+        return 0;
+}
+
+static int property_set_wall_message(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                void *userdata,
+                sd_bus_error *error) {
+
+        char **p = ASSERT_PTR(userdata);
+        const char *s;
+        int r;
+
+        assert(value);
+
+        r = sd_bus_message_read(value, "s", &s);
+        if (r < 0)
+                return r;
+
+        r = wall_message_validate(s, error);
+        if (r < 0)
+                return r;
+
+        return free_and_strdup_warn(p, empty_to_null(s));
+}
+
 static int method_set_wall_message(
                 sd_bus_message *message,
                 void *userdata,
@@ -3747,10 +3788,9 @@ static int method_set_wall_message(
         if (r < 0)
                 return r;
 
-        if (strlen(wall_message) > WALL_MESSAGE_MAX)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
-                        "Wall message too long, maximum permitted length is %u characters.",
-                        WALL_MESSAGE_MAX);
+        r = wall_message_validate(wall_message, error);
+        if (r < 0)
+                return r;
 
         /* Short-circuit the operation if the desired state is already in place, to
          * avoid an unnecessary polkit permission check. */
@@ -3913,7 +3953,7 @@ static const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
         SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, wall_messages), 0),
-        SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, NULL, offsetof(Manager, wall_message), 0),
+        SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, property_set_wall_message, offsetof(Manager, wall_message), 0),
 
         SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),