From 7d9f6034a93c695c939bb6ae3a626727d5683523 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 20 Apr 2023 01:24:42 +0100 Subject: [PATCH 1/5] sd-bus: check for pid change before closing If we try to close after a fork, the FDs will have been cloned too and we'll assert. This can happen for example in PAM modules. Avoid the macro and define ref/unref by hand to do the same check. --- src/libsystemd/sd-bus/sd-bus.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 40dadf67a88..f4f2e350f3c 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1779,6 +1779,8 @@ _public_ void sd_bus_close(sd_bus *bus) { _public_ sd_bus *sd_bus_close_unref(sd_bus *bus) { if (!bus) return NULL; + if (bus_pid_changed(bus)) + return NULL; sd_bus_close(bus); @@ -1788,6 +1790,8 @@ _public_ sd_bus *sd_bus_close_unref(sd_bus *bus) { _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) { if (!bus) return NULL; + if (bus_pid_changed(bus)) + return NULL; /* Have to do this before flush() to prevent hang */ bus_kill_exec(bus); @@ -1805,7 +1809,30 @@ void bus_enter_closing(sd_bus *bus) { bus_set_state(bus, BUS_CLOSING); } -DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free); +/* Define manually so we can add the PID check */ +_public_ sd_bus *sd_bus_ref(sd_bus *bus) { + if (!bus) + return NULL; + if (bus_pid_changed(bus)) + return NULL; + + bus->n_ref++; + + return bus; +} + +_public_ sd_bus* sd_bus_unref(sd_bus *bus) { + if (!bus) + return NULL; + if (bus_pid_changed(bus)) + return NULL; + + assert(bus->n_ref > 0); + if (--bus->n_ref > 0) + return NULL; + + return bus_free(bus); +} _public_ int sd_bus_is_open(sd_bus *bus) { if (!bus) From bf2d930fa12de997920eef493d9fcce1580c4f44 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 25 Apr 2023 00:37:51 +0100 Subject: [PATCH 2/5] macro: add helper for module origin id These need to be redefined in every module that we need to guard, so add a macro --- src/basic/origin-id.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/basic/origin-id.h diff --git a/src/basic/origin-id.h b/src/basic/origin-id.h new file mode 100644 index 00000000000..c55b0a368a9 --- /dev/null +++ b/src/basic/origin-id.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "random-util.h" + +/* This pattern needs to be repeated exactly in multiple modules, so macro it. + * To ensure an object is not passed into a different module (e.g.: when two shared objects statically + * linked to libsystemd get loaded in the same process, and the object created by one is passed to the + * other, see https://github.com/systemd/systemd/issues/27216), create a random static global random + * (mixed with PID, so that we can also check for reuse after fork) that is stored in the object and + * checked by public API on use. */ +#define _DEFINE_ORIGIN_ID_HELPERS(type, name, scope) \ +static uint64_t origin_id; \ + \ +static void origin_id_initialize(void) { \ + origin_id = random_u64(); \ +} \ + \ +static uint64_t origin_id_query(void) { \ + static pthread_once_t once = PTHREAD_ONCE_INIT; \ + assert_se(pthread_once(&once, origin_id_initialize) == 0); \ + return origin_id ^ getpid_cached(); \ +} \ + \ +scope bool name##_origin_changed(type *p) { \ + assert(p); \ + return p->origin_id != origin_id_query(); \ +} + +#define DEFINE_ORIGIN_ID_HELPERS(type, name) \ + _DEFINE_ORIGIN_ID_HELPERS(type, name,); + +#define DEFINE_PRIVATE_ORIGIN_ID_HELPERS(type, name) \ + _DEFINE_ORIGIN_ID_HELPERS(type, name, static); From bf876e3f3e7c38635547cd87de7621eb8e3e946c Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 25 Apr 2023 00:56:06 +0100 Subject: [PATCH 3/5] sd-bus: store and compare per-module static origin id sd-bus objects use hashmaps, which use module-global state, so it is not safe to pass a sd-bus object created by a module instance to another module instance (e.g.: when two libraries static linking sd-bus are pulled in a single process). Initialize a random per-module origin id and store it in the object, and compare it when entering a public API, and error out if they don't match, together with the PID. --- man/sd_bus_add_node_enumerator.xml | 2 +- man/sd_bus_add_object.xml | 2 +- man/sd_bus_add_object_manager.xml | 2 +- man/sd_bus_attach_event.xml | 2 +- man/sd_bus_close.xml | 2 +- man/sd_bus_emit_signal.xml | 2 +- man/sd_bus_enqueue_for_read.xml | 2 +- man/sd_bus_get_n_queued_read.xml | 2 +- man/sd_bus_get_name_creds.xml | 2 +- man/sd_bus_get_name_machine_id.xml | 2 +- man/sd_bus_is_open.xml | 2 +- man/sd_bus_list_names.xml | 2 +- man/sd_bus_negotiate_fds.xml | 2 +- man/sd_bus_query_sender_creds.xml | 2 +- man/sd_bus_set_close_on_exit.xml | 2 +- man/sd_bus_set_connected_signal.xml | 2 +- man/sd_bus_set_description.xml | 2 +- man/sd_bus_set_exit_on_disconnect.xml | 2 +- man/sd_bus_set_sender.xml | 2 +- man/sd_bus_set_server.xml | 2 +- man/sd_bus_set_watch_bind.xml | 2 +- man/sd_bus_slot_set_floating.xml | 2 +- src/libsystemd/sd-bus/bus-control.c | 18 ++-- src/libsystemd/sd-bus/bus-convenience.c | 36 +++---- src/libsystemd/sd-bus/bus-internal.h | 4 +- src/libsystemd/sd-bus/bus-objects.c | 24 ++--- src/libsystemd/sd-bus/sd-bus.c | 122 +++++++++++------------ src/libsystemd/sd-bus/test-bus-cleanup.c | 27 +++++ 28 files changed, 148 insertions(+), 127 deletions(-) diff --git a/man/sd_bus_add_node_enumerator.xml b/man/sd_bus_add_node_enumerator.xml index c6beb1dcd1b..541fa7b06da 100644 --- a/man/sd_bus_add_node_enumerator.xml +++ b/man/sd_bus_add_node_enumerator.xml @@ -111,7 +111,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_add_object.xml b/man/sd_bus_add_object.xml index 991f3a8064f..5a9e67abb0b 100644 --- a/man/sd_bus_add_object.xml +++ b/man/sd_bus_add_object.xml @@ -649,7 +649,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_add_object_manager.xml b/man/sd_bus_add_object_manager.xml index df2704ac991..6c66fd30018 100644 --- a/man/sd_bus_add_object_manager.xml +++ b/man/sd_bus_add_object_manager.xml @@ -90,7 +90,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_attach_event.xml b/man/sd_bus_attach_event.xml index bb34d4a7b92..ba3e58c25dc 100644 --- a/man/sd_bus_attach_event.xml +++ b/man/sd_bus_attach_event.xml @@ -94,7 +94,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_close.xml b/man/sd_bus_close.xml index 95427bd7f94..dab1d773366 100644 --- a/man/sd_bus_close.xml +++ b/man/sd_bus_close.xml @@ -96,7 +96,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_emit_signal.xml b/man/sd_bus_emit_signal.xml index 52d08b7a923..ec2a7976fd0 100644 --- a/man/sd_bus_emit_signal.xml +++ b/man/sd_bus_emit_signal.xml @@ -226,7 +226,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_enqueue_for_read.xml b/man/sd_bus_enqueue_for_read.xml index 9bdf4981950..601edafd6a5 100644 --- a/man/sd_bus_enqueue_for_read.xml +++ b/man/sd_bus_enqueue_for_read.xml @@ -67,7 +67,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_get_n_queued_read.xml b/man/sd_bus_get_n_queued_read.xml index c9978d8ba76..3b0f6148f88 100644 --- a/man/sd_bus_get_n_queued_read.xml +++ b/man/sd_bus_get_n_queued_read.xml @@ -78,7 +78,7 @@ -ECHILD - The bus connection was created in a different process. + The bus connection was created in a different process, library or module instance. diff --git a/man/sd_bus_get_name_creds.xml b/man/sd_bus_get_name_creds.xml index 6f0541d97ad..5444eeddb14 100644 --- a/man/sd_bus_get_name_creds.xml +++ b/man/sd_bus_get_name_creds.xml @@ -95,7 +95,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_get_name_machine_id.xml b/man/sd_bus_get_name_machine_id.xml index 8249485f254..cd702e4063c 100644 --- a/man/sd_bus_get_name_machine_id.xml +++ b/man/sd_bus_get_name_machine_id.xml @@ -72,7 +72,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_is_open.xml b/man/sd_bus_is_open.xml index 621ed272bb8..8f6b3bcba1a 100644 --- a/man/sd_bus_is_open.xml +++ b/man/sd_bus_is_open.xml @@ -83,7 +83,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_list_names.xml b/man/sd_bus_list_names.xml index d8f7e60b7dc..998c2866637 100644 --- a/man/sd_bus_list_names.xml +++ b/man/sd_bus_list_names.xml @@ -79,7 +79,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_negotiate_fds.xml b/man/sd_bus_negotiate_fds.xml index a4893b62e79..22b6817de34 100644 --- a/man/sd_bus_negotiate_fds.xml +++ b/man/sd_bus_negotiate_fds.xml @@ -137,7 +137,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_query_sender_creds.xml b/man/sd_bus_query_sender_creds.xml index 47cc3367064..b8fc7b39911 100644 --- a/man/sd_bus_query_sender_creds.xml +++ b/man/sd_bus_query_sender_creds.xml @@ -103,7 +103,7 @@ -ECHILD - The bus of m was created in a different process. + The bus of m was created in a different process, library or module instance. diff --git a/man/sd_bus_set_close_on_exit.xml b/man/sd_bus_set_close_on_exit.xml index cf3bbae0b55..5ee34a934ae 100644 --- a/man/sd_bus_set_close_on_exit.xml +++ b/man/sd_bus_set_close_on_exit.xml @@ -84,7 +84,7 @@ -ECHILD - The bus connection was created in a different process. + The bus connection was created in a different process, library or module instance. diff --git a/man/sd_bus_set_connected_signal.xml b/man/sd_bus_set_connected_signal.xml index b2dfcf0cf9c..09dcb5978a1 100644 --- a/man/sd_bus_set_connected_signal.xml +++ b/man/sd_bus_set_connected_signal.xml @@ -86,7 +86,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_set_description.xml b/man/sd_bus_set_description.xml index 0c38c16128f..783a0b7922b 100644 --- a/man/sd_bus_set_description.xml +++ b/man/sd_bus_set_description.xml @@ -202,7 +202,7 @@ -ECHILD - The bus was created in a different process. + The bus was created in a different process, library or module instance. diff --git a/man/sd_bus_set_exit_on_disconnect.xml b/man/sd_bus_set_exit_on_disconnect.xml index a694aef4f24..aee5adffb34 100644 --- a/man/sd_bus_set_exit_on_disconnect.xml +++ b/man/sd_bus_set_exit_on_disconnect.xml @@ -92,7 +92,7 @@ -ECHILD - The bus connection was created in a different process. + The bus connection was created in a different process, library or module instance. diff --git a/man/sd_bus_set_sender.xml b/man/sd_bus_set_sender.xml index c6e07acc979..2aedbfc01a2 100644 --- a/man/sd_bus_set_sender.xml +++ b/man/sd_bus_set_sender.xml @@ -75,7 +75,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_set_server.xml b/man/sd_bus_set_server.xml index e2cd74da90c..7c4b087628b 100644 --- a/man/sd_bus_set_server.xml +++ b/man/sd_bus_set_server.xml @@ -147,7 +147,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_set_watch_bind.xml b/man/sd_bus_set_watch_bind.xml index 20f6f53a2c8..123cef48a67 100644 --- a/man/sd_bus_set_watch_bind.xml +++ b/man/sd_bus_set_watch_bind.xml @@ -92,7 +92,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/man/sd_bus_slot_set_floating.xml b/man/sd_bus_slot_set_floating.xml index dd3a9500cf3..3309147847e 100644 --- a/man/sd_bus_slot_set_floating.xml +++ b/man/sd_bus_slot_set_floating.xml @@ -88,7 +88,7 @@ -ECHILD - The bus connection has been created in a different process. + The bus connection has been created in a different process, library or module instance. diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 83d68562dc7..864acd73ac1 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -26,7 +26,7 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(unique, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!bus->bus_client) return -EINVAL; @@ -89,7 +89,7 @@ _public_ int sd_bus_request_name( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); r = validate_request_name_parameters(bus, name, flags, ¶m); if (r < 0) @@ -193,7 +193,7 @@ _public_ int sd_bus_request_name_async( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); r = validate_request_name_parameters(bus, name, flags, ¶m); if (r < 0) @@ -247,7 +247,7 @@ _public_ int sd_bus_release_name( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); r = validate_release_name_parameters(bus, name); if (r < 0) @@ -340,7 +340,7 @@ _public_ int sd_bus_release_name_async( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); r = validate_release_name_parameters(bus, name); if (r < 0) @@ -367,7 +367,7 @@ _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatabl assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(acquired || activatable, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!bus->bus_client) return -EINVAL; @@ -438,7 +438,7 @@ _public_ int sd_bus_get_name_creds( assert_return(name, -EINVAL); assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); assert_return(mask == 0 || creds, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(service_name_is_valid(name), -EINVAL); if (!bus->bus_client) @@ -732,7 +732,7 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -903,7 +903,7 @@ _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_ assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(name, -EINVAL); assert_return(machine, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(service_name_is_valid(name), -EINVAL); if (!bus->bus_client) diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index 6974e210a24..81892c3254c 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -12,7 +12,7 @@ _public_ int sd_bus_message_send(sd_bus_message *reply) { assert_return(reply, -EINVAL); assert_return(reply->bus, -EINVAL); - assert_return(!bus_pid_changed(reply->bus), -ECHILD); + assert_return(!bus_origin_changed(reply->bus), -ECHILD); return sd_bus_send(reply->bus, reply, NULL); } @@ -30,7 +30,7 @@ _public_ int sd_bus_emit_signal_tov( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -109,7 +109,7 @@ _public_ int sd_bus_call_method_asyncv( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -163,7 +163,7 @@ _public_ int sd_bus_call_methodv( bus_assert_return(bus, -EINVAL, error); bus_assert_return(bus = bus_resolve(bus), -ENOPKG, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -217,7 +217,7 @@ _public_ int sd_bus_reply_method_returnv( assert_return(call->sealed, -EPERM); assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -264,7 +264,7 @@ _public_ int sd_bus_reply_method_error( assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(sd_bus_error_is_set(e), -EINVAL); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -291,7 +291,7 @@ _public_ int sd_bus_reply_method_errorfv( assert_return(call->sealed, -EPERM); assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -331,7 +331,7 @@ _public_ int sd_bus_reply_method_errno( assert_return(call->sealed, -EPERM); assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -359,7 +359,7 @@ _public_ int sd_bus_reply_method_errnofv( assert_return(call->sealed, -EPERM); assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -407,7 +407,7 @@ _public_ int sd_bus_get_property( bus_assert_return(member_name_is_valid(member), -EINVAL, error); bus_assert_return(reply, -EINVAL, error); bus_assert_return(signature_is_single(type, false), -EINVAL, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -452,7 +452,7 @@ _public_ int sd_bus_get_property_trivial( bus_assert_return(member_name_is_valid(member), -EINVAL, error); bus_assert_return(bus_type_is_trivial(type), -EINVAL, error); bus_assert_return(ptr, -EINVAL, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -496,7 +496,7 @@ _public_ int sd_bus_get_property_string( bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); bus_assert_return(member_name_is_valid(member), -EINVAL, error); bus_assert_return(ret, -EINVAL, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -545,7 +545,7 @@ _public_ int sd_bus_get_property_strv( bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); bus_assert_return(member_name_is_valid(member), -EINVAL, error); bus_assert_return(ret, -EINVAL, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -587,7 +587,7 @@ _public_ int sd_bus_set_propertyv( bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); bus_assert_return(member_name_is_valid(member), -EINVAL, error); bus_assert_return(signature_is_single(type, false), -EINVAL, error); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -646,7 +646,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); assert_return(ret, -EINVAL); if (!BUS_IS_OPEN(call->bus->state)) @@ -694,7 +694,7 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); assert_return(call->bus, -EINVAL); - assert_return(!bus_pid_changed(call->bus), -ECHILD); + assert_return(!bus_origin_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; @@ -786,7 +786,7 @@ _public_ int sd_bus_match_signal( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(!sender || service_name_is_valid(sender), -EINVAL); assert_return(!path || object_path_is_valid(path), -EINVAL); assert_return(!interface || interface_name_is_valid(interface), -EINVAL); @@ -812,7 +812,7 @@ _public_ int sd_bus_match_signal_async( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(!sender || service_name_is_valid(sender), -EINVAL); assert_return(!path || object_path_is_valid(path), -EINVAL); assert_return(!interface || interface_name_is_valid(interface), -EINVAL); diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index a9acdc7d0a0..aaef6ac3780 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -286,7 +286,7 @@ struct sd_bus { struct memfd_cache memfd_cache[MEMFD_CACHE_MAX]; unsigned n_memfd_cache; - pid_t original_pid; + uint64_t origin_id; pid_t busexec_pid; unsigned iteration_counter; @@ -377,7 +377,7 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m); int bus_rqueue_make_room(sd_bus *bus); -bool bus_pid_changed(sd_bus *bus); +bool bus_origin_changed(sd_bus *bus); char *bus_address_escape(const char *v); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 2ad7a9993d9..80dc86d01a4 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1610,7 +1610,7 @@ static int bus_add_object( assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(callback, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); n = bus_node_allocate(bus, path); if (!n) @@ -1806,7 +1806,7 @@ static int add_object_vtable_internal( assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_221 || vtable[0].x.start.element_size >= VTABLE_ELEMENT_SIZE_242, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(!streq(interface, "org.freedesktop.DBus.Properties") && !streq(interface, "org.freedesktop.DBus.Introspectable") && !streq(interface, "org.freedesktop.DBus.Peer") && @@ -2028,7 +2028,7 @@ _public_ int sd_bus_add_node_enumerator( assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(callback, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); n = bus_node_allocate(bus, path); if (!n) @@ -2280,7 +2280,7 @@ _public_ int sd_bus_emit_properties_changed_strv( assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(interface_name_is_valid(interface), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2334,7 +2334,7 @@ _public_ int sd_bus_emit_properties_changed( assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); assert_return(interface_name_is_valid(interface), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2523,7 +2523,7 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2703,7 +2703,7 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2862,7 +2862,7 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2932,7 +2932,7 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2950,7 +2950,7 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2986,7 +2986,7 @@ _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -3004,7 +3004,7 @@ _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const ch assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(object_path_is_valid(path), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); n = bus_node_allocate(bus, path); if (!n) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index f4f2e350f3c..6e0b88e9d73 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -38,6 +38,7 @@ #include "memory-util.h" #include "missing_syscall.h" #include "missing_threads.h" +#include "origin-id.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -232,6 +233,8 @@ static sd_bus* bus_free(sd_bus *b) { DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, bus_free); +DEFINE_ORIGIN_ID_HELPERS(sd_bus, bus); + _public_ int sd_bus_new(sd_bus **ret) { _cleanup_free_ sd_bus *b = NULL; @@ -249,7 +252,7 @@ _public_ int sd_bus_new(sd_bus **ret) { .message_version = 1, .creds_mask = SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME, .accept_fd = true, - .original_pid = getpid_cached(), + .origin_id = origin_id_query(), .n_groups = SIZE_MAX, .close_on_exit = true, .ucred = UCRED_INVALID, @@ -271,7 +274,7 @@ _public_ int sd_bus_set_address(sd_bus *bus, const char *address) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(address, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return free_and_strdup(&bus->address, address); } @@ -282,7 +285,7 @@ _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(input_fd >= 0, -EBADF); assert_return(output_fd >= 0, -EBADF); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->input_fd = input_fd; bus->output_fd = output_fd; @@ -298,7 +301,7 @@ _public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const *argv) { assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(path, -EINVAL); assert_return(!strv_isempty(argv), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); a = strv_copy(argv); if (!a) @@ -316,7 +319,7 @@ _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus->patch_sender, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->bus_client = !!b; return 0; @@ -326,7 +329,7 @@ _public_ int sd_bus_set_monitor(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->is_monitor = !!b; return 0; @@ -336,7 +339,7 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->accept_fd = !!b; return 0; @@ -346,7 +349,7 @@ _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); /* This is not actually supported by any of our transports these days, but we do honour it for synthetic * replies, and maybe one day classic D-Bus learns this too */ @@ -360,7 +363,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL); assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); SET_FLAG(bus->creds_mask, mask, b); @@ -375,7 +378,7 @@ _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(b || sd_id128_equal(server_id, SD_ID128_NULL), -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->is_server = !!b; bus->server_id = server_id; @@ -386,7 +389,7 @@ _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->anonymous_auth = !!b; return 0; @@ -396,7 +399,7 @@ _public_ int sd_bus_set_trusted(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->trusted = !!b; return 0; @@ -406,7 +409,7 @@ _public_ int sd_bus_set_description(sd_bus *bus, const char *description) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return free_and_strdup(&bus->description, description); } @@ -414,7 +417,7 @@ _public_ int sd_bus_set_description(sd_bus *bus, const char *description) { _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->allow_interactive_authorization = !!b; return 0; @@ -423,7 +426,7 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) { _public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->allow_interactive_authorization; } @@ -432,7 +435,7 @@ _public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->watch_bind = !!b; return 0; @@ -441,7 +444,7 @@ _public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) { _public_ int sd_bus_get_watch_bind(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->watch_bind; } @@ -450,7 +453,7 @@ _public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus->connected_signal = !!b; return 0; @@ -459,7 +462,7 @@ _public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) { _public_ int sd_bus_get_connected_signal(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->connected_signal; } @@ -1197,7 +1200,7 @@ _public_ int sd_bus_start(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); bus_set_state(bus, BUS_OPENING); @@ -1758,7 +1761,7 @@ _public_ void sd_bus_close(sd_bus *bus) { return; if (bus->state == BUS_CLOSED) return; - if (bus_pid_changed(bus)) + if (bus_origin_changed(bus)) return; /* Don't leave ssh hanging around */ @@ -1779,7 +1782,7 @@ _public_ void sd_bus_close(sd_bus *bus) { _public_ sd_bus *sd_bus_close_unref(sd_bus *bus) { if (!bus) return NULL; - if (bus_pid_changed(bus)) + if (bus_origin_changed(bus)) return NULL; sd_bus_close(bus); @@ -1790,7 +1793,7 @@ _public_ sd_bus *sd_bus_close_unref(sd_bus *bus) { _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) { if (!bus) return NULL; - if (bus_pid_changed(bus)) + if (bus_origin_changed(bus)) return NULL; /* Have to do this before flush() to prevent hang */ @@ -1813,7 +1816,7 @@ void bus_enter_closing(sd_bus *bus) { _public_ sd_bus *sd_bus_ref(sd_bus *bus) { if (!bus) return NULL; - if (bus_pid_changed(bus)) + if (bus_origin_changed(bus)) return NULL; bus->n_ref++; @@ -1824,7 +1827,7 @@ _public_ sd_bus *sd_bus_ref(sd_bus *bus) { _public_ sd_bus* sd_bus_unref(sd_bus *bus) { if (!bus) return NULL; - if (bus_pid_changed(bus)) + if (bus_origin_changed(bus)) return NULL; assert(bus->n_ref > 0); @@ -1839,7 +1842,7 @@ _public_ int sd_bus_is_open(sd_bus *bus) { return 0; assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return BUS_IS_OPEN(bus->state); } @@ -1849,7 +1852,7 @@ _public_ int sd_bus_is_ready(sd_bus *bus) { return 0; assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->state == BUS_RUNNING; } @@ -1860,7 +1863,7 @@ _public_ int sd_bus_can_send(sd_bus *bus, char type) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->state != BUS_UNSET, -ENOTCONN); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->is_monitor) return 0; @@ -1885,7 +1888,7 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(id, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); r = bus_ensure_running(bus); if (r < 0) @@ -2138,7 +2141,7 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) { assert_return(bus = bus_resolve(bus), -ENOPKG); else assert_return(bus = m->bus, -ENOTCONN); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2223,7 +2226,7 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat assert_return(bus = bus_resolve(bus), -ENOPKG); else assert_return(bus = m->bus, -ENOTCONN); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2291,7 +2294,7 @@ _public_ int sd_bus_call_async( assert_return(bus = bus_resolve(bus), -ENOPKG); else assert_return(bus = m->bus, -ENOTCONN); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -2399,7 +2402,7 @@ _public_ int sd_bus_call( assert_return(bus = bus_resolve(bus), -ENOPKG); else assert_return(bus = m->bus, -ENOTCONN); - bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus_origin_changed(bus), -ECHILD, error); if (!BUS_IS_OPEN(bus->state)) { r = -ENOTCONN; @@ -2532,7 +2535,7 @@ _public_ int sd_bus_get_fd(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(bus->input_fd == bus->output_fd, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->state == BUS_CLOSED) return -ENOTCONN; @@ -2551,7 +2554,7 @@ _public_ int sd_bus_get_events(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); switch (bus->state) { @@ -2598,7 +2601,7 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(timeout_usec, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state) && bus->state != BUS_CLOSING) return -ENOTCONN; @@ -3237,7 +3240,7 @@ static int bus_process_internal(sd_bus *bus, sd_bus_message **ret) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); /* We don't allow recursively invoking sd_bus_process(). */ assert_return(!bus->current_message, -EBUSY); @@ -3371,7 +3374,7 @@ _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->state == BUS_CLOSING) return 0; @@ -3394,7 +3397,7 @@ _public_ int sd_bus_flush(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->state == BUS_CLOSING) return 0; @@ -3448,7 +3451,7 @@ _public_ int sd_bus_add_filter( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(callback, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); s = bus_slot_allocate(bus, !slot, BUS_FILTER_CALLBACK, sizeof(struct filter_callback), userdata); if (!s) @@ -3545,7 +3548,7 @@ static int bus_add_match_full( assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(match, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); CLEANUP_ARRAY(components, n_components, bus_match_parse_free); @@ -3630,15 +3633,6 @@ _public_ int sd_bus_add_match_async( return bus_add_match_full(bus, slot, true, match, callback, install_callback, userdata); } -bool bus_pid_changed(sd_bus *bus) { - assert(bus); - - /* We don't support people creating a bus connection and - * keeping it around over a fork(). Let's complain. */ - - return bus->original_pid != getpid_cached(); -} - static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_bus *bus = ASSERT_PTR(userdata); int r; @@ -3969,7 +3963,7 @@ _public_ int sd_bus_default(sd_bus **ret) { _public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) { assert_return(b, -EINVAL); assert_return(tid, -EINVAL); - assert_return(!bus_pid_changed(b), -ECHILD); + assert_return(!bus_origin_changed(b), -ECHILD); if (b->tid != 0) { *tid = b->tid; @@ -4195,7 +4189,7 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template _public_ int sd_bus_try_close(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return -EOPNOTSUPP; } @@ -4205,7 +4199,7 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(description, -EINVAL); assert_return(bus->description, -ENXIO); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->description) *description = bus->description; @@ -4219,7 +4213,7 @@ _public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(scope, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->runtime_scope < 0) return -ENODATA; @@ -4232,7 +4226,7 @@ _public_ int sd_bus_get_address(sd_bus *bus, const char **address) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(address, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (bus->address) { *address = bus->address; @@ -4246,7 +4240,7 @@ _public_ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(mask, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); *mask = bus->creds_mask; return 0; @@ -4255,7 +4249,7 @@ _public_ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) { _public_ int sd_bus_is_bus_client(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->bus_client; } @@ -4263,7 +4257,7 @@ _public_ int sd_bus_is_bus_client(sd_bus *bus) { _public_ int sd_bus_is_server(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->is_server; } @@ -4271,7 +4265,7 @@ _public_ int sd_bus_is_server(sd_bus *bus) { _public_ int sd_bus_is_anonymous(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->anonymous_auth; } @@ -4279,7 +4273,7 @@ _public_ int sd_bus_is_anonymous(sd_bus *bus) { _public_ int sd_bus_is_trusted(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->trusted; } @@ -4287,7 +4281,7 @@ _public_ int sd_bus_is_trusted(sd_bus *bus) { _public_ int sd_bus_is_monitor(sd_bus *bus) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); return bus->is_monitor; } @@ -4353,7 +4347,7 @@ _public_ int sd_bus_get_sender(sd_bus *bus, const char **ret) { _public_ int sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(ret, -EINVAL); *ret = bus->rqueue_size; @@ -4363,7 +4357,7 @@ _public_ int sd_bus_get_n_queued_read(sd_bus *bus, uint64_t *ret) { _public_ int sd_bus_get_n_queued_write(sd_bus *bus, uint64_t *ret) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); assert_return(ret, -EINVAL); *ret = bus->wqueue_size; @@ -4425,7 +4419,7 @@ _public_ int sd_bus_enqueue_for_read(sd_bus *bus, sd_bus_message *m) { assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(m, -EINVAL); assert_return(m->sealed, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus_origin_changed(bus), -ECHILD); if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index f563db74e6d..3e14627c750 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -1,11 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "sd-bus.h" #include "bus-internal.h" #include "bus-message.h" +#include "process-util.h" #include "tests.h" static bool use_system_bus = false; @@ -17,6 +19,30 @@ static void test_bus_new(void) { assert_se(bus->n_ref == 1); } +static void test_bus_fork(void) { + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + int r; + + assert_se(sd_bus_new(&bus) == 0); + assert_se(bus->n_ref == 1); + + /* Check that after a fork the cleanup functions return NULL */ + r = safe_fork("(bus-fork-test)", FORK_WAIT|FORK_LOG, NULL); + if (r == 0) { + assert_se(bus); + assert_se(sd_bus_is_ready(bus) == -ECHILD); + assert_se(sd_bus_flush_close_unref(bus) == NULL); + assert_se(sd_bus_close_unref(bus) == NULL); + assert_se(sd_bus_unref(bus) == NULL); + sd_bus_close(bus); + assert_se(bus->n_ref == 1); + _exit(EXIT_SUCCESS); + } + + assert_se(r >= 0); + assert_se(bus->n_ref == 1); +} + static int test_bus_open(void) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; @@ -67,6 +93,7 @@ int main(int argc, char **argv) { test_setup_logging(LOG_INFO); test_bus_new(); + test_bus_fork(); if (test_bus_open() < 0) return log_tests_skipped("Failed to connect to bus"); From e046719b749ebba5d44d92c7e0a9fb207d545ff7 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 25 Apr 2023 01:08:46 +0100 Subject: [PATCH 4/5] sd-journal: store and compare per-module static origin id sd-journal objects use hashmaps, which use module-global state, so it is not safe to pass a sd-journal object created by a module instance to another module instance (e.g.: when two libraries static linking sd-journal are pulled in a single process). Initialize a random per-module origin id and store it in the object, and compare it when entering a public API, and error out if they don't match, together with the PID. --- man/sd_journal_get_data.xml | 2 +- src/libsystemd/sd-journal/journal-internal.h | 2 +- src/libsystemd/sd-journal/sd-journal.c | 88 +++++++++---------- src/libsystemd/sd-journal/test-journal-init.c | 19 ++++ 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml index 2955cd264b6..9a90f95d1ab 100644 --- a/man/sd_journal_get_data.xml +++ b/man/sd_journal_get_data.xml @@ -168,7 +168,7 @@ -ECHILD - The journal object was created in a different process. + The journal object was created in a different process, library or module instance. diff --git a/src/libsystemd/sd-journal/journal-internal.h b/src/libsystemd/sd-journal/journal-internal.h index 60e448dac0c..259aac847d6 100644 --- a/src/libsystemd/sd-journal/journal-internal.h +++ b/src/libsystemd/sd-journal/journal-internal.h @@ -87,7 +87,7 @@ struct sd_journal { Match *level0, *level1, *level2; - pid_t original_pid; + uint64_t origin_id; int inotify_fd; unsigned current_invalidate_counter, last_invalidate_counter; diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c index 8964140f7ae..b0194e875c9 100644 --- a/src/libsystemd/sd-journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -33,6 +33,7 @@ #include "list.h" #include "lookup3.h" #include "nulstr-util.h" +#include "origin-id.h" #include "path-util.h" #include "prioq.h" #include "process-util.h" @@ -51,19 +52,12 @@ #define DEFAULT_DATA_THRESHOLD (64*1024) +DEFINE_PRIVATE_ORIGIN_ID_HELPERS(sd_journal, journal); + static void remove_file_real(sd_journal *j, JournalFile *f); static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f); static void journal_file_unlink_newest_by_bood_id(sd_journal *j, JournalFile *f); -static bool journal_pid_changed(sd_journal *j) { - assert(j); - - /* We don't support people creating a journal object and - * keeping it around over a fork(). Let's complain. */ - - return j->original_pid != getpid_cached(); -} - static int journal_put_error(sd_journal *j, int r, const char *path) { _cleanup_free_ char *copy = NULL; int k; @@ -234,7 +228,7 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) uint64_t hash; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(data, -EINVAL); if (size == 0) @@ -330,7 +324,7 @@ fail: _public_ int sd_journal_add_conjunction(sd_journal *j) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); if (!j->level0) return 0; @@ -349,7 +343,7 @@ _public_ int sd_journal_add_conjunction(sd_journal *j) { _public_ int sd_journal_add_disjunction(sd_journal *j) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); if (!j->level0) return 0; @@ -406,7 +400,7 @@ char *journal_make_match_string(sd_journal *j) { } _public_ void sd_journal_flush_matches(sd_journal *j) { - if (!j) + if (!j || journal_origin_changed(j)) return; if (j->level0) @@ -930,7 +924,7 @@ static int real_journal_next(sd_journal *j, direction_t direction) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); r = iterated_cache_get(j->files_cache, NULL, &files, &n_files); if (r < 0) @@ -988,7 +982,7 @@ static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t int c = 0, r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(skip <= INT_MAX, -ERANGE); if (skip == 0) { @@ -1031,7 +1025,7 @@ _public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(cursor, -EINVAL); if (!j->current_file || j->current_file->current_offset <= 0) @@ -1064,7 +1058,7 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(!isempty(cursor), -EINVAL); for (const char *p = cursor;;) { @@ -1160,7 +1154,7 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { Object *o; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(!isempty(cursor), -EINVAL); if (!j->current_file || j->current_file->current_offset <= 0) @@ -1239,7 +1233,7 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); detach_location(j); @@ -1255,7 +1249,7 @@ _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, u _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); detach_location(j); @@ -1270,7 +1264,7 @@ _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) { _public_ int sd_journal_seek_head(sd_journal *j) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); detach_location(j); @@ -1283,7 +1277,7 @@ _public_ int sd_journal_seek_head(sd_journal *j) { _public_ int sd_journal_seek_tail(sd_journal *j) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); detach_location(j); @@ -2001,7 +1995,7 @@ static sd_journal *journal_new(int flags, const char *path, const char *namespac return NULL; *j = (sd_journal) { - .original_pid = getpid_cached(), + .origin_id = origin_id_query(), .toplevel_fd = -EBADF, .inotify_fd = -EBADF, .flags = flags, @@ -2254,7 +2248,7 @@ _public_ void sd_journal_close(sd_journal *j) { Directory *d; Prioq *p; - if (!j) + if (!j || journal_origin_changed(j)) return; while ((p = hashmap_first(j->newest_by_boot_id))) @@ -2470,7 +2464,7 @@ _public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); f = j->current_file; if (!f) @@ -2498,7 +2492,7 @@ _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id12 int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); f = j->current_file; if (!f) @@ -2543,7 +2537,7 @@ _public_ int sd_journal_get_seqnum( int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); f = j->current_file; if (!f) @@ -2597,7 +2591,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(field, -EINVAL); assert_return(data, -EINVAL); assert_return(size, -EINVAL); @@ -2654,7 +2648,7 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(data, -EINVAL); assert_return(size, -EINVAL); @@ -2715,7 +2709,7 @@ _public_ int sd_journal_enumerate_available_data(sd_journal *j, const void **dat } _public_ void sd_journal_restart_data(sd_journal *j) { - if (!j) + if (!j || journal_origin_changed(j)) return; j->current_field = 0; @@ -2743,7 +2737,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); if (j->no_inotify) return -EMEDIUMTYPE; @@ -2769,7 +2763,7 @@ _public_ int sd_journal_get_events(sd_journal *j) { int fd; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); fd = sd_journal_get_fd(j); if (fd < 0) @@ -2782,7 +2776,7 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { int fd; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(timeout_usec, -EINVAL); fd = sd_journal_get_fd(j); @@ -2905,7 +2899,7 @@ _public_ int sd_journal_process(sd_journal *j) { bool got_something = false; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); if (j->inotify_fd < 0) /* We have no inotify fd yet? Then there's noting to process. */ return 0; @@ -2937,7 +2931,7 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { uint64_t t; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); if (j->inotify_fd < 0) { JournalFile *f; @@ -2990,7 +2984,7 @@ _public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(from || to, -EINVAL); assert_return(from != to, -EINVAL); @@ -3035,7 +3029,7 @@ _public_ int sd_journal_get_cutoff_monotonic_usec( int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(ret_from != ret_to, -EINVAL); ORDERED_HASHMAP_FOREACH(f, j->files) { @@ -3088,7 +3082,7 @@ _public_ int sd_journal_get_usage(sd_journal *j, uint64_t *ret) { uint64_t sum = 0; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(ret, -EINVAL); ORDERED_HASHMAP_FOREACH(f, j->files) { @@ -3116,7 +3110,7 @@ _public_ int sd_journal_query_unique(sd_journal *j, const char *field) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(!isempty(field), -EINVAL); assert_return(field_is_valid(field), -EINVAL); @@ -3139,7 +3133,7 @@ _public_ int sd_journal_enumerate_unique( size_t k; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(j->unique_field, -EINVAL); k = strlen(j->unique_field); @@ -3272,7 +3266,7 @@ _public_ int sd_journal_enumerate_available_unique(sd_journal *j, const void **d } _public_ void sd_journal_restart_unique(sd_journal *j) { - if (!j) + if (!j || journal_origin_changed(j)) return; j->unique_file = NULL; @@ -3284,7 +3278,7 @@ _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(field, -EINVAL); if (!j->fields_file) { @@ -3423,7 +3417,7 @@ _public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) { } _public_ void sd_journal_restart_fields(sd_journal *j) { - if (!j) + if (!j || journal_origin_changed(j)) return; j->fields_file = NULL; @@ -3434,7 +3428,7 @@ _public_ void sd_journal_restart_fields(sd_journal *j) { _public_ int sd_journal_reliable_fd(sd_journal *j) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); return !j->on_network; } @@ -3466,7 +3460,7 @@ _public_ int sd_journal_get_catalog(sd_journal *j, char **ret) { int r; assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(ret, -EINVAL); r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size); @@ -3501,7 +3495,7 @@ _public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) { _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); j->data_threshold = sz; return 0; @@ -3509,7 +3503,7 @@ _public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) { _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!journal_origin_changed(j), -ECHILD); assert_return(sz, -EINVAL); *sz = j->data_threshold; diff --git a/src/libsystemd/sd-journal/test-journal-init.c b/src/libsystemd/sd-journal/test-journal-init.c index d5702db3300..c8a19779f5f 100644 --- a/src/libsystemd/sd-journal/test-journal-init.c +++ b/src/libsystemd/sd-journal/test-journal-init.c @@ -1,10 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "sd-journal.h" #include "chattr-util.h" +#include "journal-internal.h" #include "log.h" #include "parse-util.h" +#include "process-util.h" #include "rm-rf.h" #include "tests.h" @@ -35,6 +39,21 @@ int main(int argc, char *argv[]) { r = sd_journal_open_directory(&j, t, 0); assert_se(r == 0); + assert_se(sd_journal_seek_head(j) == 0); + assert_se(j->current_location.type == LOCATION_HEAD); + + r = safe_fork("(journal-fork-test)", FORK_WAIT|FORK_LOG, NULL); + if (r == 0) { + assert_se(j); + assert_se(sd_journal_get_realtime_usec(j, NULL) == -ECHILD); + assert_se(sd_journal_seek_tail(j) == -ECHILD); + assert_se(j->current_location.type == LOCATION_HEAD); + sd_journal_close(j); + _exit(EXIT_SUCCESS); + } + + assert_se(r >= 0); + sd_journal_close(j); j = NULL; From 2eeff0f4f1af40eb0c22d869c50eb364e2a5d489 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 25 Apr 2023 01:46:22 +0100 Subject: [PATCH 5/5] sd-event: store and compare per-module static origin id sd-event objects use hashmaps, which use module-global state, so it is not safe to pass a sd-event object created by a module instance to another module instance (e.g.: when two libraries static linking sd-event are pulled in a single process). Initialize a random per-module origin id and store it in the object, and compare it when entering a public API, and error out if they don't match, together with the PID. --- man/sd_event_add_child.xml | 2 +- man/sd_event_add_defer.xml | 2 +- man/sd_event_add_inotify.xml | 2 +- man/sd_event_add_io.xml | 2 +- man/sd_event_add_memory_pressure.xml | 2 +- man/sd_event_add_signal.xml | 2 +- man/sd_event_add_time.xml | 2 +- man/sd_event_exit.xml | 2 +- man/sd_event_get_fd.xml | 2 +- man/sd_event_now.xml | 2 +- man/sd_event_run.xml | 2 +- man/sd_event_set_signal_exit.xml | 2 +- man/sd_event_set_watchdog.xml | 2 +- man/sd_event_source_get_pending.xml | 2 +- man/sd_event_source_set_description.xml | 2 +- man/sd_event_source_set_enabled.xml | 2 +- man/sd_event_source_set_floating.xml | 2 +- man/sd_event_source_set_prepare.xml | 2 +- man/sd_event_source_set_priority.xml | 2 +- man/sd_event_source_set_ratelimit.xml | 2 +- man/sd_event_wait.xml | 2 +- src/libsystemd/sd-event/sd-event.c | 176 +++++++++++++++--------- src/libsystemd/sd-event/test-event.c | 20 +++ 23 files changed, 150 insertions(+), 88 deletions(-) diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml index fec754d2dde..31b9d763402 100644 --- a/man/sd_event_add_child.xml +++ b/man/sd_event_add_child.xml @@ -289,7 +289,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml index e56e16a0328..3bac5d53d42 100644 --- a/man/sd_event_add_defer.xml +++ b/man/sd_event_add_defer.xml @@ -168,7 +168,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_inotify.xml b/man/sd_event_add_inotify.xml index c7af7bdcd00..1f31907b0db 100644 --- a/man/sd_event_add_inotify.xml +++ b/man/sd_event_add_inotify.xml @@ -170,7 +170,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_io.xml b/man/sd_event_add_io.xml index 383a58a074e..4201c68f0d0 100644 --- a/man/sd_event_add_io.xml +++ b/man/sd_event_add_io.xml @@ -270,7 +270,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_memory_pressure.xml b/man/sd_event_add_memory_pressure.xml index 8df69fde3bb..08a27d15c1b 100644 --- a/man/sd_event_add_memory_pressure.xml +++ b/man/sd_event_add_memory_pressure.xml @@ -236,7 +236,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml index 3e8536e9611..29a78239740 100644 --- a/man/sd_event_add_signal.xml +++ b/man/sd_event_add_signal.xml @@ -165,7 +165,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index 19f112b0f60..6031fee1b38 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -270,7 +270,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_exit.xml b/man/sd_event_exit.xml index e13cbe18ab9..343dd9066e1 100644 --- a/man/sd_event_exit.xml +++ b/man/sd_event_exit.xml @@ -109,7 +109,7 @@ -ECHILD - The event loop was created in a different process. + The event loop was created in a different process, library or module instance. diff --git a/man/sd_event_get_fd.xml b/man/sd_event_get_fd.xml index a3b11e41ee3..698691fa0d2 100644 --- a/man/sd_event_get_fd.xml +++ b/man/sd_event_get_fd.xml @@ -77,7 +77,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_now.xml b/man/sd_event_now.xml index 789b9e02884..70e980ab7b3 100644 --- a/man/sd_event_now.xml +++ b/man/sd_event_now.xml @@ -91,7 +91,7 @@ -ECHILD - The event loop object was created in a different process. + The event loop object was created in a different process, library or module instance. diff --git a/man/sd_event_run.xml b/man/sd_event_run.xml index 81c51b70603..c30f5eb4c23 100644 --- a/man/sd_event_run.xml +++ b/man/sd_event_run.xml @@ -129,7 +129,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_set_signal_exit.xml b/man/sd_event_set_signal_exit.xml index e5e675beec9..cdf49a54f9c 100644 --- a/man/sd_event_set_signal_exit.xml +++ b/man/sd_event_set_signal_exit.xml @@ -72,7 +72,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_set_watchdog.xml b/man/sd_event_set_watchdog.xml index 28d647c7bcd..954a1366cf6 100644 --- a/man/sd_event_set_watchdog.xml +++ b/man/sd_event_set_watchdog.xml @@ -108,7 +108,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_get_pending.xml b/man/sd_event_source_get_pending.xml index 5906930b3c3..7521ba6420c 100644 --- a/man/sd_event_source_get_pending.xml +++ b/man/sd_event_source_get_pending.xml @@ -109,7 +109,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_description.xml b/man/sd_event_source_set_description.xml index bea3e71914e..9ad369817f8 100644 --- a/man/sd_event_source_set_description.xml +++ b/man/sd_event_source_set_description.xml @@ -106,7 +106,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_enabled.xml b/man/sd_event_source_set_enabled.xml index 5f13fc101d0..cab8667f0fe 100644 --- a/man/sd_event_source_set_enabled.xml +++ b/man/sd_event_source_set_enabled.xml @@ -127,7 +127,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_floating.xml b/man/sd_event_source_set_floating.xml index 7f3ed86a658..db288094b67 100644 --- a/man/sd_event_source_set_floating.xml +++ b/man/sd_event_source_set_floating.xml @@ -89,7 +89,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_prepare.xml b/man/sd_event_source_set_prepare.xml index d52c55b3db9..e7526a9ff5a 100644 --- a/man/sd_event_source_set_prepare.xml +++ b/man/sd_event_source_set_prepare.xml @@ -104,7 +104,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_priority.xml b/man/sd_event_source_set_priority.xml index 2616c12e3fc..efe05b11d26 100644 --- a/man/sd_event_source_set_priority.xml +++ b/man/sd_event_source_set_priority.xml @@ -139,7 +139,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_source_set_ratelimit.xml b/man/sd_event_source_set_ratelimit.xml index b8e6380ddd3..07ac18b7917 100644 --- a/man/sd_event_source_set_ratelimit.xml +++ b/man/sd_event_source_set_ratelimit.xml @@ -120,7 +120,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index 25e21b9d5cf..0dc7105cf9c 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -291,7 +291,7 @@ -ECHILD - The event loop has been created in a different process. + The event loop has been created in a different process, library or module instance. diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f11f35ef6e8..a12d5e1a5a5 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -25,6 +25,7 @@ #include "missing_magic.h" #include "missing_syscall.h" #include "missing_threads.h" +#include "origin-id.h" #include "path-util.h" #include "prioq.h" #include "process-util.h" @@ -144,7 +145,7 @@ struct sd_event { /* A list of memory pressure event sources that still need their subscription string written */ LIST_HEAD(sd_event_source, memory_pressure_write_list); - pid_t original_pid; + uint64_t origin_id; uint64_t iteration; triple_timestamp timestamp; @@ -174,6 +175,8 @@ struct sd_event { unsigned delays[sizeof(usec_t) * 8]; }; +DEFINE_PRIVATE_ORIGIN_ID_HELPERS(sd_event, event); + static thread_local sd_event *default_event = NULL; static void source_disconnect(sd_event_source *s); @@ -410,7 +413,7 @@ _public_ int sd_event_new(sd_event** ret) { .boottime_alarm.fd = -EBADF, .boottime_alarm.next = USEC_INFINITY, .perturb = USEC_INFINITY, - .original_pid = getpid_cached(), + .origin_id = origin_id_query(), }; r = prioq_ensure_allocated(&e->pending, pending_prioq_compare); @@ -439,7 +442,31 @@ fail: return r; } -DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free); +/* Define manually so we can add the origin check */ +_public_ sd_event *sd_event_ref(sd_event *e) { + if (!e) + return NULL; + if (event_origin_changed(e)) + return NULL; + + e->n_ref++; + + return e; +} + +_public_ sd_event* sd_event_unref(sd_event *e) { + if (!e) + return NULL; + if (event_origin_changed(e)) + return NULL; + + assert(e->n_ref > 0); + if (--e->n_ref > 0) + return NULL; + + return event_free(e); +} + #define PROTECT_EVENT(e) \ _unused_ _cleanup_(sd_event_unrefp) sd_event *_ref = sd_event_ref(e); @@ -449,20 +476,11 @@ _public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) { return sd_event_source_unref(s); } -static bool event_pid_changed(sd_event *e) { - assert(e); - - /* We don't support people creating an event loop and keeping - * it around over a fork(). Let's complain. */ - - return e->original_pid != getpid_cached(); -} - static void source_io_unregister(sd_event_source *s) { assert(s); assert(s->type == SOURCE_IO); - if (event_pid_changed(s->event)) + if (event_origin_changed(s->event)) return; if (!s->io.registered) @@ -503,7 +521,7 @@ static void source_child_pidfd_unregister(sd_event_source *s) { assert(s); assert(s->type == SOURCE_CHILD); - if (event_pid_changed(s->event)) + if (event_origin_changed(s->event)) return; if (!s->child.registered) @@ -542,7 +560,7 @@ static void source_memory_pressure_unregister(sd_event_source *s) { assert(s); assert(s->type == SOURCE_MEMORY_PRESSURE); - if (event_pid_changed(s->event)) + if (event_origin_changed(s->event)) return; if (!s->memory_pressure.registered) @@ -694,7 +712,7 @@ static int event_make_signal_data( assert(e); - if (event_pid_changed(e)) + if (event_origin_changed(e)) return -ECHILD; if (e->signal_sources && e->signal_sources[sig]) @@ -791,7 +809,7 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig return; } - if (event_pid_changed(e)) + if (event_origin_changed(e)) return; assert(d->fd >= 0); @@ -954,7 +972,7 @@ static void source_disconnect(sd_event_source *s) { break; case SOURCE_CHILD: - if (event_pid_changed(s->event)) + if (event_origin_changed(s->event)) s->child.process_owned = false; if (s->child.pid > 0) { @@ -1231,7 +1249,7 @@ _public_ int sd_event_add_io( assert_return(fd >= 0, -EBADF); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = io_exit_callback; @@ -1378,7 +1396,7 @@ _public_ int sd_event_add_time( assert_return(e = event_resolve(e), -ENOPKG); assert_return(accuracy != UINT64_MAX, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */ return -EOPNOTSUPP; @@ -1465,7 +1483,7 @@ _public_ int sd_event_add_signal( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); /* Let's make sure our special flag stays outside of the valid signal range */ assert_cc(_NSIG < SD_EVENT_SIGNAL_PROCMASK); @@ -1575,7 +1593,7 @@ _public_ int sd_event_add_child( assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = child_exit_callback; @@ -1673,7 +1691,7 @@ _public_ int sd_event_add_child_pidfd( assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = child_exit_callback; @@ -1754,7 +1772,7 @@ _public_ int sd_event_add_defer( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = generic_exit_callback; @@ -1790,7 +1808,7 @@ _public_ int sd_event_add_post( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = generic_exit_callback; @@ -1828,7 +1846,7 @@ _public_ int sd_event_add_exit( assert_return(e = event_resolve(e), -ENOPKG); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); r = prioq_ensure_allocated(&e->exit, exit_prioq_compare); if (r < 0) @@ -1928,7 +1946,7 @@ _public_ int sd_event_add_memory_pressure( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = memory_pressure_callback; @@ -2126,7 +2144,7 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { assert_se(hashmap_remove(e->inotify_data, &d->priority) == d); if (d->fd >= 0) { - if (!event_pid_changed(e) && + if (!event_origin_changed(e) && epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m"); @@ -2237,7 +2255,7 @@ static void event_free_inode_data( if (d->inotify_data) { if (d->wd >= 0) { - if (d->inotify_data->fd >= 0 && !event_pid_changed(e)) { + if (d->inotify_data->fd >= 0 && !event_origin_changed(e)) { /* So here's a problem. At the time this runs the watch descriptor might already be * invalidated, because an IN_IGNORED event might be queued right the moment we enter * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very @@ -2444,7 +2462,7 @@ static int event_add_inotify_fd_internal( assert_return(e = event_resolve(e), -ENOPKG); assert_return(fd >= 0, -EBADF); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!callback) callback = inotify_exit_callback; @@ -2577,7 +2595,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event_source, sd_event_source, event_sou _public_ int sd_event_source_set_description(sd_event_source *s, const char *description) { assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); return free_and_strdup(&s->description, description); } @@ -2585,7 +2603,7 @@ _public_ int sd_event_source_set_description(sd_event_source *s, const char *des _public_ int sd_event_source_get_description(sd_event_source *s, const char **description) { assert_return(s, -EINVAL); assert_return(description, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (!s->description) return -ENXIO; @@ -2596,6 +2614,7 @@ _public_ int sd_event_source_get_description(sd_event_source *s, const char **de _public_ sd_event *sd_event_source_get_event(sd_event_source *s) { assert_return(s, NULL); + assert_return(!event_origin_changed(s->event), NULL); return s->event; } @@ -2604,7 +2623,7 @@ _public_ int sd_event_source_get_pending(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type != SOURCE_EXIT, -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->pending; } @@ -2612,7 +2631,7 @@ _public_ int sd_event_source_get_pending(sd_event_source *s) { _public_ int sd_event_source_get_io_fd(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->io.fd; } @@ -2623,7 +2642,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { assert_return(s, -EINVAL); assert_return(fd >= 0, -EBADF); assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->io.fd == fd) return 0; @@ -2656,6 +2675,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { _public_ int sd_event_source_get_io_fd_own(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->io.owned; } @@ -2663,6 +2683,7 @@ _public_ int sd_event_source_get_io_fd_own(sd_event_source *s) { _public_ int sd_event_source_set_io_fd_own(sd_event_source *s, int own) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); s->io.owned = own; return 0; @@ -2672,7 +2693,7 @@ _public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) assert_return(s, -EINVAL); assert_return(events, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *events = s->io.events; return 0; @@ -2685,7 +2706,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) assert_return(s->type == SOURCE_IO, -EDOM); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); /* edge-triggered updates are never skipped, so we can reset edges */ if (s->io.events == events && !(events & EPOLLET)) @@ -2711,7 +2732,7 @@ _public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revent assert_return(revents, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); assert_return(s->pending, -ENODATA); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *revents = s->io.revents; return 0; @@ -2720,14 +2741,14 @@ _public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revent _public_ int sd_event_source_get_signal(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_SIGNAL, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->signal.sig; } _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) { assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *priority = s->priority; return 0; @@ -2741,7 +2762,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) assert_return(s, -EINVAL); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->priority == priority) return 0; @@ -2841,7 +2862,7 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { return false; assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (ret) *ret = s->enabled; @@ -3035,7 +3056,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { return 0; assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ if (s->event->state == SD_EVENT_FINISHED) @@ -3067,7 +3088,7 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { assert_return(s, -EINVAL); assert_return(usec, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *usec = s->time.next; return 0; @@ -3079,7 +3100,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { assert_return(s, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); r = source_set_pending(s, false); if (r < 0) @@ -3097,6 +3118,7 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec assert_return(s, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); if (usec == USEC_INFINITY) return sd_event_source_set_time(s, USEC_INFINITY); @@ -3116,7 +3138,7 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use assert_return(s, -EINVAL); assert_return(usec, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *usec = s->time.accuracy; return 0; @@ -3129,7 +3151,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec assert_return(usec != UINT64_MAX, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); r = source_set_pending(s, false); if (r < 0) @@ -3148,7 +3170,7 @@ _public_ int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock assert_return(s, -EINVAL); assert_return(clock, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *clock = event_source_type_to_clock(s->type); return 0; @@ -3158,7 +3180,7 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { assert_return(s, -EINVAL); assert_return(pid, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *pid = s->child.pid; return 0; @@ -3167,7 +3189,7 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { _public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->child.pidfd < 0) return -EOPNOTSUPP; @@ -3178,7 +3200,7 @@ _public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { _public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); assert_return(SIGNAL_VALID(sig), -EINVAL); /* If we already have seen indication the process exited refuse sending a signal early. This way we @@ -3223,6 +3245,7 @@ _public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, cons _public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->child.pidfd < 0) return -EOPNOTSUPP; @@ -3233,6 +3256,7 @@ _public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { _public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->child.pidfd < 0) return -EOPNOTSUPP; @@ -3244,6 +3268,7 @@ _public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { _public_ int sd_event_source_get_child_process_own(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->child.process_owned; } @@ -3251,6 +3276,7 @@ _public_ int sd_event_source_get_child_process_own(sd_event_source *s) { _public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); s->child.process_owned = own; return 0; @@ -3260,7 +3286,7 @@ _public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask assert_return(s, -EINVAL); assert_return(mask, -EINVAL); assert_return(s->type == SOURCE_INOTIFY, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); *mask = s->inotify.mask; return 0; @@ -3272,7 +3298,7 @@ _public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t assert_return(s, -EINVAL); assert_return(s->type != SOURCE_EXIT, -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->prepare == callback) return 0; @@ -3300,6 +3326,7 @@ _public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t _public_ void* sd_event_source_get_userdata(sd_event_source *s) { assert_return(s, NULL); + assert_return(!event_origin_changed(s->event), NULL); return s->userdata; } @@ -3308,6 +3335,7 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) void *ret; assert_return(s, NULL); + assert_return(!event_origin_changed(s->event), NULL); ret = s->userdata; s->userdata = userdata; @@ -4423,7 +4451,7 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); @@ -4662,7 +4690,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_ARMED, -EBUSY); @@ -4765,7 +4793,7 @@ _public_ int sd_event_dispatch(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_PENDING, -EBUSY); @@ -4805,7 +4833,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); @@ -4853,9 +4881,10 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + PROTECT_EVENT(e); while (e->state != SD_EVENT_FINISHED) { @@ -4870,7 +4899,7 @@ _public_ int sd_event_loop(sd_event *e) { _public_ int sd_event_get_fd(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); return e->epoll_fd; } @@ -4878,7 +4907,7 @@ _public_ int sd_event_get_fd(sd_event *e) { _public_ int sd_event_get_state(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); return e->state; } @@ -4887,7 +4916,7 @@ _public_ int sd_event_get_exit_code(sd_event *e, int *code) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(code, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!e->exit_requested) return -ENODATA; @@ -4900,7 +4929,7 @@ _public_ int sd_event_exit(sd_event *e, int code) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); e->exit_requested = true; e->exit_code = code; @@ -4912,7 +4941,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(usec, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock)) return -EOPNOTSUPP; @@ -4955,7 +4984,7 @@ _public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(tid, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (e->tid != 0) { *tid = e->tid; @@ -4970,7 +4999,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); if (e->watchdog == !!b) return e->watchdog; @@ -5020,7 +5049,7 @@ fail: _public_ int sd_event_get_watchdog(sd_event *e) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); return e->watchdog; } @@ -5028,7 +5057,7 @@ _public_ int sd_event_get_watchdog(sd_event *e) { _public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); + assert_return(!event_origin_changed(e), -ECHILD); *ret = e->iteration; return 0; @@ -5036,6 +5065,8 @@ _public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { _public_ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback) { assert_return(s, -EINVAL); + assert_return(s->event, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); s->destroy_callback = callback; return 0; @@ -5043,6 +5074,7 @@ _public_ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_d _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); if (ret) *ret = s->destroy_callback; @@ -5052,12 +5084,14 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d _public_ int sd_event_source_get_floating(sd_event_source *s) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->floating; } _public_ int sd_event_source_set_floating(sd_event_source *s, int b) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->floating == !!b) return 0; @@ -5081,6 +5115,7 @@ _public_ int sd_event_source_set_floating(sd_event_source *s, int b) { _public_ int sd_event_source_get_exit_on_failure(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type != SOURCE_EXIT, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); return s->exit_on_failure; } @@ -5088,6 +5123,7 @@ _public_ int sd_event_source_get_exit_on_failure(sd_event_source *s) { _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) { assert_return(s, -EINVAL); assert_return(s->type != SOURCE_EXIT, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); if (s->exit_on_failure == !!b) return 0; @@ -5100,6 +5136,7 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval int r; assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing * so is a programming error. */ @@ -5117,6 +5154,7 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval _public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); s->ratelimit_expire_callback = callback; return 0; @@ -5124,6 +5162,7 @@ _public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, s _public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); /* Querying whether an event source has ratelimiting configured is not a loggable offense, hence * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error. */ @@ -5143,6 +5182,7 @@ _public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_int _public_ int sd_event_source_is_ratelimited(sd_event_source *s) { assert_return(s, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) return false; @@ -5212,6 +5252,7 @@ _public_ int sd_event_source_set_memory_pressure_type(sd_event_source *s, const assert_return(s, -EINVAL); assert_return(s->type == SOURCE_MEMORY_PRESSURE, -EDOM); assert_return(ty, -EINVAL); + assert_return(!event_origin_changed(s->event), -ECHILD); if (!STR_IN_SET(ty, "some", "full")) return -EINVAL; @@ -5253,6 +5294,7 @@ _public_ int sd_event_source_set_memory_pressure_period(sd_event_source *s, uint assert_return(s, -EINVAL); assert_return(s->type == SOURCE_MEMORY_PRESSURE, -EDOM); + assert_return(!event_origin_changed(s->event), -ECHILD); if (threshold_usec <= 0 || threshold_usec >= UINT64_MAX) return -ERANGE; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 591eab8896e..4f61af50f33 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "sd-event.h" @@ -808,4 +809,23 @@ TEST(inotify_process_buffered_data) { assert_se(sd_event_wait(e, 0) == 0); } +TEST(fork) { + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + int r; + + assert_se(sd_event_default(&e) >= 0); + assert_se(sd_event_prepare(e) == 0); + + /* Check that after a fork the cleanup functions return NULL */ + r = safe_fork("(bus-fork-test)", FORK_WAIT|FORK_LOG, NULL); + if (r == 0) { + assert_se(e); + assert_se(sd_event_ref(e) == NULL); + assert_se(sd_event_unref(e) == NULL); + _exit(EXIT_SUCCESS); + } + + assert_se(r >= 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG);