summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch')
-rw-r--r--meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch520
1 files changed, 520 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch b/meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch
new file mode 100644
index 0000000000..e684ab8755
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch
@@ -0,0 +1,520 @@
1From 0062d795bf29301ae054e1826a7189198a2565c4 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
3Date: Tue, 14 Apr 2020 09:06:53 +0000
4Subject: [PATCH] Merge branch 'polkit-ref-count'
5
6Upsteam-Status: Backport [https://github.com/systemd/systemd/commit/ea0d0ede03c6f18dbc5036c5e9cccf97e415ccc2]
7CVE: CVE-2020-1712
8
9Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
10---
11 TODO | 2 +-
12 man/rules/meson.build | 1 +
13 man/sd_bus_enqueue_for_read.xml | 88 ++++++++++++++++
14 src/libsystemd/libsystemd.sym | 1 +
15 src/libsystemd/sd-bus/sd-bus.c | 24 +++++
16 src/shared/bus-util.c | 179 +++++++++++++++++++++-----------
17 src/systemd/sd-bus.h | 1 +
18 7 files changed, 235 insertions(+), 61 deletions(-)
19 create mode 100644 man/sd_bus_enqueue_for_read.xml
20
21diff --git a/TODO b/TODO
22index c5b5b86057..5c5ea1f568 100644
23--- a/TODO
24+++ b/TODO
25@@ -184,7 +184,7 @@ Features:
26
27 * the a-posteriori stopping of units bound to units that disappeared logic
28 should be reworked: there should be a queue of units, and we should only
29- enqeue stop jobs from a defer event that processes queue instead of
30+ enqueue stop jobs from a defer event that processes queue instead of
31 right-away when we find a unit that is bound to one that doesn't exist
32 anymore. (similar to how the stop-unneeded queue has been reworked the same
33 way)
34diff --git a/man/rules/meson.build b/man/rules/meson.build
35index 3b63311d7b..e80ed98c34 100644
36--- a/man/rules/meson.build
37+++ b/man/rules/meson.build
38@@ -192,6 +192,7 @@ manpages = [
39 'sd_bus_open_user_with_description',
40 'sd_bus_open_with_description'],
41 ''],
42+ ['sd_bus_enqueue_for_read', '3', [], ''],
43 ['sd_bus_error',
44 '3',
45 ['SD_BUS_ERROR_MAKE_CONST',
46diff --git a/man/sd_bus_enqueue_for_read.xml b/man/sd_bus_enqueue_for_read.xml
47new file mode 100644
48index 0000000000..3318a3031b
49--- /dev/null
50+++ b/man/sd_bus_enqueue_for_read.xml
51@@ -0,0 +1,88 @@
52+<?xml version='1.0'?>
53+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
54+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
55+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
56+
57+<refentry id="sd_bus_enqueue_for_read"
58+ xmlns:xi="http://www.w3.org/2001/XInclude">
59+
60+ <refentryinfo>
61+ <title>sd_bus_enqueue_for_read</title>
62+ <productname>systemd</productname>
63+ </refentryinfo>
64+
65+ <refmeta>
66+ <refentrytitle>sd_bus_enqueue_for_read</refentrytitle>
67+ <manvolnum>3</manvolnum>
68+ </refmeta>
69+
70+ <refnamediv>
71+ <refname>sd_bus_enqueue_for_read</refname>
72+
73+ <refpurpose>Re-enqueue a bus message on a bus connection, for reading.</refpurpose>
74+ </refnamediv>
75+
76+ <refsynopsisdiv>
77+ <funcsynopsis>
78+ <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
79+
80+ <funcprototype>
81+ <funcdef>int <function>sd_bus_enqueue_for_read</function></funcdef>
82+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
83+ <paramdef>sd_bus_message *<parameter>message</parameter></paramdef>
84+ </funcprototype>
85+
86+ </funcsynopsis>
87+ </refsynopsisdiv>
88+
89+ <refsect1>
90+ <title>Description</title>
91+
92+ <para><function>sd_bus_enqueue_for_read()</function> may be used to re-enqueue an incoming bus message on
93+ the local read queue, so that it is processed and dispatched locally again, similar to how an incoming
94+ message from the peer is processed. Takes a bus connection object and the message to enqueue. A reference
95+ is taken of the message and the caller's reference thus remains in possession of the caller. The message
96+ is enqueued at the end of the queue, thus will be dispatched after all other already queued messages are
97+ dispatched.</para>
98+
99+ <para>This call is primarily useful for dealing with incoming method calls that may be processed only
100+ after an additional asynchronous operation completes. One example are PolicyKit authorization requests
101+ that are determined to be necessary to authorize a newly incoming method call: when the PolicyKit response
102+ is received the original method call may be re-enqueued to process it again, this time with the
103+ authorization result known.</para>
104+ </refsect1>
105+
106+ <refsect1>
107+ <title>Return Value</title>
108+
109+ <para>On success, this function return 0 or a positive integer. On failure, it returns a negative errno-style
110+ error code.</para>
111+
112+ <refsect2>
113+ <title>Errors</title>
114+
115+ <para>Returned errors may indicate the following problems:</para>
116+
117+ <variablelist>
118+ <varlistentry>
119+ <term><constant>-ECHILD</constant></term>
120+
121+ <listitem><para>The bus connection has been created in a different process.</para></listitem>
122+ </varlistentry>
123+ </variablelist>
124+ </refsect2>
125+ </refsect1>
126+
127+ <xi:include href="libsystemd-pkgconfig.xml" />
128+
129+ <refsect1>
130+ <title>See Also</title>
131+
132+ <para>
133+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
134+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
135+ <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
136+ </para>
137+ </refsect1>
138+
139+</refentry>
140diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
141index 5ec42e0f1f..c40f1b7d1a 100644
142--- a/src/libsystemd/libsystemd.sym
143+++ b/src/libsystemd/libsystemd.sym
144@@ -679,6 +679,7 @@ global:
145
146 LIBSYSTEMD_243 {
147 global:
148+ sd_bus_enqueue_for_read;
149 sd_bus_object_vtable_format;
150 sd_event_source_disable_unref;
151 } LIBSYSTEMD_241;
152diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
153index 026ac8cb94..07bc145f37 100644
154--- a/src/libsystemd/sd-bus/sd-bus.c
155+++ b/src/libsystemd/sd-bus/sd-bus.c
156@@ -4194,3 +4194,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
157
158 return bus->close_on_exit;
159 }
160+
161+_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) {
162+ int r;
163+
164+ assert_return(bus, -EINVAL);
165+ assert_return(bus = bus_resolve(bus), -ENOPKG);
166+ assert_return(m, -EINVAL);
167+ assert_return(m->sealed, -EINVAL);
168+ assert_return(!bus_pid_changed(bus), -ECHILD);
169+
170+ if (!BUS_IS_OPEN(bus->state))
171+ return -ENOTCONN;
172+
173+ /* Re-enqueue a message for reading. This is primarily useful for PolicyKit-style authentication,
174+ * where we accept a message, then determine we need to interactively authenticate the user, and then
175+ * we want to process the message again. */
176+
177+ r = bus_rqueue_make_room(bus);
178+ if (r < 0)
179+ return r;
180+
181+ bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
182+ return 0;
183+}
184diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
185index e9b0b8a99d..88cad9cd0a 100644
186--- a/src/shared/bus-util.c
187+++ b/src/shared/bus-util.c
188@@ -212,6 +212,34 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) {
189 return sender_uid == good_user;
190 }
191
192+#if ENABLE_POLKIT
193+static int bus_message_append_strv_key_value(
194+ sd_bus_message *m,
195+ const char **l) {
196+
197+ const char **k, **v;
198+ int r;
199+
200+ assert(m);
201+
202+ r = sd_bus_message_open_container(m, 'a', "{ss}");
203+ if (r < 0)
204+ return r;
205+
206+ STRV_FOREACH_PAIR(k, v, l) {
207+ r = sd_bus_message_append(m, "{ss}", *k, *v);
208+ if (r < 0)
209+ return r;
210+ }
211+
212+ r = sd_bus_message_close_container(m);
213+ if (r < 0)
214+ return r;
215+
216+ return r;
217+}
218+#endif
219+
220 int bus_test_polkit(
221 sd_bus_message *call,
222 int capability,
223@@ -219,7 +247,7 @@ int bus_test_polkit(
224 const char **details,
225 uid_t good_user,
226 bool *_challenge,
227- sd_bus_error *e) {
228+ sd_bus_error *ret_error) {
229
230 int r;
231
232@@ -242,7 +270,7 @@ int bus_test_polkit(
233 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
234 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
235 int authorized = false, challenge = false;
236- const char *sender, **k, **v;
237+ const char *sender;
238
239 sender = sd_bus_message_get_sender(call);
240 if (!sender)
241@@ -266,17 +294,7 @@ int bus_test_polkit(
242 if (r < 0)
243 return r;
244
245- r = sd_bus_message_open_container(request, 'a', "{ss}");
246- if (r < 0)
247- return r;
248-
249- STRV_FOREACH_PAIR(k, v, details) {
250- r = sd_bus_message_append(request, "{ss}", *k, *v);
251- if (r < 0)
252- return r;
253- }
254-
255- r = sd_bus_message_close_container(request);
256+ r = bus_message_append_strv_key_value(request, details);
257 if (r < 0)
258 return r;
259
260@@ -284,11 +302,11 @@ int bus_test_polkit(
261 if (r < 0)
262 return r;
263
264- r = sd_bus_call(call->bus, request, 0, e, &reply);
265+ r = sd_bus_call(call->bus, request, 0, ret_error, &reply);
266 if (r < 0) {
267 /* Treat no PK available as access denied */
268- if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
269- sd_bus_error_free(e);
270+ if (sd_bus_error_has_name(ret_error, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
271+ sd_bus_error_free(ret_error);
272 return -EACCES;
273 }
274
275@@ -319,15 +337,17 @@ int bus_test_polkit(
276 #if ENABLE_POLKIT
277
278 typedef struct AsyncPolkitQuery {
279+ char *action;
280+ char **details;
281+
282 sd_bus_message *request, *reply;
283- sd_bus_message_handler_t callback;
284- void *userdata;
285 sd_bus_slot *slot;
286+
287 Hashmap *registry;
288+ sd_event_source *defer_event_source;
289 } AsyncPolkitQuery;
290
291 static void async_polkit_query_free(AsyncPolkitQuery *q) {
292-
293 if (!q)
294 return;
295
296@@ -339,9 +359,25 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
297 sd_bus_message_unref(q->request);
298 sd_bus_message_unref(q->reply);
299
300+ free(q->action);
301+ strv_free(q->details);
302+
303+ sd_event_source_disable_unref(q->defer_event_source);
304 free(q);
305 }
306
307+static int async_polkit_defer(sd_event_source *s, void *userdata) {
308+ AsyncPolkitQuery *q = userdata;
309+
310+ assert(s);
311+
312+ /* This is called as idle event source after we processed the async polkit reply, hopefully after the
313+ * method call we re-enqueued has been properly processed. */
314+
315+ async_polkit_query_free(q);
316+ return 0;
317+}
318+
319 static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
320 _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
321 AsyncPolkitQuery *q = userdata;
322@@ -350,21 +386,46 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
323 assert(reply);
324 assert(q);
325
326+ assert(q->slot);
327 q->slot = sd_bus_slot_unref(q->slot);
328+
329+ assert(!q->reply);
330 q->reply = sd_bus_message_ref(reply);
331
332+ /* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the
333+ * whole message processing again, and thus re-validating and re-retrieving the "userdata" field
334+ * again.
335+ *
336+ * We install an idle event loop event to clean-up the PolicyKit request data when we are idle again,
337+ * i.e. after the second time the message is processed is complete. */
338+
339+ assert(!q->defer_event_source);
340+ r = sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)), &q->defer_event_source, async_polkit_defer, q);
341+ if (r < 0)
342+ goto fail;
343+
344+ r = sd_event_source_set_priority(q->defer_event_source, SD_EVENT_PRIORITY_IDLE);
345+ if (r < 0)
346+ goto fail;
347+
348+ r = sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_ONESHOT);
349+ if (r < 0)
350+ goto fail;
351+
352 r = sd_bus_message_rewind(q->request, true);
353- if (r < 0) {
354- r = sd_bus_reply_method_errno(q->request, r, NULL);
355- goto finish;
356- }
357+ if (r < 0)
358+ goto fail;
359
360- r = q->callback(q->request, q->userdata, &error_buffer);
361- r = bus_maybe_reply_error(q->request, r, &error_buffer);
362+ r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q->request), q->request);
363+ if (r < 0)
364+ goto fail;
365
366-finish:
367- async_polkit_query_free(q);
368+ return 1;
369
370+fail:
371+ log_debug_errno(r, "Processing asynchronous PolicyKit reply failed, ignoring: %m");
372+ (void) sd_bus_reply_method_errno(q->request, r, NULL);
373+ async_polkit_query_free(q);
374 return r;
375 }
376
377@@ -378,16 +439,14 @@ int bus_verify_polkit_async(
378 bool interactive,
379 uid_t good_user,
380 Hashmap **registry,
381- sd_bus_error *error) {
382+ sd_bus_error *ret_error) {
383
384 #if ENABLE_POLKIT
385 _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
386 AsyncPolkitQuery *q;
387- const char *sender, **k, **v;
388- sd_bus_message_handler_t callback;
389- void *userdata;
390 int c;
391 #endif
392+ const char *sender;
393 int r;
394
395 assert(call);
396@@ -403,11 +462,17 @@ int bus_verify_polkit_async(
397 if (q) {
398 int authorized, challenge;
399
400- /* This is the second invocation of this function, and
401- * there's already a response from polkit, let's
402- * process it */
403+ /* This is the second invocation of this function, and there's already a response from
404+ * polkit, let's process it */
405 assert(q->reply);
406
407+ /* If the operation we want to authenticate changed between the first and the second time,
408+ * let's not use this authentication, it might be out of date as the object and context we
409+ * operate on might have changed. */
410+ if (!streq(q->action, action) ||
411+ !strv_equal(q->details, (char**) details))
412+ return -ESTALE;
413+
414 if (sd_bus_message_is_method_error(q->reply, NULL)) {
415 const sd_bus_error *e;
416
417@@ -418,7 +483,7 @@ int bus_verify_polkit_async(
418 return -EACCES;
419
420 /* Copy error from polkit reply */
421- sd_bus_error_copy(error, e);
422+ sd_bus_error_copy(ret_error, e);
423 return -sd_bus_error_get_errno(e);
424 }
425
426@@ -433,7 +498,7 @@ int bus_verify_polkit_async(
427 return 1;
428
429 if (challenge)
430- return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
431+ return sd_bus_error_set(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
432
433 return -EACCES;
434 }
435@@ -445,20 +510,12 @@ int bus_verify_polkit_async(
436 else if (r > 0)
437 return 1;
438
439-#if ENABLE_POLKIT
440- if (sd_bus_get_current_message(call->bus) != call)
441- return -EINVAL;
442-
443- callback = sd_bus_get_current_handler(call->bus);
444- if (!callback)
445- return -EINVAL;
446-
447- userdata = sd_bus_get_current_userdata(call->bus);
448
449 sender = sd_bus_message_get_sender(call);
450 if (!sender)
451 return -EBADMSG;
452
453+#if ENABLE_POLKIT
454 c = sd_bus_message_get_allow_interactive_authorization(call);
455 if (c < 0)
456 return c;
457@@ -487,17 +544,7 @@ int bus_verify_polkit_async(
458 if (r < 0)
459 return r;
460
461- r = sd_bus_message_open_container(pk, 'a', "{ss}");
462- if (r < 0)
463- return r;
464-
465- STRV_FOREACH_PAIR(k, v, details) {
466- r = sd_bus_message_append(pk, "{ss}", *k, *v);
467- if (r < 0)
468- return r;
469- }
470-
471- r = sd_bus_message_close_container(pk);
472+ r = bus_message_append_strv_key_value(pk, details);
473 if (r < 0)
474 return r;
475
476@@ -505,13 +552,25 @@ int bus_verify_polkit_async(
477 if (r < 0)
478 return r;
479
480- q = new0(AsyncPolkitQuery, 1);
481+ q = new(AsyncPolkitQuery, 1);
482 if (!q)
483 return -ENOMEM;
484
485- q->request = sd_bus_message_ref(call);
486- q->callback = callback;
487- q->userdata = userdata;
488+ *q = (AsyncPolkitQuery) {
489+ .request = sd_bus_message_ref(call),
490+ };
491+
492+ q->action = strdup(action);
493+ if (!q->action) {
494+ async_polkit_query_free(q);
495+ return -ENOMEM;
496+ }
497+
498+ q->details = strv_copy((char**) details);
499+ if (!q->details) {
500+ async_polkit_query_free(q);
501+ return -ENOMEM;
502+ }
503
504 r = hashmap_put(*registry, call, q);
505 if (r < 0) {
506diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
507index 84ceb62dc7..0e5c761f83 100644
508--- a/src/systemd/sd-bus.h
509+++ b/src/systemd/sd-bus.h
510@@ -201,6 +201,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
511 int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
512 int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
513 int sd_bus_flush(sd_bus *bus);
514+int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m);
515
516 sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
517 sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
518--
5192.23.0
520