1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-03 05:18:09 +03:00

bus-proxy: turn into multi-threaded daemon

Instead of using Accept=true and running one proxy for each connection, we
now run one proxy-daemon with a thread per connection. This will enable us
to share resources like policies in the future.
This commit is contained in:
David Herrmann 2015-01-17 13:57:46 +01:00
parent f4a53250ac
commit a8a1a43f48
9 changed files with 149 additions and 162 deletions

View File

@ -2699,6 +2699,10 @@ libsystemd_proxy_la_LIBADD = \
systemd_bus_proxyd_SOURCES = \ systemd_bus_proxyd_SOURCES = \
src/bus-proxyd/bus-proxyd.c src/bus-proxyd/bus-proxyd.c
systemd_bus_proxyd_CFLAGS = \
$(AM_CFLAGS) \
-pthread
systemd_bus_proxyd_LDADD = \ systemd_bus_proxyd_LDADD = \
libsystemd-proxy.la \ libsystemd-proxy.la \
libsystemd-internal.la \ libsystemd-internal.la \
@ -2714,24 +2718,24 @@ systemd_stdio_bridge_LDADD = \
if ENABLE_KDBUS if ENABLE_KDBUS
nodist_systemunit_DATA += \ nodist_systemunit_DATA += \
units/systemd-bus-proxyd@.service units/systemd-bus-proxyd.service
dist_systemunit_DATA += \ dist_systemunit_DATA += \
units/systemd-bus-proxyd.socket units/systemd-bus-proxyd.socket
nodist_userunit_DATA += \ nodist_userunit_DATA += \
units/user/systemd-bus-proxyd@.service units/user/systemd-bus-proxyd.service
dist_userunit_DATA += \ dist_userunit_DATA += \
units/user/systemd-bus-proxyd.socket units/user/systemd-bus-proxyd.socket
endif endif
EXTRA_DIST += \ EXTRA_DIST += \
units/systemd-bus-proxyd@.service.m4.in \ units/systemd-bus-proxyd.service.m4.in \
units/user/systemd-bus-proxyd@.service.in units/user/systemd-bus-proxyd.service.in
CLEANFILES += \ CLEANFILES += \
units/systemd-bus-proxyd@.service.m4 units/systemd-bus-proxyd.service.m4
if HAVE_SMACK if HAVE_SMACK
bus-proxyd-set-cap-hook: bus-proxyd-set-cap-hook:

View File

@ -6,6 +6,7 @@
Copyright 2010 Lennart Poettering Copyright 2010 Lennart Poettering
Copyright 2013 Daniel Mack Copyright 2013 Daniel Mack
Copyright 2014 Kay Sievers Copyright 2014 Kay Sievers
Copyright 2015 David Herrmann
systemd is free software; you can redistribute it and/or modify it systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by under the terms of the GNU Lesser General Public License as published by
@ -31,9 +32,11 @@
#include <sys/poll.h> #include <sys/poll.h>
#include <stddef.h> #include <stddef.h>
#include <getopt.h> #include <getopt.h>
#include <pthread.h>
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#include "hashmap.h"
#include "socket-util.h" #include "socket-util.h"
#include "sd-daemon.h" #include "sd-daemon.h"
#include "sd-bus.h" #include "sd-bus.h"
@ -53,17 +56,118 @@
#include "synthesize.h" #include "synthesize.h"
static char *arg_address = NULL; static char *arg_address = NULL;
static char *arg_command_line_buffer = NULL;
static bool arg_drop_privileges = false;
static char **arg_configuration = NULL; static char **arg_configuration = NULL;
typedef struct {
int fd;
} ClientContext;
static ClientContext *client_context_free(ClientContext *c) {
if (!c)
return NULL;
close(c->fd);
free(c);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
static int client_context_new(ClientContext **out, int fd) {
_cleanup_(client_context_freep) ClientContext *c = NULL;
c = new0(ClientContext, 1);
if (!c)
return log_oom();
c->fd = fd;
*out = c;
c = NULL;
return 0;
}
static void *run_client(void *userdata) {
_cleanup_(client_context_freep) ClientContext *c = userdata;
_cleanup_(proxy_freep) Proxy *p = NULL;
int r;
r = proxy_new(&p, c->fd, c->fd, arg_address);
if (r < 0)
goto exit;
r = proxy_load_policy(p, arg_configuration);
if (r < 0)
goto exit;
r = proxy_hello_policy(p, getuid());
if (r < 0)
goto exit;
r = proxy_run(p);
exit:
return NULL;
}
static int loop_clients(int accept_fd) {
pthread_attr_t attr;
int r;
r = pthread_attr_init(&attr);
if (r < 0) {
r = log_error_errno(errno, "Cannot initialize pthread attributes: %m");
goto exit;
}
r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (r < 0) {
r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
goto exit_attr;
}
for (;;) {
ClientContext *c;
pthread_t tid;
int fd;
fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (fd < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
r = log_error_errno(errno, "accept4() failed: %m");
break;
}
r = client_context_new(&c, fd);
if (r < 0) {
log_oom();
close(fd);
continue;
}
r = pthread_create(&tid, &attr, run_client, c);
if (r < 0) {
log_error("Cannot spawn thread: %m");
client_context_free(c);
continue;
}
}
exit_attr:
pthread_attr_destroy(&attr);
exit:
return r;
}
static int help(void) { static int help(void) {
printf("%s [OPTIONS...]\n\n" printf("%s [OPTIONS...]\n\n"
"Connect STDIO or a socket to a given bus address.\n\n" "DBus proxy server.\n\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n" " --version Show package version\n"
" --drop-privileges Drop privileges\n"
" --configuration=PATH Configuration file or directory\n" " --configuration=PATH Configuration file or directory\n"
" --machine=MACHINE Connect to specified machine\n" " --machine=MACHINE Connect to specified machine\n"
" --address=ADDRESS Connect to the bus specified by ADDRESS\n" " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
@ -78,7 +182,6 @@ static int parse_argv(int argc, char *argv[]) {
enum { enum {
ARG_VERSION = 0x100, ARG_VERSION = 0x100,
ARG_ADDRESS, ARG_ADDRESS,
ARG_DROP_PRIVILEGES,
ARG_CONFIGURATION, ARG_CONFIGURATION,
ARG_MACHINE, ARG_MACHINE,
}; };
@ -87,7 +190,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION }, { "version", no_argument, NULL, ARG_VERSION },
{ "address", required_argument, NULL, ARG_ADDRESS }, { "address", required_argument, NULL, ARG_ADDRESS },
{ "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES },
{ "configuration", required_argument, NULL, ARG_CONFIGURATION }, { "configuration", required_argument, NULL, ARG_CONFIGURATION },
{ "machine", required_argument, NULL, ARG_MACHINE }, { "machine", required_argument, NULL, ARG_MACHINE },
{}, {},
@ -123,10 +225,6 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
} }
case ARG_DROP_PRIVILEGES:
arg_drop_privileges = true;
break;
case ARG_CONFIGURATION: case ARG_CONFIGURATION:
r = strv_extend(&arg_configuration, optarg); r = strv_extend(&arg_configuration, optarg);
if (r < 0) if (r < 0)
@ -162,11 +260,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option"); assert_not_reached("Unhandled option");
} }
/* If the first command line argument is only "x" characters if (argc > optind) {
* we'll write who we are talking to into it, so that "ps" is
* explanatory */
arg_command_line_buffer = argv[optind];
if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
log_error("Too many arguments"); log_error("Too many arguments");
return -EINVAL; return -EINVAL;
} }
@ -180,78 +274,8 @@ static int parse_argv(int argc, char *argv[]) {
return 1; return 1;
} }
static int rename_service(sd_bus *a, sd_bus *b) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_free_ char *p = NULL, *name = NULL;
const char *comm;
char **cmdline;
uid_t uid;
pid_t pid;
int r;
assert(a);
assert(b);
r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
if (r < 0)
return r;
r = sd_bus_creds_get_uid(creds, &uid);
if (r < 0)
return r;
r = sd_bus_creds_get_pid(creds, &pid);
if (r < 0)
return r;
r = sd_bus_creds_get_cmdline(creds, &cmdline);
if (r < 0)
return r;
r = sd_bus_creds_get_comm(creds, &comm);
if (r < 0)
return r;
name = uid_to_name(uid);
if (!name)
return -ENOMEM;
p = strv_join(cmdline, " ");
if (!p)
return -ENOMEM;
/* The status string gets the full command line ... */
sd_notifyf(false,
"STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
pid, p,
uid, name);
/* ... and the argv line only the short comm */
if (arg_command_line_buffer) {
size_t m, w;
m = strlen(arg_command_line_buffer);
w = snprintf(arg_command_line_buffer, m,
"[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
pid, comm,
uid, name);
if (m > w)
memzero(arg_command_line_buffer + w, m - w);
}
log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
pid, p,
uid, name,
a->unique_name);
return 0;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
_cleanup_(proxy_freep) Proxy *p = NULL; int r, accept_fd;
int r, in_fd, out_fd;
uid_t original_uid;
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_parse_environment(); log_parse_environment();
@ -262,52 +286,19 @@ int main(int argc, char *argv[]) {
goto finish; goto finish;
r = sd_listen_fds(0); r = sd_listen_fds(0);
if (r == 0) { if (r != 1) {
in_fd = STDIN_FILENO;
out_fd = STDOUT_FILENO;
} else if (r == 1) {
in_fd = SD_LISTEN_FDS_START;
out_fd = SD_LISTEN_FDS_START;
} else {
log_error("Illegal number of file descriptors passed"); log_error("Illegal number of file descriptors passed");
goto finish; goto finish;
} }
original_uid = getuid(); accept_fd = SD_LISTEN_FDS_START;
r = fd_nonblock(accept_fd, false);
if (arg_drop_privileges) { if (r < 0) {
const char *user = "systemd-bus-proxy"; log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
uid_t uid; goto finish;
gid_t gid;
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Cannot resolve user name %s: %m", user);
goto finish;
}
r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
if (r < 0)
goto finish;
} }
r = proxy_new(&p, in_fd, out_fd, arg_address); r = loop_clients(accept_fd);
if (r < 0)
goto finish;
r = proxy_load_policy(p, arg_configuration);
if (r < 0)
goto finish;
r = proxy_hello_policy(p, original_uid);
if (r < 0)
goto finish;
r = rename_service(p->dest_bus, p->local_bus);
if (r < 0)
log_debug_errno(r, "Failed to rename process: %m");
r = proxy_run(p);
finish: finish:
sd_notify(false, sd_notify(false,

4
units/.gitignore vendored
View File

@ -1,4 +1,4 @@
/systemd-bus-proxyd@.service.m4 /systemd-bus-proxyd.service.m4
/user@.service.m4 /user@.service.m4
/console-getty.service /console-getty.service
/console-getty.service.m4 /console-getty.service.m4
@ -24,7 +24,7 @@
/systemd-backlight@.service /systemd-backlight@.service
/systemd-binfmt.service /systemd-binfmt.service
/systemd-bootchart.service /systemd-bootchart.service
/systemd-bus-proxyd@.service /systemd-bus-proxyd.service
/systemd-firstboot.service /systemd-firstboot.service
/systemd-fsck-root.service /systemd-fsck-root.service
/systemd-fsck@.service /systemd-fsck@.service

View File

@ -9,8 +9,11 @@
Description=Legacy D-Bus Protocol Compatibility Daemon Description=Legacy D-Bus Protocol Compatibility Daemon
[Service] [Service]
# The first argument will be replaced by the service by information on ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus
# the process requesting the proxy, we need a placeholder to keep the
# space available for this.
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NotifyAccess=main NotifyAccess=main
CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN )
PrivateTmp=yes
PrivateDevices=yes
PrivateNetwork=yes
ProtectSystem=full
ProtectHome=yes

View File

@ -10,4 +10,3 @@ Description=Legacy D-Bus Protocol Compatibility Socket
[Socket] [Socket]
ListenStream=/var/run/dbus/system_bus_socket ListenStream=/var/run/dbus/system_bus_socket
Accept=yes

View File

@ -1,22 +0,0 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Legacy D-Bus Protocol Compatibility Daemon
[Service]
# The first argument will be replaced by the service by information on
# the process requesting the proxy, we need a placeholder to keep the
# space available for this.
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --drop-privileges --address=kernel:path=/sys/fs/kdbus/0-system/bus xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NotifyAccess=main
CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN )
PrivateTmp=yes
PrivateDevices=yes
PrivateNetwork=yes
ProtectSystem=full
ProtectHome=yes

View File

@ -1,3 +1,3 @@
/systemd-exit.service /systemd-exit.service
/systemd-bus-proxyd@.service /systemd-bus-proxyd.service
/systemd-consoled.service /systemd-consoled.service

View File

@ -0,0 +1,13 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Legacy D-Bus Protocol Compatibility Daemon
[Service]
ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus
NotifyAccess=main

View File

@ -10,4 +10,3 @@ Description=Legacy D-Bus Protocol Compatibility Socket
[Socket] [Socket]
ListenStream=%t/bus ListenStream=%t/bus
Accept=yes