]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-varlink: put a limit on queued outgoing messages
authorLennart Poettering <lennart@poettering.net>
Fri, 25 Apr 2025 18:02:27 +0000 (20:02 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 30 Apr 2025 08:34:44 +0000 (10:34 +0200)
This is only a safety net for runaway programs: it puts a limit on
outgoing messages, i.e. not on resources accessible directly from
outside, but only on resources taken by trusted local code.

src/libsystemd/sd-varlink/sd-varlink.c
src/libsystemd/sd-varlink/varlink-internal.h

index 773f70ede8ef9abed930bad668bf005ad3e58a0c..bf38564783ad169f16a69f976160cf44a53a3b6e 100644 (file)
@@ -41,6 +41,7 @@
 #define VARLINK_BUFFER_MAX (16U*1024U*1024U)
 #define VARLINK_READ_SIZE (64U*1024U)
 #define VARLINK_COLLECT_MAX 1024U
+#define VARLINK_QUEUE_MAX (64U*1024U)
 
 static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
         [VARLINK_IDLE_CLIENT]              = "idle-client",
@@ -631,6 +632,7 @@ static void varlink_clear(sd_varlink *v) {
 
         LIST_CLEAR(queue, v->output_queue, varlink_json_queue_item_free);
         v->output_queue_tail = NULL;
+        v->n_output_queue = 0;
 
         v->event = sd_event_unref(v->event);
 
@@ -1946,6 +1948,9 @@ static int varlink_enqueue_json(sd_varlink *v, sd_json_variant *m) {
         if (v->n_pushed_fds == 0 && !v->output_queue)
                 return varlink_format_json(v, m);
 
+        if (v->n_output_queue >= VARLINK_QUEUE_MAX)
+                return -ENOBUFS;
+
         /* Otherwise add a queue entry for this */
         q = varlink_json_queue_item_new(m, v->pushed_fds, v->n_pushed_fds);
         if (!q)
@@ -1955,6 +1960,7 @@ static int varlink_enqueue_json(sd_varlink *v, sd_json_variant *m) {
 
         LIST_INSERT_AFTER(queue, v->output_queue, v->output_queue_tail, q);
         v->output_queue_tail = q;
+        v->n_output_queue++;
         return 0;
 }
 
@@ -1968,6 +1974,9 @@ static int varlink_format_queue(sd_varlink *v) {
 
         while (v->output_queue) {
                 _cleanup_free_ int *array = NULL;
+
+                assert(v->n_output_queue > 0);
+
                 VarlinkJsonQueueItem *q = v->output_queue;
 
                 if (v->n_output_fds > 0) /* unwritten fds? if we'd add more we'd corrupt the fd message boundaries, hence wait */
@@ -1992,6 +2001,7 @@ static int varlink_format_queue(sd_varlink *v) {
                 LIST_REMOVE(queue, v->output_queue, q);
                 if (!v->output_queue)
                         v->output_queue_tail = NULL;
+                v->n_output_queue--;
 
                 varlink_json_queue_item_free(q);
         }
index 377f8cfae4511f7e3e5d9a00fc9912a025c4d049..5ff233f210e785c05c4db1ab9241bea7dd993769 100644 (file)
@@ -142,6 +142,7 @@ struct sd_varlink {
          * with preceding or following messages. */
         LIST_HEAD(VarlinkJsonQueueItem, output_queue);
         VarlinkJsonQueueItem *output_queue_tail;
+        size_t n_output_queue;
 
         /* The fds to associate with the next message that is about to be enqueued. The user first pushes the
          * fds it intends to send via varlink_push_fd() into this queue, and then once the message data is