All of lore.kernel.org
 help / color / mirror / Atom feed
* [OE-core][zeus][PATCH] systemd: Fix CVE-2020-1712
@ 2020-04-28  8:36 wenlin.kang
  2020-04-29  4:47 ` Anuj Mittal
  0 siblings, 1 reply; 3+ messages in thread
From: wenlin.kang @ 2020-04-28  8:36 UTC (permalink / raw)
  To: openembedded-core

Fix CVE-2020-1712

Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
---
 .../0001-Merge-branch-polkit-ref-count.patch  | 520 ++++++++++++++++++
 meta/recipes-core/systemd/systemd_243.2.bb    |   1 +
 2 files changed, 521 insertions(+)
 create mode 100644 meta/recipes-core/systemd/systemd/0001-Merge-branch-polkit-ref-count.patch

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 @@
+From 0062d795bf29301ae054e1826a7189198a2565c4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Tue, 14 Apr 2020 09:06:53 +0000
+Subject: [PATCH] Merge branch 'polkit-ref-count'
+
+Upsteam-Status: Backport [https://github.com/systemd/systemd/commit/ea0d0ede03c6f18dbc5036c5e9cccf97e415ccc2]
+CVE: CVE-2020-1712
+
+Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
+---
+ TODO                            |   2 +-
+ man/rules/meson.build           |   1 +
+ man/sd_bus_enqueue_for_read.xml |  88 ++++++++++++++++
+ src/libsystemd/libsystemd.sym   |   1 +
+ src/libsystemd/sd-bus/sd-bus.c  |  24 +++++
+ src/shared/bus-util.c           | 179 +++++++++++++++++++++-----------
+ src/systemd/sd-bus.h            |   1 +
+ 7 files changed, 235 insertions(+), 61 deletions(-)
+ create mode 100644 man/sd_bus_enqueue_for_read.xml
+
+diff --git a/TODO b/TODO
+index c5b5b86057..5c5ea1f568 100644
+--- a/TODO
++++ b/TODO
+@@ -184,7 +184,7 @@ Features:
+ 
+ * the a-posteriori stopping of units bound to units that disappeared logic
+   should be reworked: there should be a queue of units, and we should only
+-  enqeue stop jobs from a defer event that processes queue instead of
++  enqueue stop jobs from a defer event that processes queue instead of
+   right-away when we find a unit that is bound to one that doesn't exist
+   anymore. (similar to how the stop-unneeded queue has been reworked the same
+   way)
+diff --git a/man/rules/meson.build b/man/rules/meson.build
+index 3b63311d7b..e80ed98c34 100644
+--- a/man/rules/meson.build
++++ b/man/rules/meson.build
+@@ -192,6 +192,7 @@ manpages = [
+    'sd_bus_open_user_with_description',
+    'sd_bus_open_with_description'],
+   ''],
++ ['sd_bus_enqueue_for_read', '3', [], ''],
+  ['sd_bus_error',
+   '3',
+   ['SD_BUS_ERROR_MAKE_CONST',
+diff --git a/man/sd_bus_enqueue_for_read.xml b/man/sd_bus_enqueue_for_read.xml
+new file mode 100644
+index 0000000000..3318a3031b
+--- /dev/null
++++ b/man/sd_bus_enqueue_for_read.xml
+@@ -0,0 +1,88 @@
++<?xml version='1.0'?>
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
++  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++<!-- SPDX-License-Identifier: LGPL-2.1+ -->
++
++<refentry id="sd_bus_enqueue_for_read"
++          xmlns:xi="http://www.w3.org/2001/XInclude">
++
++  <refentryinfo>
++    <title>sd_bus_enqueue_for_read</title>
++    <productname>systemd</productname>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle>sd_bus_enqueue_for_read</refentrytitle>
++    <manvolnum>3</manvolnum>
++  </refmeta>
++
++  <refnamediv>
++    <refname>sd_bus_enqueue_for_read</refname>
++
++    <refpurpose>Re-enqueue a bus message on a bus connection, for reading.</refpurpose>
++  </refnamediv>
++
++  <refsynopsisdiv>
++    <funcsynopsis>
++      <funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
++
++      <funcprototype>
++        <funcdef>int <function>sd_bus_enqueue_for_read</function></funcdef>
++        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
++        <paramdef>sd_bus_message *<parameter>message</parameter></paramdef>
++      </funcprototype>
++
++    </funcsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>Description</title>
++
++    <para><function>sd_bus_enqueue_for_read()</function> may be used to re-enqueue an incoming bus message on
++    the local read queue, so that it is processed and dispatched locally again, similar to how an incoming
++    message from the peer is processed. Takes a bus connection object and the message to enqueue. A reference
++    is taken of the message and the caller's reference thus remains in possession of the caller. The message
++    is enqueued at the end of the queue, thus will be dispatched after all other already queued messages are
++    dispatched.</para>
++
++    <para>This call is primarily useful for dealing with incoming method calls that may be processed only
++    after an additional asynchronous operation completes. One example are PolicyKit authorization requests
++    that are determined to be necessary to authorize a newly incoming method call: when the PolicyKit response
++    is received the original method call may be re-enqueued to process it again, this time with the
++    authorization result known.</para>
++  </refsect1>
++
++  <refsect1>
++    <title>Return Value</title>
++
++    <para>On success, this function return 0 or a positive integer. On failure, it returns a negative errno-style
++    error code.</para>
++
++    <refsect2>
++      <title>Errors</title>
++
++      <para>Returned errors may indicate the following problems:</para>
++
++      <variablelist>
++        <varlistentry>
++          <term><constant>-ECHILD</constant></term>
++
++          <listitem><para>The bus connection has been created in a different process.</para></listitem>
++        </varlistentry>
++      </variablelist>
++    </refsect2>
++  </refsect1>
++
++  <xi:include href="libsystemd-pkgconfig.xml" />
++
++  <refsect1>
++    <title>See Also</title>
++
++    <para>
++      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
++      <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
++    </para>
++  </refsect1>
++
++</refentry>
+diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
+index 5ec42e0f1f..c40f1b7d1a 100644
+--- a/src/libsystemd/libsystemd.sym
++++ b/src/libsystemd/libsystemd.sym
+@@ -679,6 +679,7 @@ global:
+ 
+ LIBSYSTEMD_243 {
+ global:
++        sd_bus_enqueue_for_read;
+         sd_bus_object_vtable_format;
+         sd_event_source_disable_unref;
+ } LIBSYSTEMD_241;
+diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
+index 026ac8cb94..07bc145f37 100644
+--- a/src/libsystemd/sd-bus/sd-bus.c
++++ b/src/libsystemd/sd-bus/sd-bus.c
+@@ -4194,3 +4194,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus *bus) {
+ 
+         return bus->close_on_exit;
+ }
++
++_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) {
++        int r;
++
++        assert_return(bus, -EINVAL);
++        assert_return(bus = bus_resolve(bus), -ENOPKG);
++        assert_return(m, -EINVAL);
++        assert_return(m->sealed, -EINVAL);
++        assert_return(!bus_pid_changed(bus), -ECHILD);
++
++        if (!BUS_IS_OPEN(bus->state))
++                return -ENOTCONN;
++
++        /* Re-enqueue a message for reading. This is primarily useful for PolicyKit-style authentication,
++         * where we accept a message, then determine we need to interactively authenticate the user, and then
++         * we want to process the message again. */
++
++        r = bus_rqueue_make_room(bus);
++        if (r < 0)
++                return r;
++
++        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
++        return 0;
++}
+diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
+index e9b0b8a99d..88cad9cd0a 100644
+--- a/src/shared/bus-util.c
++++ b/src/shared/bus-util.c
+@@ -212,6 +212,34 @@ static int check_good_user(sd_bus_message *m, uid_t good_user) {
+         return sender_uid == good_user;
+ }
+ 
++#if ENABLE_POLKIT
++static int bus_message_append_strv_key_value(
++                sd_bus_message *m,
++                const char **l) {
++
++        const char **k, **v;
++        int r;
++
++        assert(m);
++
++        r = sd_bus_message_open_container(m, 'a', "{ss}");
++        if (r < 0)
++                return r;
++
++        STRV_FOREACH_PAIR(k, v, l) {
++                r = sd_bus_message_append(m, "{ss}", *k, *v);
++                if (r < 0)
++                        return r;
++        }
++
++        r = sd_bus_message_close_container(m);
++        if (r < 0)
++                return r;
++
++        return r;
++}
++#endif
++
+ int bus_test_polkit(
+                 sd_bus_message *call,
+                 int capability,
+@@ -219,7 +247,7 @@ int bus_test_polkit(
+                 const char **details,
+                 uid_t good_user,
+                 bool *_challenge,
+-                sd_bus_error *e) {
++                sd_bus_error *ret_error) {
+ 
+         int r;
+ 
+@@ -242,7 +270,7 @@ int bus_test_polkit(
+                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
+                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                 int authorized = false, challenge = false;
+-                const char *sender, **k, **v;
++                const char *sender;
+ 
+                 sender = sd_bus_message_get_sender(call);
+                 if (!sender)
+@@ -266,17 +294,7 @@ int bus_test_polkit(
+                 if (r < 0)
+                         return r;
+ 
+-                r = sd_bus_message_open_container(request, 'a', "{ss}");
+-                if (r < 0)
+-                        return r;
+-
+-                STRV_FOREACH_PAIR(k, v, details) {
+-                        r = sd_bus_message_append(request, "{ss}", *k, *v);
+-                        if (r < 0)
+-                                return r;
+-                }
+-
+-                r = sd_bus_message_close_container(request);
++                r = bus_message_append_strv_key_value(request, details);
+                 if (r < 0)
+                         return r;
+ 
+@@ -284,11 +302,11 @@ int bus_test_polkit(
+                 if (r < 0)
+                         return r;
+ 
+-                r = sd_bus_call(call->bus, request, 0, e, &reply);
++                r = sd_bus_call(call->bus, request, 0, ret_error, &reply);
+                 if (r < 0) {
+                         /* Treat no PK available as access denied */
+-                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
+-                                sd_bus_error_free(e);
++                        if (sd_bus_error_has_name(ret_error, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
++                                sd_bus_error_free(ret_error);
+                                 return -EACCES;
+                         }
+ 
+@@ -319,15 +337,17 @@ int bus_test_polkit(
+ #if ENABLE_POLKIT
+ 
+ typedef struct AsyncPolkitQuery {
++        char *action;
++        char **details;
++
+         sd_bus_message *request, *reply;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+         sd_bus_slot *slot;
++
+         Hashmap *registry;
++        sd_event_source *defer_event_source;
+ } AsyncPolkitQuery;
+ 
+ static void async_polkit_query_free(AsyncPolkitQuery *q) {
+-
+         if (!q)
+                 return;
+ 
+@@ -339,9 +359,25 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
+         sd_bus_message_unref(q->request);
+         sd_bus_message_unref(q->reply);
+ 
++        free(q->action);
++        strv_free(q->details);
++
++        sd_event_source_disable_unref(q->defer_event_source);
+         free(q);
+ }
+ 
++static int async_polkit_defer(sd_event_source *s, void *userdata) {
++        AsyncPolkitQuery *q = userdata;
++
++        assert(s);
++
++        /* This is called as idle event source after we processed the async polkit reply, hopefully after the
++         * method call we re-enqueued has been properly processed. */
++
++        async_polkit_query_free(q);
++        return 0;
++}
++
+ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+         AsyncPolkitQuery *q = userdata;
+@@ -350,21 +386,46 @@ static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
+         assert(reply);
+         assert(q);
+ 
++        assert(q->slot);
+         q->slot = sd_bus_slot_unref(q->slot);
++
++        assert(!q->reply);
+         q->reply = sd_bus_message_ref(reply);
+ 
++        /* Now, let's dispatch the original message a second time be re-enqueing. This will then traverse the
++         * whole message processing again, and thus re-validating and re-retrieving the "userdata" field
++         * again.
++         *
++         * We install an idle event loop event to clean-up the PolicyKit request data when we are idle again,
++         * i.e. after the second time the message is processed is complete. */
++
++        assert(!q->defer_event_source);
++        r = sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)), &q->defer_event_source, async_polkit_defer, q);
++        if (r < 0)
++                goto fail;
++
++        r = sd_event_source_set_priority(q->defer_event_source, SD_EVENT_PRIORITY_IDLE);
++        if (r < 0)
++                goto fail;
++
++        r = sd_event_source_set_enabled(q->defer_event_source, SD_EVENT_ONESHOT);
++        if (r < 0)
++                goto fail;
++
+         r = sd_bus_message_rewind(q->request, true);
+-        if (r < 0) {
+-                r = sd_bus_reply_method_errno(q->request, r, NULL);
+-                goto finish;
+-        }
++        if (r < 0)
++                goto fail;
+ 
+-        r = q->callback(q->request, q->userdata, &error_buffer);
+-        r = bus_maybe_reply_error(q->request, r, &error_buffer);
++        r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q->request), q->request);
++        if (r < 0)
++                goto fail;
+ 
+-finish:
+-        async_polkit_query_free(q);
++        return 1;
+ 
++fail:
++        log_debug_errno(r, "Processing asynchronous PolicyKit reply failed, ignoring: %m");
++        (void) sd_bus_reply_method_errno(q->request, r, NULL);
++        async_polkit_query_free(q);
+         return r;
+ }
+ 
+@@ -378,16 +439,14 @@ int bus_verify_polkit_async(
+                 bool interactive,
+                 uid_t good_user,
+                 Hashmap **registry,
+-                sd_bus_error *error) {
++                sd_bus_error *ret_error) {
+ 
+ #if ENABLE_POLKIT
+         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
+         AsyncPolkitQuery *q;
+-        const char *sender, **k, **v;
+-        sd_bus_message_handler_t callback;
+-        void *userdata;
+         int c;
+ #endif
++        const char *sender;
+         int r;
+ 
+         assert(call);
+@@ -403,11 +462,17 @@ int bus_verify_polkit_async(
+         if (q) {
+                 int authorized, challenge;
+ 
+-                /* This is the second invocation of this function, and
+-                 * there's already a response from polkit, let's
+-                 * process it */
++                /* This is the second invocation of this function, and there's already a response from
++                 * polkit, let's process it */
+                 assert(q->reply);
+ 
++                /* If the operation we want to authenticate changed between the first and the second time,
++                 * let's not use this authentication, it might be out of date as the object and context we
++                 * operate on might have changed. */
++                if (!streq(q->action, action) ||
++                    !strv_equal(q->details, (char**) details))
++                        return -ESTALE;
++
+                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
+                         const sd_bus_error *e;
+ 
+@@ -418,7 +483,7 @@ int bus_verify_polkit_async(
+                                 return -EACCES;
+ 
+                         /* Copy error from polkit reply */
+-                        sd_bus_error_copy(error, e);
++                        sd_bus_error_copy(ret_error, e);
+                         return -sd_bus_error_get_errno(e);
+                 }
+ 
+@@ -433,7 +498,7 @@ int bus_verify_polkit_async(
+                         return 1;
+ 
+                 if (challenge)
+-                        return sd_bus_error_set(error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
++                        return sd_bus_error_set(ret_error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive authentication required.");
+ 
+                 return -EACCES;
+         }
+@@ -445,20 +510,12 @@ int bus_verify_polkit_async(
+         else if (r > 0)
+                 return 1;
+ 
+-#if ENABLE_POLKIT
+-        if (sd_bus_get_current_message(call->bus) != call)
+-                return -EINVAL;
+-
+-        callback = sd_bus_get_current_handler(call->bus);
+-        if (!callback)
+-                return -EINVAL;
+-
+-        userdata = sd_bus_get_current_userdata(call->bus);
+ 
+         sender = sd_bus_message_get_sender(call);
+         if (!sender)
+                 return -EBADMSG;
+ 
++#if ENABLE_POLKIT
+         c = sd_bus_message_get_allow_interactive_authorization(call);
+         if (c < 0)
+                 return c;
+@@ -487,17 +544,7 @@ int bus_verify_polkit_async(
+         if (r < 0)
+                 return r;
+ 
+-        r = sd_bus_message_open_container(pk, 'a', "{ss}");
+-        if (r < 0)
+-                return r;
+-
+-        STRV_FOREACH_PAIR(k, v, details) {
+-                r = sd_bus_message_append(pk, "{ss}", *k, *v);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        r = sd_bus_message_close_container(pk);
++        r = bus_message_append_strv_key_value(pk, details);
+         if (r < 0)
+                 return r;
+ 
+@@ -505,13 +552,25 @@ int bus_verify_polkit_async(
+         if (r < 0)
+                 return r;
+ 
+-        q = new0(AsyncPolkitQuery, 1);
++        q = new(AsyncPolkitQuery, 1);
+         if (!q)
+                 return -ENOMEM;
+ 
+-        q->request = sd_bus_message_ref(call);
+-        q->callback = callback;
+-        q->userdata = userdata;
++        *q = (AsyncPolkitQuery) {
++                .request = sd_bus_message_ref(call),
++        };
++
++        q->action = strdup(action);
++        if (!q->action) {
++                async_polkit_query_free(q);
++                return -ENOMEM;
++        }
++
++        q->details = strv_copy((char**) details);
++        if (!q->details) {
++                async_polkit_query_free(q);
++                return -ENOMEM;
++        }
+ 
+         r = hashmap_put(*registry, call, q);
+         if (r < 0) {
+diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
+index 84ceb62dc7..0e5c761f83 100644
+--- a/src/systemd/sd-bus.h
++++ b/src/systemd/sd-bus.h
+@@ -201,6 +201,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
+ int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
+ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
+ int sd_bus_flush(sd_bus *bus);
++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m);
+ 
+ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
+ sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
+-- 
+2.23.0
+
diff --git a/meta/recipes-core/systemd/systemd_243.2.bb b/meta/recipes-core/systemd/systemd_243.2.bb
index 6e7f95693b..082eb4c384 100644
--- a/meta/recipes-core/systemd/systemd_243.2.bb
+++ b/meta/recipes-core/systemd/systemd_243.2.bb
@@ -24,6 +24,7 @@ SRC_URI += "file://touchscreen.rules \
            file://0005-rules-watch-metadata-changes-in-ide-devices.patch \
            file://0001-unit-file.c-consider-symlink-on-filesystems-like-NFS.patch \
            file://99-default.preset \
+           file://0001-Merge-branch-polkit-ref-count.patch \
            "
 
 # patches needed by musl
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [OE-core][zeus][PATCH] systemd: Fix CVE-2020-1712
  2020-04-28  8:36 [OE-core][zeus][PATCH] systemd: Fix CVE-2020-1712 wenlin.kang
@ 2020-04-29  4:47 ` Anuj Mittal
  2020-04-29 15:15   ` Richard Purdie
  0 siblings, 1 reply; 3+ messages in thread
From: Anuj Mittal @ 2020-04-29  4:47 UTC (permalink / raw)
  To: openembedded-core, wenlin.kang

I wonder if it'd be better to upgrade to latest stable release for v243
instead which has this fix.

Does the stable branch policy allow that in case of systemd?

Thanks,

Anuj

On Tue, 2020-04-28 at 01:36 -0700, wenlin.kang@windriver.com wrote:
> Fix CVE-2020-1712
> 
> Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
> ---
>  .../0001-Merge-branch-polkit-ref-count.patch  | 520
> ++++++++++++++++++
>  meta/recipes-core/systemd/systemd_243.2.bb    |   1 +
>  2 files changed, 521 insertions(+)
>  create mode 100644 meta/recipes-core/systemd/systemd/0001-Merge-
> branch-polkit-ref-count.patch
> 
> 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 @@
> +From 0062d795bf29301ae054e1826a7189198a2565c4 Mon Sep 17 00:00:00
> 2001
> +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <
> zbyszek@in.waw.pl>
> +Date: Tue, 14 Apr 2020 09:06:53 +0000
> +Subject: [PATCH] Merge branch 'polkit-ref-count'
> +
> +Upsteam-Status: Backport [
> https://github.com/systemd/systemd/commit/ea0d0ede03c6f18dbc5036c5e9cccf97e415ccc2
> ]
> +CVE: CVE-2020-1712
> +
> +Signed-off-by: Wenlin Kang <wenlin.kang@windriver.com>
> +---
> + TODO                            |   2 +-
> + man/rules/meson.build           |   1 +
> + man/sd_bus_enqueue_for_read.xml |  88 ++++++++++++++++
> + src/libsystemd/libsystemd.sym   |   1 +
> + src/libsystemd/sd-bus/sd-bus.c  |  24 +++++
> + src/shared/bus-util.c           | 179 +++++++++++++++++++++------
> -----
> + src/systemd/sd-bus.h            |   1 +
> + 7 files changed, 235 insertions(+), 61 deletions(-)
> + create mode 100644 man/sd_bus_enqueue_for_read.xml
> +
> +diff --git a/TODO b/TODO
> +index c5b5b86057..5c5ea1f568 100644
> +--- a/TODO
> ++++ b/TODO
> +@@ -184,7 +184,7 @@ Features:
> + 
> + * the a-posteriori stopping of units bound to units that
> disappeared logic
> +   should be reworked: there should be a queue of units, and we
> should only
> +-  enqeue stop jobs from a defer event that processes queue instead
> of
> ++  enqueue stop jobs from a defer event that processes queue instead
> of
> +   right-away when we find a unit that is bound to one that doesn't
> exist
> +   anymore. (similar to how the stop-unneeded queue has been
> reworked the same
> +   way)
> +diff --git a/man/rules/meson.build b/man/rules/meson.build
> +index 3b63311d7b..e80ed98c34 100644
> +--- a/man/rules/meson.build
> ++++ b/man/rules/meson.build
> +@@ -192,6 +192,7 @@ manpages = [
> +    'sd_bus_open_user_with_description',
> +    'sd_bus_open_with_description'],
> +   ''],
> ++ ['sd_bus_enqueue_for_read', '3', [], ''],
> +  ['sd_bus_error',
> +   '3',
> +   ['SD_BUS_ERROR_MAKE_CONST',
> +diff --git a/man/sd_bus_enqueue_for_read.xml
> b/man/sd_bus_enqueue_for_read.xml
> +new file mode 100644
> +index 0000000000..3318a3031b
> +--- /dev/null
> ++++ b/man/sd_bus_enqueue_for_read.xml
> +@@ -0,0 +1,88 @@
> ++<?xml version='1.0'?>
> ++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
> ++  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
> ++<!-- SPDX-License-Identifier: LGPL-2.1+ -->
> ++
> ++<refentry id="sd_bus_enqueue_for_read"
> ++          xmlns:xi="http://www.w3.org/2001/XInclude">
> ++
> ++  <refentryinfo>
> ++    <title>sd_bus_enqueue_for_read</title>
> ++    <productname>systemd</productname>
> ++  </refentryinfo>
> ++
> ++  <refmeta>
> ++    <refentrytitle>sd_bus_enqueue_for_read</refentrytitle>
> ++    <manvolnum>3</manvolnum>
> ++  </refmeta>
> ++
> ++  <refnamediv>
> ++    <refname>sd_bus_enqueue_for_read</refname>
> ++
> ++    <refpurpose>Re-enqueue a bus message on a bus connection, for
> reading.</refpurpose>
> ++  </refnamediv>
> ++
> ++  <refsynopsisdiv>
> ++    <funcsynopsis>
> ++      <funcsynopsisinfo>#include &lt;systemd/sd-
> bus.h&gt;</funcsynopsisinfo>
> ++
> ++      <funcprototype>
> ++        <funcdef>int
> <function>sd_bus_enqueue_for_read</function></funcdef>
> ++        <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
> ++        <paramdef>sd_bus_message
> *<parameter>message</parameter></paramdef>
> ++      </funcprototype>
> ++
> ++    </funcsynopsis>
> ++  </refsynopsisdiv>
> ++
> ++  <refsect1>
> ++    <title>Description</title>
> ++
> ++    <para><function>sd_bus_enqueue_for_read()</function> may be
> used to re-enqueue an incoming bus message on
> ++    the local read queue, so that it is processed and dispatched
> locally again, similar to how an incoming
> ++    message from the peer is processed. Takes a bus connection
> object and the message to enqueue. A reference
> ++    is taken of the message and the caller's reference thus remains
> in possession of the caller. The message
> ++    is enqueued at the end of the queue, thus will be dispatched
> after all other already queued messages are
> ++    dispatched.</para>
> ++
> ++    <para>This call is primarily useful for dealing with incoming
> method calls that may be processed only
> ++    after an additional asynchronous operation completes. One
> example are PolicyKit authorization requests
> ++    that are determined to be necessary to authorize a newly
> incoming method call: when the PolicyKit response
> ++    is received the original method call may be re-enqueued to
> process it again, this time with the
> ++    authorization result known.</para>
> ++  </refsect1>
> ++
> ++  <refsect1>
> ++    <title>Return Value</title>
> ++
> ++    <para>On success, this function return 0 or a positive integer.
> On failure, it returns a negative errno-style
> ++    error code.</para>
> ++
> ++    <refsect2>
> ++      <title>Errors</title>
> ++
> ++      <para>Returned errors may indicate the following
> problems:</para>
> ++
> ++      <variablelist>
> ++        <varlistentry>
> ++          <term><constant>-ECHILD</constant></term>
> ++
> ++          <listitem><para>The bus connection has been created in a
> different process.</para></listitem>
> ++        </varlistentry>
> ++      </variablelist>
> ++    </refsect2>
> ++  </refsect1>
> ++
> ++  <xi:include href="libsystemd-pkgconfig.xml" />
> ++
> ++  <refsect1>
> ++    <title>See Also</title>
> ++
> ++    <para>
> ++      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnu
> m>1</manvolnum></citerefentry>,
> ++      <citerefentry><refentrytitle>sd-
> bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
> ++      <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manv
> olnum>3</manvolnum></citerefentry>,
> ++    </para>
> ++  </refsect1>
> ++
> ++</refentry>
> +diff --git a/src/libsystemd/libsystemd.sym
> b/src/libsystemd/libsystemd.sym
> +index 5ec42e0f1f..c40f1b7d1a 100644
> +--- a/src/libsystemd/libsystemd.sym
> ++++ b/src/libsystemd/libsystemd.sym
> +@@ -679,6 +679,7 @@ global:
> + 
> + LIBSYSTEMD_243 {
> + global:
> ++        sd_bus_enqueue_for_read;
> +         sd_bus_object_vtable_format;
> +         sd_event_source_disable_unref;
> + } LIBSYSTEMD_241;
> +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-
> bus/sd-bus.c
> +index 026ac8cb94..07bc145f37 100644
> +--- a/src/libsystemd/sd-bus/sd-bus.c
> ++++ b/src/libsystemd/sd-bus/sd-bus.c
> +@@ -4194,3 +4194,27 @@ _public_ int sd_bus_get_close_on_exit(sd_bus
> *bus) {
> + 
> +         return bus->close_on_exit;
> + }
> ++
> ++_public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message
> *m) {
> ++        int r;
> ++
> ++        assert_return(bus, -EINVAL);
> ++        assert_return(bus = bus_resolve(bus), -ENOPKG);
> ++        assert_return(m, -EINVAL);
> ++        assert_return(m->sealed, -EINVAL);
> ++        assert_return(!bus_pid_changed(bus), -ECHILD);
> ++
> ++        if (!BUS_IS_OPEN(bus->state))
> ++                return -ENOTCONN;
> ++
> ++        /* Re-enqueue a message for reading. This is primarily
> useful for PolicyKit-style authentication,
> ++         * where we accept a message, then determine we need to
> interactively authenticate the user, and then
> ++         * we want to process the message again. */
> ++
> ++        r = bus_rqueue_make_room(bus);
> ++        if (r < 0)
> ++                return r;
> ++
> ++        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m,
> bus);
> ++        return 0;
> ++}
> +diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
> +index e9b0b8a99d..88cad9cd0a 100644
> +--- a/src/shared/bus-util.c
> ++++ b/src/shared/bus-util.c
> +@@ -212,6 +212,34 @@ static int check_good_user(sd_bus_message *m,
> uid_t good_user) {
> +         return sender_uid == good_user;
> + }
> + 
> ++#if ENABLE_POLKIT
> ++static int bus_message_append_strv_key_value(
> ++                sd_bus_message *m,
> ++                const char **l) {
> ++
> ++        const char **k, **v;
> ++        int r;
> ++
> ++        assert(m);
> ++
> ++        r = sd_bus_message_open_container(m, 'a', "{ss}");
> ++        if (r < 0)
> ++                return r;
> ++
> ++        STRV_FOREACH_PAIR(k, v, l) {
> ++                r = sd_bus_message_append(m, "{ss}", *k, *v);
> ++                if (r < 0)
> ++                        return r;
> ++        }
> ++
> ++        r = sd_bus_message_close_container(m);
> ++        if (r < 0)
> ++                return r;
> ++
> ++        return r;
> ++}
> ++#endif
> ++
> + int bus_test_polkit(
> +                 sd_bus_message *call,
> +                 int capability,
> +@@ -219,7 +247,7 @@ int bus_test_polkit(
> +                 const char **details,
> +                 uid_t good_user,
> +                 bool *_challenge,
> +-                sd_bus_error *e) {
> ++                sd_bus_error *ret_error) {
> + 
> +         int r;
> + 
> +@@ -242,7 +270,7 @@ int bus_test_polkit(
> +                 _cleanup_(sd_bus_message_unrefp) sd_bus_message
> *request = NULL;
> +                 _cleanup_(sd_bus_message_unrefp) sd_bus_message
> *reply = NULL;
> +                 int authorized = false, challenge = false;
> +-                const char *sender, **k, **v;
> ++                const char *sender;
> + 
> +                 sender = sd_bus_message_get_sender(call);
> +                 if (!sender)
> +@@ -266,17 +294,7 @@ int bus_test_polkit(
> +                 if (r < 0)
> +                         return r;
> + 
> +-                r = sd_bus_message_open_container(request, 'a',
> "{ss}");
> +-                if (r < 0)
> +-                        return r;
> +-
> +-                STRV_FOREACH_PAIR(k, v, details) {
> +-                        r = sd_bus_message_append(request, "{ss}",
> *k, *v);
> +-                        if (r < 0)
> +-                                return r;
> +-                }
> +-
> +-                r = sd_bus_message_close_container(request);
> ++                r = bus_message_append_strv_key_value(request,
> details);
> +                 if (r < 0)
> +                         return r;
> + 
> +@@ -284,11 +302,11 @@ int bus_test_polkit(
> +                 if (r < 0)
> +                         return r;
> + 
> +-                r = sd_bus_call(call->bus, request, 0, e, &reply);
> ++                r = sd_bus_call(call->bus, request, 0, ret_error,
> &reply);
> +                 if (r < 0) {
> +                         /* Treat no PK available as access denied
> */
> +-                        if (sd_bus_error_has_name(e,
> SD_BUS_ERROR_SERVICE_UNKNOWN)) {
> +-                                sd_bus_error_free(e);
> ++                        if (sd_bus_error_has_name(ret_error,
> SD_BUS_ERROR_SERVICE_UNKNOWN)) {
> ++                                sd_bus_error_free(ret_error);
> +                                 return -EACCES;
> +                         }
> + 
> +@@ -319,15 +337,17 @@ int bus_test_polkit(
> + #if ENABLE_POLKIT
> + 
> + typedef struct AsyncPolkitQuery {
> ++        char *action;
> ++        char **details;
> ++
> +         sd_bus_message *request, *reply;
> +-        sd_bus_message_handler_t callback;
> +-        void *userdata;
> +         sd_bus_slot *slot;
> ++
> +         Hashmap *registry;
> ++        sd_event_source *defer_event_source;
> + } AsyncPolkitQuery;
> + 
> + static void async_polkit_query_free(AsyncPolkitQuery *q) {
> +-
> +         if (!q)
> +                 return;
> + 
> +@@ -339,9 +359,25 @@ static void
> async_polkit_query_free(AsyncPolkitQuery *q) {
> +         sd_bus_message_unref(q->request);
> +         sd_bus_message_unref(q->reply);
> + 
> ++        free(q->action);
> ++        strv_free(q->details);
> ++
> ++        sd_event_source_disable_unref(q->defer_event_source);
> +         free(q);
> + }
> + 
> ++static int async_polkit_defer(sd_event_source *s, void *userdata) {
> ++        AsyncPolkitQuery *q = userdata;
> ++
> ++        assert(s);
> ++
> ++        /* This is called as idle event source after we processed
> the async polkit reply, hopefully after the
> ++         * method call we re-enqueued has been properly processed.
> */
> ++
> ++        async_polkit_query_free(q);
> ++        return 0;
> ++}
> ++
> + static int async_polkit_callback(sd_bus_message *reply, void
> *userdata, sd_bus_error *error) {
> +         _cleanup_(sd_bus_error_free) sd_bus_error error_buffer =
> SD_BUS_ERROR_NULL;
> +         AsyncPolkitQuery *q = userdata;
> +@@ -350,21 +386,46 @@ static int
> async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_e
> +         assert(reply);
> +         assert(q);
> + 
> ++        assert(q->slot);
> +         q->slot = sd_bus_slot_unref(q->slot);
> ++
> ++        assert(!q->reply);
> +         q->reply = sd_bus_message_ref(reply);
> + 
> ++        /* Now, let's dispatch the original message a second time
> be re-enqueing. This will then traverse the
> ++         * whole message processing again, and thus re-validating
> and re-retrieving the "userdata" field
> ++         * again.
> ++         *
> ++         * We install an idle event loop event to clean-up the
> PolicyKit request data when we are idle again,
> ++         * i.e. after the second time the message is processed is
> complete. */
> ++
> ++        assert(!q->defer_event_source);
> ++        r =
> sd_event_add_defer(sd_bus_get_event(sd_bus_message_get_bus(reply)),
> &q->defer_event_source, async_polkit_defer, q);
> ++        if (r < 0)
> ++                goto fail;
> ++
> ++        r = sd_event_source_set_priority(q->defer_event_source,
> SD_EVENT_PRIORITY_IDLE);
> ++        if (r < 0)
> ++                goto fail;
> ++
> ++        r = sd_event_source_set_enabled(q->defer_event_source,
> SD_EVENT_ONESHOT);
> ++        if (r < 0)
> ++                goto fail;
> ++
> +         r = sd_bus_message_rewind(q->request, true);
> +-        if (r < 0) {
> +-                r = sd_bus_reply_method_errno(q->request, r, NULL);
> +-                goto finish;
> +-        }
> ++        if (r < 0)
> ++                goto fail;
> + 
> +-        r = q->callback(q->request, q->userdata, &error_buffer);
> +-        r = bus_maybe_reply_error(q->request, r, &error_buffer);
> ++        r = sd_bus_enqueue_for_read(sd_bus_message_get_bus(q-
> >request), q->request);
> ++        if (r < 0)
> ++                goto fail;
> + 
> +-finish:
> +-        async_polkit_query_free(q);
> ++        return 1;
> + 
> ++fail:
> ++        log_debug_errno(r, "Processing asynchronous PolicyKit reply
> failed, ignoring: %m");
> ++        (void) sd_bus_reply_method_errno(q->request, r, NULL);
> ++        async_polkit_query_free(q);
> +         return r;
> + }
> + 
> +@@ -378,16 +439,14 @@ int bus_verify_polkit_async(
> +                 bool interactive,
> +                 uid_t good_user,
> +                 Hashmap **registry,
> +-                sd_bus_error *error) {
> ++                sd_bus_error *ret_error) {
> + 
> + #if ENABLE_POLKIT
> +         _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
> +         AsyncPolkitQuery *q;
> +-        const char *sender, **k, **v;
> +-        sd_bus_message_handler_t callback;
> +-        void *userdata;
> +         int c;
> + #endif
> ++        const char *sender;
> +         int r;
> + 
> +         assert(call);
> +@@ -403,11 +462,17 @@ int bus_verify_polkit_async(
> +         if (q) {
> +                 int authorized, challenge;
> + 
> +-                /* This is the second invocation of this function,
> and
> +-                 * there's already a response from polkit, let's
> +-                 * process it */
> ++                /* This is the second invocation of this function,
> and there's already a response from
> ++                 * polkit, let's process it */
> +                 assert(q->reply);
> + 
> ++                /* If the operation we want to authenticate changed
> between the first and the second time,
> ++                 * let's not use this authentication, it might be
> out of date as the object and context we
> ++                 * operate on might have changed. */
> ++                if (!streq(q->action, action) ||
> ++                    !strv_equal(q->details, (char**) details))
> ++                        return -ESTALE;
> ++
> +                 if (sd_bus_message_is_method_error(q->reply, NULL))
> {
> +                         const sd_bus_error *e;
> + 
> +@@ -418,7 +483,7 @@ int bus_verify_polkit_async(
> +                                 return -EACCES;
> + 
> +                         /* Copy error from polkit reply */
> +-                        sd_bus_error_copy(error, e);
> ++                        sd_bus_error_copy(ret_error, e);
> +                         return -sd_bus_error_get_errno(e);
> +                 }
> + 
> +@@ -433,7 +498,7 @@ int bus_verify_polkit_async(
> +                         return 1;
> + 
> +                 if (challenge)
> +-                        return sd_bus_error_set(error,
> SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive
> authentication required.");
> ++                        return sd_bus_error_set(ret_error,
> SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED, "Interactive
> authentication required.");
> + 
> +                 return -EACCES;
> +         }
> +@@ -445,20 +510,12 @@ int bus_verify_polkit_async(
> +         else if (r > 0)
> +                 return 1;
> + 
> +-#if ENABLE_POLKIT
> +-        if (sd_bus_get_current_message(call->bus) != call)
> +-                return -EINVAL;
> +-
> +-        callback = sd_bus_get_current_handler(call->bus);
> +-        if (!callback)
> +-                return -EINVAL;
> +-
> +-        userdata = sd_bus_get_current_userdata(call->bus);
> + 
> +         sender = sd_bus_message_get_sender(call);
> +         if (!sender)
> +                 return -EBADMSG;
> + 
> ++#if ENABLE_POLKIT
> +         c =
> sd_bus_message_get_allow_interactive_authorization(call);
> +         if (c < 0)
> +                 return c;
> +@@ -487,17 +544,7 @@ int bus_verify_polkit_async(
> +         if (r < 0)
> +                 return r;
> + 
> +-        r = sd_bus_message_open_container(pk, 'a', "{ss}");
> +-        if (r < 0)
> +-                return r;
> +-
> +-        STRV_FOREACH_PAIR(k, v, details) {
> +-                r = sd_bus_message_append(pk, "{ss}", *k, *v);
> +-                if (r < 0)
> +-                        return r;
> +-        }
> +-
> +-        r = sd_bus_message_close_container(pk);
> ++        r = bus_message_append_strv_key_value(pk, details);
> +         if (r < 0)
> +                 return r;
> + 
> +@@ -505,13 +552,25 @@ int bus_verify_polkit_async(
> +         if (r < 0)
> +                 return r;
> + 
> +-        q = new0(AsyncPolkitQuery, 1);
> ++        q = new(AsyncPolkitQuery, 1);
> +         if (!q)
> +                 return -ENOMEM;
> + 
> +-        q->request = sd_bus_message_ref(call);
> +-        q->callback = callback;
> +-        q->userdata = userdata;
> ++        *q = (AsyncPolkitQuery) {
> ++                .request = sd_bus_message_ref(call),
> ++        };
> ++
> ++        q->action = strdup(action);
> ++        if (!q->action) {
> ++                async_polkit_query_free(q);
> ++                return -ENOMEM;
> ++        }
> ++
> ++        q->details = strv_copy((char**) details);
> ++        if (!q->details) {
> ++                async_polkit_query_free(q);
> ++                return -ENOMEM;
> ++        }
> + 
> +         r = hashmap_put(*registry, call, q);
> +         if (r < 0) {
> +diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
> +index 84ceb62dc7..0e5c761f83 100644
> +--- a/src/systemd/sd-bus.h
> ++++ b/src/systemd/sd-bus.h
> +@@ -201,6 +201,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message
> **r);
> + int sd_bus_process_priority(sd_bus *bus, int64_t max_priority,
> sd_bus_message **r);
> + int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
> + int sd_bus_flush(sd_bus *bus);
> ++int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m);
> + 
> + sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
> + sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
> +-- 
> +2.23.0
> +
> diff --git a/meta/recipes-core/systemd/systemd_243.2.bb
> b/meta/recipes-core/systemd/systemd_243.2.bb
> index 6e7f95693b..082eb4c384 100644
> --- a/meta/recipes-core/systemd/systemd_243.2.bb
> +++ b/meta/recipes-core/systemd/systemd_243.2.bb
> @@ -24,6 +24,7 @@ SRC_URI += "file://touchscreen.rules \
>             file://0005-rules-watch-metadata-changes-in-ide-
> devices.patch \
>             file://0001-unit-file.c-consider-symlink-on-filesystems-
> like-NFS.patch \
>             file://99-default.preset \
> +           file://0001-Merge-branch-polkit-ref-count.patch \
>             "
>  
>  # patches needed by musl
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [OE-core][zeus][PATCH] systemd: Fix CVE-2020-1712
  2020-04-29  4:47 ` Anuj Mittal
@ 2020-04-29 15:15   ` Richard Purdie
  0 siblings, 0 replies; 3+ messages in thread
From: Richard Purdie @ 2020-04-29 15:15 UTC (permalink / raw)
  To: openembedded-core, wenlin.kang

On Wed, 2020-04-29 at 04:47 +0000, Anuj Mittal wrote:
> I wonder if it'd be better to upgrade to latest stable release for
> v243
> instead which has this fix.
> 
> Does the stable branch policy allow that in case of systemd?

Yes, we allow updating along upstream stable branches for our stable
releases.

Cheers,

Richard


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-04-29 15:15 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-28  8:36 [OE-core][zeus][PATCH] systemd: Fix CVE-2020-1712 wenlin.kang
2020-04-29  4:47 ` Anuj Mittal
2020-04-29 15:15   ` Richard Purdie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.