Skip to content

Commit 3b3875e

Browse files
YHNdnzjbluca
andcommitted
core: reliably check if varlink socket has been deserialized
Follow-up for 6906c02 The mentioned commit uses access() to check if varlink socket already exists in the filesystem, but that isn't sufficient. > Varlink sockets are not serialized until v252, so upgrading from > v251 or older means we will not listen anymore on the varlink sockets. > > See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1074789 > for more details as this was found when updating from Debian Bullseye to a new version. After this commit, the set up of varlink_server is effectively split into two steps. manager_varlink_init_system(), which is called after deserialization, would no longer skip listening even if Manager.varlink_server is in place, but actually check if we're listening on desired sockets. Then, manager_deserialize() can be switched back to using manager_setup_varlink_server(). Alternative to #33817 Co-authored-by: Luca Boccassi <[email protected]> (cherry picked from commit d4e5c66) (cherry picked from commit b825a8b)
1 parent 5be64a5 commit 3b3875e

File tree

5 files changed

+76
-70
lines changed

5 files changed

+76
-70
lines changed

src/core/core-varlink.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "strv.h"
66
#include "user-util.h"
77
#include "varlink.h"
8+
#include "varlink-internal.h"
89
#include "varlink-io.systemd.UserDatabase.h"
910
#include "varlink-io.systemd.ManagedOOM.h"
1011

@@ -492,46 +493,42 @@ static void vl_disconnect(VarlinkServer *s, Varlink *link, void *userdata) {
492493
}
493494

494495
static int manager_varlink_init_system(Manager *m) {
495-
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
496496
int r;
497497

498498
assert(m);
499499

500-
if (m->varlink_server)
501-
return 1;
502-
503500
if (!MANAGER_IS_SYSTEM(m))
504501
return 0;
505502

506-
r = manager_setup_varlink_server(m, &s);
503+
r = manager_setup_varlink_server(m);
507504
if (r < 0)
508505
return log_error_errno(r, "Failed to set up varlink server: %m");
506+
bool fresh = r > 0;
509507

510508
if (!MANAGER_IS_TEST_RUN(m)) {
511509
(void) mkdir_p_label("/run/systemd/userdb", 0755);
512510

513511
FOREACH_STRING(address, "/run/systemd/userdb/io.systemd.DynamicUser", VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM) {
514-
if (MANAGER_IS_RELOADING(m)) {
515-
/* If manager is reloading, we skip listening on existing addresses, since
516-
* the fd should be acquired later through deserialization. */
517-
if (access(address, F_OK) >= 0)
512+
if (!fresh) {
513+
/* We might have got sockets through deserialization. Do not bind to them twice. */
514+
515+
bool found = false;
516+
LIST_FOREACH(sockets, ss, m->varlink_server->sockets)
517+
if (path_equal(ss->address, address)) {
518+
found = true;
519+
break;
520+
}
521+
522+
if (found)
518523
continue;
519-
if (errno != ENOENT)
520-
return log_error_errno(errno,
521-
"Failed to check if varlink socket '%s' exists: %m", address);
522524
}
523525

524-
r = varlink_server_listen_address(s, address, 0666);
526+
r = varlink_server_listen_address(m->varlink_server, address, 0666);
525527
if (r < 0)
526528
return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address);
527529
}
528530
}
529531

530-
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
531-
if (r < 0)
532-
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
533-
534-
m->varlink_server = TAKE_PTR(s);
535532
return 1;
536533
}
537534

@@ -597,12 +594,17 @@ static int manager_varlink_init_user(Manager *m) {
597594
return 1;
598595
}
599596

600-
int manager_setup_varlink_server(Manager *m, VarlinkServer **ret) {
597+
int manager_setup_varlink_server(Manager *m) {
601598
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
602599
int r;
603600

604601
assert(m);
605-
assert(ret);
602+
603+
if (m->varlink_server)
604+
return 0;
605+
606+
if (!MANAGER_IS_SYSTEM(m))
607+
return -EINVAL;
606608

607609
r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
608610
if (r < 0)
@@ -630,8 +632,12 @@ int manager_setup_varlink_server(Manager *m, VarlinkServer **ret) {
630632
if (r < 0)
631633
return log_debug_errno(r, "Failed to register varlink disconnect handler: %m");
632634

633-
*ret = TAKE_PTR(s);
634-
return 0;
635+
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
636+
if (r < 0)
637+
return log_debug_errno(r, "Failed to attach varlink connection to event loop: %m");
638+
639+
m->varlink_server = TAKE_PTR(s);
640+
return 1;
635641
}
636642

637643
int manager_varlink_init(Manager *m) {

src/core/core-varlink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ void manager_varlink_done(Manager *m);
88

99
/* Creates a new VarlinkServer and binds methods. Does not set up sockets or attach events.
1010
* Used for manager serialize/deserialize. */
11-
int manager_setup_varlink_server(Manager *m, VarlinkServer **ret_s);
11+
int manager_setup_varlink_server(Manager *m);
1212

1313
/* The manager is expected to send an update to systemd-oomd if one of the following occurs:
1414
* - The value of ManagedOOM*= properties change

src/core/manager-serialize.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
499499
return -ENOMEM;
500500
} else if ((val = startswith(l, "varlink-server-socket-address="))) {
501501
if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) {
502-
r = manager_varlink_init(m);
502+
r = manager_setup_varlink_server(m);
503503
if (r < 0) {
504504
log_warning_errno(r, "Failed to setup varlink server, ignoring: %m");
505505
continue;

src/shared/varlink-internal.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,51 @@
66
#include "fdset.h"
77
#include "varlink.h"
88

9+
typedef struct VarlinkServerSocket VarlinkServerSocket;
10+
11+
struct VarlinkServerSocket {
12+
VarlinkServer *server;
13+
14+
int fd;
15+
char *address;
16+
17+
sd_event_source *event_source;
18+
19+
LIST_FIELDS(VarlinkServerSocket, sockets);
20+
};
21+
22+
struct VarlinkServer {
23+
unsigned n_ref;
24+
VarlinkServerFlags flags;
25+
26+
LIST_HEAD(VarlinkServerSocket, sockets);
27+
28+
Hashmap *methods; /* Fully qualified symbol name of a method → VarlinkMethod */
29+
Hashmap *interfaces; /* Fully qualified interface name → VarlinkInterface* */
30+
Hashmap *symbols; /* Fully qualified symbol name of method/error → VarlinkSymbol* */
31+
VarlinkConnect connect_callback;
32+
VarlinkDisconnect disconnect_callback;
33+
34+
sd_event *event;
35+
int64_t event_priority;
36+
37+
unsigned n_connections;
38+
Hashmap *by_uid; /* UID_TO_PTR(uid) → UINT_TO_PTR(n_connections) */
39+
40+
void *userdata;
41+
char *description;
42+
43+
unsigned connections_max;
44+
unsigned connections_per_uid_max;
45+
46+
bool exit_on_idle;
47+
};
48+
49+
typedef struct VarlinkCollectContext {
50+
JsonVariant *parameters;
51+
const char *error_id;
52+
VarlinkReplyFlags flags;
53+
} VarlinkCollectContext ;
54+
955
int varlink_server_serialize(VarlinkServer *s, FILE *f, FDSet *fds);
1056
int varlink_server_deserialize_one(VarlinkServer *s, const char *value, FDSet *fds);

src/shared/varlink.c

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -201,52 +201,6 @@ struct Varlink {
201201
pid_t exec_pid;
202202
};
203203

204-
typedef struct VarlinkServerSocket VarlinkServerSocket;
205-
206-
struct VarlinkServerSocket {
207-
VarlinkServer *server;
208-
209-
int fd;
210-
char *address;
211-
212-
sd_event_source *event_source;
213-
214-
LIST_FIELDS(VarlinkServerSocket, sockets);
215-
};
216-
217-
struct VarlinkServer {
218-
unsigned n_ref;
219-
VarlinkServerFlags flags;
220-
221-
LIST_HEAD(VarlinkServerSocket, sockets);
222-
223-
Hashmap *methods; /* Fully qualified symbol name of a method → VarlinkMethod */
224-
Hashmap *interfaces; /* Fully qualified interface name → VarlinkInterface* */
225-
Hashmap *symbols; /* Fully qualified symbol name of method/error → VarlinkSymbol* */
226-
VarlinkConnect connect_callback;
227-
VarlinkDisconnect disconnect_callback;
228-
229-
sd_event *event;
230-
int64_t event_priority;
231-
232-
unsigned n_connections;
233-
Hashmap *by_uid; /* UID_TO_PTR(uid) → UINT_TO_PTR(n_connections) */
234-
235-
void *userdata;
236-
char *description;
237-
238-
unsigned connections_max;
239-
unsigned connections_per_uid_max;
240-
241-
bool exit_on_idle;
242-
};
243-
244-
typedef struct VarlinkCollectContext {
245-
JsonVariant *parameters;
246-
const char *error_id;
247-
VarlinkReplyFlags flags;
248-
} VarlinkCollectContext ;
249-
250204
static const char* const varlink_state_table[_VARLINK_STATE_MAX] = {
251205
[VARLINK_IDLE_CLIENT] = "idle-client",
252206
[VARLINK_AWAITING_REPLY] = "awaiting-reply",

0 commit comments

Comments
 (0)