File: gdbus-Never-buffer-reads-during-server-authentication.patch

package info (click to toggle)
glib2.0 2.74.6-2%2Bdeb12u7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-proposed-updates
  • size: 61,572 kB
  • sloc: ansic: 489,099; xml: 17,388; python: 7,962; sh: 1,229; perl: 1,144; makefile: 225; cpp: 195
file content (141 lines) | stat: -rw-r--r-- 6,202 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
From: Marius Vollmer <mvollmer@redhat.com>
Date: Mon, 13 Feb 2023 14:12:52 +0200
Subject: gdbus: Never buffer reads during server authentication

Otherwise, the content of the buffer is thrown away when switching
from reading via a GDataInputStream to unbuffered reads when waiting
for the "BEGIN" line.

(The code already tried to protect against over-reading like this by
using unbuffered reads for the last few lines of the auth protocol,
but it might already be too late at that point.  The buffer of the
GDataInputStream might already contain the "BEGIN" line for example.)

This matters when connecting a sd-bus client directly to a GDBus
client.  A sd-bus client optimistically sends the whole auth
conversation in one go without waiting for intermediate replies.  This
is done to improve performance for the many short-lived connections
that are typically made.

Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/2916
Origin: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3300
Applied-upstream: 2.74.7, commit:d982c86078741671949a6800f60d450901497e4e
---
 gio/gdbusauth.c | 50 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index 6710368..b52a06e 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -949,7 +949,6 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
 {
   gboolean ret;
   ServerState state;
-  GDataInputStream *dis;
   GDataOutputStream *dos;
   GError *local_error;
   gchar *line;
@@ -965,7 +964,6 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
   _g_dbus_auth_add_mechs (auth, observer);
 
   ret = FALSE;
-  dis = NULL;
   dos = NULL;
   mech = NULL;
   negotiated_capabilities = 0;
@@ -981,13 +979,18 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
       goto out;
     }
 
-  dis = G_DATA_INPUT_STREAM (g_data_input_stream_new (g_io_stream_get_input_stream (auth->priv->stream)));
+  /* We use an extremely slow (but reliable) line reader for input
+   * instead of something buffered - this basically does a recvfrom()
+   * system call per character
+   *
+   * (the problem with using GDataInputStream's read_line is that
+   * because of buffering it might start reading into the first D-Bus
+   * message that appears after "BEGIN\r\n"....)
+   */
+
   dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream)));
-  g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (dis), FALSE);
   g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (dos), FALSE);
 
-  g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
-
   /* read the NUL-byte, possibly with credentials attached */
 #ifndef G_CREDENTIALS_PREFER_MESSAGE_PASSING
   if (G_IS_SOCKET_CONNECTION (auth->priv->stream))
@@ -1026,11 +1029,22 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
     }
   else
     {
+      gchar c;
+      gssize num_read;
+
       local_error = NULL;
-      (void)g_data_input_stream_read_byte (dis, cancellable, &local_error);
-      if (local_error != NULL)
+      num_read = g_input_stream_read (g_io_stream_get_input_stream (auth->priv->stream),
+                                      &c, 1,
+                                      cancellable, &local_error);
+      if (num_read != 1 || local_error != NULL)
         {
-          g_propagate_error (error, local_error);
+          if (local_error == NULL)
+            g_set_error_literal (error,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_FAILED,
+                                 _ ("Unexpected lack of content trying to read a byte"));
+          else
+            g_propagate_error (error, local_error);
           goto out;
         }
     }
@@ -1058,7 +1072,10 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
         {
         case SERVER_STATE_WAITING_FOR_AUTH:
           debug_print ("SERVER: WaitingForAuth");
-          line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+          line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
+                                                    &line_length,
+                                                    cancellable,
+                                                    error);
           debug_print ("SERVER: WaitingForAuth, read '%s'", line);
           if (line == NULL)
             goto out;
@@ -1276,7 +1293,10 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
 
         case SERVER_STATE_WAITING_FOR_DATA:
           debug_print ("SERVER: WaitingForData");
-          line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+          line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
+                                                    &line_length,
+                                                    cancellable,
+                                                    error);
           debug_print ("SERVER: WaitingForData, read '%s'", line);
           if (line == NULL)
             goto out;
@@ -1315,13 +1335,6 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
 
         case SERVER_STATE_WAITING_FOR_BEGIN:
           debug_print ("SERVER: WaitingForBegin");
-          /* Use extremely slow (but reliable) line reader - this basically
-           * does a recvfrom() system call per character
-           *
-           * (the problem with using GDataInputStream's read_line is that because of
-           * buffering it might start reading into the first D-Bus message that
-           * appears after "BEGIN\r\n"....)
-           */
           line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
                                                     &line_length,
                                                     cancellable,
@@ -1380,7 +1393,6 @@ _g_dbus_auth_run_server (GDBusAuth              *auth,
 
  out:
   g_clear_object (&mech);
-  g_clear_object (&dis);
   g_clear_object (&dos);
   g_clear_object (&own_credentials);