From 264ad849a4a0acf1ca392da62b7018d4fe7b66b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 May 2013 04:25:56 +0200 Subject: [PATCH] bus: add APIs for negotiating what is attached to messages --- TODO | 2 - src/libsystemd-bus/bus-internal.h | 3 +- src/libsystemd-bus/bus-kernel.c | 12 +--- src/libsystemd-bus/bus-socket.c | 12 ++-- src/libsystemd-bus/sd-bus.c | 92 ++++++++++++++++++++++++++-- src/libsystemd-bus/test-bus-kernel.c | 16 +++++ src/libsystemd-bus/test-bus-server.c | 4 +- src/shared/macro.h | 3 + src/stdio-bridge/stdio-bridge.c | 4 +- src/systemd/sd-bus.h | 9 ++- 10 files changed, 130 insertions(+), 27 deletions(-) diff --git a/TODO b/TODO index 390106aadf..fb5f0c3813 100644 --- a/TODO +++ b/TODO @@ -35,14 +35,12 @@ Features: * libsystemd-bus: - default policy (allow uid == 0 and our own uid) - enforce alignment of pointers passed in - - negotiation for attach attributes - when kdbus doesn't take our message without memfds, try again with memfds - kdbus: generate correct bloom filter for matches - implement translator service - port systemd to new library - implement busname unit type in systemd - move to gvariant - - keep the connection fds around as long as the bus is open - merge busctl into systemctl or so? - synthesize sd_bus_message objects from kernel messages diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index 8f87bea781..e775b09419 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -99,7 +99,6 @@ struct sd_bus { int message_version; bool is_kernel:1; - bool negotiate_fds:1; bool can_fds:1; bool bus_client:1; bool ucred_valid:1; @@ -181,6 +180,8 @@ struct sd_bus { unsigned n_memfd_cache; pid_t original_pid; + + uint64_t hello_flags; }; static inline void bus_unrefp(sd_bus **b) { diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index 699d24185e..107b2bd694 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -345,15 +345,7 @@ int bus_kernel_take_fd(sd_bus *b) { } hello->size = sizeof(h); - hello->conn_flags = - KDBUS_HELLO_ACCEPT_FD| - KDBUS_HELLO_ATTACH_COMM| - KDBUS_HELLO_ATTACH_EXE| - KDBUS_HELLO_ATTACH_CMDLINE| - KDBUS_HELLO_ATTACH_CGROUP| - KDBUS_HELLO_ATTACH_CAPS| - KDBUS_HELLO_ATTACH_SECLABEL| - KDBUS_HELLO_ATTACH_AUDIT; + hello->conn_flags = b->hello_flags; hello->items[0].type = KDBUS_HELLO_POOL; hello->items[0].size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); @@ -378,7 +370,7 @@ int bus_kernel_take_fd(sd_bus *b) { b->is_kernel = true; b->bus_client = true; - b->can_fds = true; + b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD); r = bus_start_running(b); if (r < 0) diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c index befded7079..b60facb20f 100644 --- a/src/libsystemd-bus/bus-socket.c +++ b/src/libsystemd-bus/bus-socket.c @@ -181,7 +181,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) { if (!e) return 0; - if (b->negotiate_fds) { + if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) { f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2); if (!f) return 0; @@ -464,7 +464,7 @@ static int bus_socket_auth_verify_server(sd_bus *b) { r = bus_socket_auth_write_ok(b); } } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) { - if (b->auth == _BUS_AUTH_INVALID || !b->negotiate_fds) + if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD)) r = bus_socket_auth_write(b, "ERROR\r\n"); else { b->can_fds = true; @@ -610,6 +610,8 @@ static int bus_socket_setup(sd_bus *b) { * socket, just in case. */ enable = !b->bus_client; setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); + + enable = !b->bus_client && (b->hello_flags & KDBUS_HELLO_ATTACH_SECLABEL); setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); /* Increase the buffers to a MB */ @@ -651,7 +653,7 @@ static int bus_socket_start_auth_client(sd_bus *b) { if (!b->auth_buffer) return -ENOMEM; - if (b->negotiate_fds) + if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n"; else auth_suffix = "\r\nBEGIN\r\n"; @@ -673,11 +675,11 @@ static int bus_socket_start_auth(sd_bus *b) { b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT; if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0) - b->negotiate_fds = false; + b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; if (b->output_fd != b->input_fd) if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0) - b->negotiate_fds = false; + b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; if (b->is_server) return bus_socket_read_auth(b); diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 5e66a31162..6033aa744f 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -125,7 +125,7 @@ int sd_bus_new(sd_bus **ret) { r->n_ref = REFCNT_INIT; r->input_fd = r->output_fd = -1; r->message_version = 1; - r->negotiate_fds = true; + r->hello_flags |= KDBUS_HELLO_ACCEPT_FD; r->original_pid = getpid(); assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0); @@ -226,7 +226,7 @@ int sd_bus_set_bus_client(sd_bus *bus, int b) { return 0; } -int sd_bus_set_negotiate_fds(sd_bus *bus, int b) { +int sd_bus_negotiate_fds(sd_bus *bus, int b) { if (!bus) return -EINVAL; if (bus->state != BUS_UNSET) @@ -234,7 +234,91 @@ int sd_bus_set_negotiate_fds(sd_bus *bus, int b) { if (bus_pid_changed(bus)) return -ECHILD; - bus->negotiate_fds = !!b; + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b); + return 0; +} + +int sd_bus_negotiate_attach_comm(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM, b); + return 0; +} + +int sd_bus_negotiate_attach_exe(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE, b); + return 0; +} + +int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE, b); + return 0; +} + +int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP, b); + return 0; +} + +int sd_bus_negotiate_attach_caps(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS, b); + return 0; +} + +int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL, b); + return 0; +} + +int sd_bus_negotiate_attach_audit(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + if (bus_pid_changed(bus)) + return -ECHILD; + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT, b); return 0; } @@ -1015,7 +1099,7 @@ int sd_bus_can_send(sd_bus *bus, char type) { return -ECHILD; if (type == SD_BUS_TYPE_UNIX_FD) { - if (!bus->negotiate_fds) + if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) return 0; r = bus_ensure_running(bus); diff --git a/src/libsystemd-bus/test-bus-kernel.c b/src/libsystemd-bus/test-bus-kernel.c index 72514a3dee..b8e89e41bc 100644 --- a/src/libsystemd-bus/test-bus-kernel.c +++ b/src/libsystemd-bus/test-bus-kernel.c @@ -60,6 +60,22 @@ int main(int argc, char *argv[]) { r = sd_bus_set_address(b, address); assert_se(r >= 0); + assert_se(sd_bus_negotiate_attach_comm(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_exe(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_cmdline(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_cgroup(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_caps(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_selinux_context(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_audit(a, 1) >= 0); + + assert_se(sd_bus_negotiate_attach_comm(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_exe(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_cmdline(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_cgroup(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_caps(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_selinux_context(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_audit(b, 1) >= 0); + r = sd_bus_start(a); assert_se(r >= 0); diff --git a/src/libsystemd-bus/test-bus-server.c b/src/libsystemd-bus/test-bus-server.c index a9772624f2..ef26a65d87 100644 --- a/src/libsystemd-bus/test-bus-server.c +++ b/src/libsystemd-bus/test-bus-server.c @@ -55,8 +55,8 @@ static void *server(void *p) { assert_se(sd_bus_new(&bus) >= 0); assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); assert_se(sd_bus_set_server(bus, 1, id) >= 0); - assert_se(sd_bus_set_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0); assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0); + assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0); assert_se(sd_bus_start(bus) >= 0); while (!quit) { @@ -134,7 +134,7 @@ static int client(struct context *c) { assert_se(sd_bus_new(&bus) >= 0); assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); - assert_se(sd_bus_set_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0); + assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0); assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0); assert_se(sd_bus_start(bus) >= 0); diff --git a/src/shared/macro.h b/src/shared/macro.h index 2f151bcc8c..bfe03f2ae0 100644 --- a/src/shared/macro.h +++ b/src/shared/macro.h @@ -284,4 +284,7 @@ do { \ sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) +#define SET_FLAG(v, flag, b) \ + (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) + #include "log.h" diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index a5bdb03416..ab1a43ab1a 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = sd_bus_set_negotiate_fds(a, is_unix); + r = sd_bus_negotiate_fds(a, is_unix); if (r < 0) { log_error("Failed to set FD negotiation: %s", strerror(-r)); goto finish; @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = sd_bus_set_negotiate_fds(b, is_unix); + r = sd_bus_negotiate_fds(b, is_unix); if (r < 0) { log_error("Failed to set FD negotiation: %s", strerror(-r)); goto finish; diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 85deacf63f..eeca69dd1a 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -64,7 +64,14 @@ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]); int sd_bus_set_bus_client(sd_bus *bus, int b); int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id); int sd_bus_set_anonymous(sd_bus *bus, int b); -int sd_bus_set_negotiate_fds(sd_bus *bus, int b); +int sd_bus_negotiate_fds(sd_bus *bus, int b); +int sd_bus_negotiate_attach_comm(sd_bus *bus, int b); +int sd_bus_negotiate_attach_exe(sd_bus *bus, int b); +int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b); +int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b); +int sd_bus_negotiate_attach_caps(sd_bus *bus, int b); +int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b); +int sd_bus_negotiate_attach_audit(sd_bus *bus, int b); int sd_bus_start(sd_bus *ret); void sd_bus_close(sd_bus *bus);