Skip to content

Commit 3180c4d

Browse files
YHNdnzjyuwata
authored andcommitted
logind: drop session fifo logic, rely solely on pidfd for exit notification
Traditionally, logind installed a fifo in the PAM session and used EOF on the fd as signal for session close. With the addition of pidfd (76f2191) however, logind tracks the leader process and the session is terminated as soon as that exits. I think the new behavior generally makes more sense, and the behavior got changed *in the mentioned commit already* without anyone ever showing up to complain. It hence feels safe to kill the concept now (also before the varlink interface gets rolled out). Note that the 'PID' field in CreateSession() Varlink method is now marked as strict, i.e. failure to acquire pidfd is immediately treated as fatal.
1 parent f630d17 commit 3180c4d

File tree

8 files changed

+48
-172
lines changed

8 files changed

+48
-172
lines changed

NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ CHANGES WITH 258 in spe:
7373
removed. Also, 'cryptolib' meson option has been deprecated, and will
7474
be removed in a future release.
7575

76+
* systemd-logind's session tracking, which used to be performed via
77+
fifo fd installed in the client, has been fully switched to be
78+
pidfd-based. The fd returned by CreateSession() and related calls
79+
is therefore unused. Moreover, the exit of session leader process
80+
will immediately cause the session to be stopped.
81+
7682
Announcements of Future Feature Removals:
7783

7884
* The D-Bus method org.freedesktop.systemd1.StartAuxiliaryScope() is

src/login/logind-dbus.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,9 @@ static int manager_create_session_by_bus(
11131113
if (leader.pid == 1 || pidref_is_self(&leader))
11141114
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
11151115

1116+
if (leader.fd < 0)
1117+
return sd_bus_error_set_errnof(error, EUNATCH, "Leader PIDFD not available");
1118+
11161119
SessionType t;
11171120
if (isempty(type))
11181121
t = _SESSION_TYPE_INVALID;

src/login/logind-session-dbus.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: LGPL-2.1-or-later */
22

33
#include <errno.h>
4+
#include <sys/eventfd.h>
45

56
#include "alloc-util.h"
67
#include "bus-common-errors.h"
@@ -912,25 +913,23 @@ int session_send_create_reply_bus(Session *s, const sd_bus_error *error) {
912913
if (sd_bus_error_is_set(error))
913914
return sd_bus_reply_method_error(c, error);
914915

915-
_cleanup_close_ int fifo_fd = session_create_fifo(s);
916-
if (fifo_fd < 0)
917-
return fifo_fd;
918-
919-
/* Update the session state file before we notify the client about the result. */
920-
session_save(s);
916+
/* Prior to v258, logind tracked sessions by installing a fifo in client and subscribe to its EOF.
917+
* Now we can fully rely on pidfd for this, but still need to return *something* to the client.
918+
* Allocate something lightweight and isolated as placeholder. */
919+
_cleanup_close_ int fd = eventfd(0, EFD_CLOEXEC);
920+
if (fd < 0)
921+
return -errno;
921922

922923
_cleanup_free_ char *p = session_bus_path(s);
923924
if (!p)
924925
return -ENOMEM;
925926

926927
log_debug("Sending D-Bus reply about created session: "
927-
"id=%s object_path=%s uid=" UID_FMT " runtime_path=%s "
928-
"session_fd=%d seat=%s vtnr=%u",
928+
"id=%s object_path=%s uid=" UID_FMT " runtime_path=%s seat=%s vtnr=%u",
929929
s->id,
930930
p,
931931
s->user->user_record->uid,
932932
s->user->runtime_path,
933-
fifo_fd,
934933
s->seat ? s->seat->id : "",
935934
s->vtnr);
936935

@@ -939,7 +938,7 @@ int session_send_create_reply_bus(Session *s, const sd_bus_error *error) {
939938
s->id,
940939
p,
941940
s->user->runtime_path,
942-
fifo_fd,
941+
fd, /* not really used - see comments above */
943942
(uint32_t) s->user->user_record->uid,
944943
s->seat ? s->seat->id : "",
945944
(uint32_t) s->vtnr,

src/login/logind-session.c

Lines changed: 21 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444

4545
#define RELEASE_USEC (20*USEC_PER_SEC)
4646

47-
static void session_remove_fifo(Session *s);
4847
static void session_restore_vt(Session *s);
4948

5049
int session_new(Manager *m, const char *id, Session **ret) {
@@ -66,7 +65,6 @@ int session_new(Manager *m, const char *id, Session **ret) {
6665
.manager = m,
6766
.id = strdup(id),
6867
.state_file = path_join("/run/systemd/sessions/", id),
69-
.fifo_fd = -EBADF,
7068
.vtfd = -EBADF,
7169
.audit_id = AUDIT_SESSION_INVALID,
7270
.tty_validity = _TTY_VALIDITY_INVALID,
@@ -107,11 +105,9 @@ static int session_watch_pidfd(Session *s) {
107105
assert(s);
108106
assert(s->manager);
109107
assert(pidref_is_set(&s->leader));
108+
assert(s->leader.fd >= 0);
110109
assert(!s->leader_pidfd_event_source);
111110

112-
if (s->leader.fd < 0)
113-
return 0;
114-
115111
r = sd_event_add_io(s->manager->event, &s->leader_pidfd_event_source, s->leader.fd, EPOLLIN, session_dispatch_leader_pidfd, s);
116112
if (r < 0)
117113
return r;
@@ -209,12 +205,7 @@ Session* session_free(Session *s) {
209205

210206
hashmap_remove(s->manager->sessions, s->id);
211207

212-
sd_event_source_unref(s->fifo_event_source);
213-
safe_close(s->fifo_fd);
214-
215-
/* Note that we remove neither the state file nor the fifo path here, since we want both to survive
216-
* daemon restarts */
217-
free(s->fifo_path);
208+
/* Note that we don't remove the state file here, since it's supposed to survive daemon restarts */
218209
free(s->state_file);
219210
free(s->id);
220211

@@ -237,6 +228,7 @@ int session_set_leader_consume(Session *s, PidRef _leader) {
237228

238229
assert(s);
239230
assert(pidref_is_set(&pidref));
231+
assert(pidref.fd >= 0);
240232

241233
if (pidref_equal(&s->leader, &pidref))
242234
return 0;
@@ -332,9 +324,6 @@ int session_save(Session *s) {
332324
if (s->scope_job)
333325
fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
334326

335-
if (s->fifo_path)
336-
fprintf(f, "FIFO=%s\n", s->fifo_path);
337-
338327
if (s->seat)
339328
fprintf(f, "SEAT=%s\n", s->seat->id);
340329

@@ -486,7 +475,8 @@ int session_load(Session *s) {
486475
*controller = NULL,
487476
*active = NULL,
488477
*devices = NULL,
489-
*is_display = NULL;
478+
*is_display = NULL,
479+
*fifo_path = NULL; /* compat only, not used */
490480

491481
int k, r;
492482

@@ -496,7 +486,7 @@ int session_load(Session *s) {
496486
"REMOTE", &remote,
497487
"SCOPE", &s->scope,
498488
"SCOPE_JOB", &s->scope_job,
499-
"FIFO", &s->fifo_path,
489+
"FIFO", &fifo_path,
500490
"SEAT", &seat,
501491
"TTY", &s->tty,
502492
"TTY_VALIDITY", &tty_validity,
@@ -615,19 +605,10 @@ int session_load(Session *s) {
615605
if (streq_ptr(state, "closing"))
616606
s->stopping = true;
617607

618-
if (s->fifo_path) {
619-
int fd;
620-
621-
/* If we open an unopened pipe for reading we will not
622-
get an EOF. to trigger an EOF we hence open it for
623-
writing, but close it right away which then will
624-
trigger the EOF. This will happen immediately if no
625-
other process has the FIFO open for writing, i. e.
626-
when the session died before logind (re)started. */
627-
628-
fd = session_create_fifo(s);
629-
safe_close(fd);
630-
}
608+
/* logind before v258 used a fifo for session close notification. Since v258 we fully employ
609+
* pidfd for the job, hence just unlink the legacy fifo. */
610+
if (fifo_path)
611+
(void) unlink(fifo_path);
631612

632613
if (realtime)
633614
(void) deserialize_usec(realtime, &s->timestamp.realtime);
@@ -681,13 +662,19 @@ int session_load(Session *s) {
681662
_cleanup_(pidref_done) PidRef p = PIDREF_NULL;
682663

683664
r = pidref_set_pid(&p, s->deserialized_pid);
684-
if (r >= 0)
685-
r = session_set_leader_consume(s, TAKE_PIDREF(p));
686665
if (r < 0)
687-
log_warning_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
666+
return log_error_errno(r, "Failed to deserialize leader PID for session '%s': %m", s->id);
667+
if (p.fd < 0)
668+
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
669+
"Failed to acquire pidfd for session leader '" PID_FMT "', refusing.",
670+
p.pid);
671+
672+
r = session_set_leader_consume(s, TAKE_PIDREF(p));
673+
if (r < 0)
674+
return log_error_errno(r, "Failed to set leader PID for session '%s': %m", s->id);
688675
}
689676

690-
return r;
677+
return 0;
691678
}
692679

693680
int session_activate(Session *s) {
@@ -968,9 +955,6 @@ int session_stop(Session *s, bool force) {
968955
if (s->seat)
969956
seat_evict_position(s->seat, s);
970957

971-
/* We are going down, don't care about FIFOs anymore */
972-
session_remove_fifo(s);
973-
974958
/* Kill cgroup */
975959
r = session_stop_scope(s, force);
976960

@@ -1264,71 +1248,6 @@ int session_set_tty(Session *s, const char *tty) {
12641248
return 1;
12651249
}
12661250

1267-
static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
1268-
Session *s = ASSERT_PTR(userdata);
1269-
1270-
assert(s->fifo_fd == fd);
1271-
1272-
/* EOF on the FIFO means the session died abnormally. */
1273-
1274-
session_remove_fifo(s);
1275-
session_stop(s, /* force = */ false);
1276-
1277-
session_add_to_gc_queue(s);
1278-
1279-
return 1;
1280-
}
1281-
1282-
int session_create_fifo(Session *s) {
1283-
int r;
1284-
1285-
assert(s);
1286-
1287-
/* Create FIFO */
1288-
if (!s->fifo_path) {
1289-
r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
1290-
if (r < 0)
1291-
return r;
1292-
1293-
s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
1294-
if (!s->fifo_path)
1295-
return -ENOMEM;
1296-
1297-
if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1298-
return -errno;
1299-
}
1300-
1301-
/* Open reading side */
1302-
if (s->fifo_fd < 0) {
1303-
s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
1304-
if (s->fifo_fd < 0)
1305-
return -errno;
1306-
}
1307-
1308-
if (!s->fifo_event_source) {
1309-
r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
1310-
if (r < 0)
1311-
return r;
1312-
1313-
/* Let's make sure we noticed dead sessions before we process new bus requests (which might
1314-
* create new sessions). */
1315-
r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
1316-
if (r < 0)
1317-
return r;
1318-
}
1319-
1320-
/* Open writing side */
1321-
return RET_NERRNO(open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK));
1322-
}
1323-
1324-
static void session_remove_fifo(Session *s) {
1325-
assert(s);
1326-
1327-
s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1328-
s->fifo_fd = safe_close(s->fifo_fd);
1329-
s->fifo_path = unlink_and_free(s->fifo_path);
1330-
}
1331-
13321251
bool session_may_gc(Session *s, bool drop_not_started) {
13331252
int r;
13341253

@@ -1350,9 +1269,6 @@ bool session_may_gc(Session *s, bool drop_not_started) {
13501269
if (r > 0)
13511270
return false;
13521271

1353-
if (s->fifo_fd >= 0 && pipe_eof(s->fifo_fd) <= 0)
1354-
return false;
1355-
13561272
if (s->scope_job) {
13571273
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
13581274

@@ -1393,7 +1309,7 @@ SessionState session_get_state(Session *s) {
13931309
if (s->stopping || s->timer_event_source)
13941310
return SESSION_CLOSING;
13951311

1396-
if (s->scope_job || (!pidref_is_set(&s->leader) && s->fifo_fd < 0))
1312+
if (s->scope_job || !pidref_is_set(&s->leader))
13971313
return SESSION_OPENING;
13981314

13991315
if (session_is_active(s))

src/login/logind-session.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,6 @@ struct Session {
138138
pid_t deserialized_pid; /* PID deserialized from state file (for verification when pidfd is used) */
139139
uint32_t audit_id;
140140

141-
int fifo_fd;
142-
char *fifo_path;
143-
144-
sd_event_source *fifo_event_source;
145141
sd_event_source *leader_pidfd_event_source;
146142

147143
bool in_gc_queue;
@@ -194,7 +190,6 @@ void session_set_type(Session *s, SessionType t);
194190
void session_set_class(Session *s, SessionClass c);
195191
int session_set_display(Session *s, const char *display);
196192
int session_set_tty(Session *s, const char *tty);
197-
int session_create_fifo(Session *s);
198193
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
199194
int session_stop(Session *s, bool force);
200195
int session_finalize(Session *s);

src/login/logind-varlink.c

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,36 +101,18 @@ int session_send_create_reply_varlink(Session *s, const sd_bus_error *error) {
101101
if (sd_bus_error_is_set(error))
102102
return sd_varlink_error(vl, "io.systemd.Login.UnitAllocationFailed", /* parameters= */ NULL);
103103

104-
_cleanup_close_ int fifo_fd = session_create_fifo(s);
105-
if (fifo_fd < 0)
106-
return fifo_fd;
107-
108-
/* Update the session state file before we notify the client about the result. */
109-
session_save(s);
110-
111104
log_debug("Sending Varlink reply about created session: "
112-
"id=%s uid=" UID_FMT " runtime_path=%s "
113-
"session_fd=%d seat=%s vtnr=%u",
105+
"id=%s uid=" UID_FMT " runtime_path=%s seat=%s vtnr=%u",
114106
s->id,
115107
s->user->user_record->uid,
116108
s->user->runtime_path,
117-
fifo_fd,
118109
s->seat ? s->seat->id : "",
119110
s->vtnr);
120111

121-
int fifo_fd_idx = sd_varlink_push_fd(vl, fifo_fd);
122-
if (fifo_fd_idx < 0) {
123-
log_error_errno(fifo_fd_idx, "Failed to push FIFO fd to Varlink: %m");
124-
return sd_varlink_error_errno(vl, fifo_fd_idx);
125-
}
126-
127-
TAKE_FD(fifo_fd);
128-
129112
return sd_varlink_replybo(
130113
vl,
131114
SD_JSON_BUILD_PAIR_STRING("Id", s->id),
132115
SD_JSON_BUILD_PAIR_STRING("RuntimePath", s->user->runtime_path),
133-
SD_JSON_BUILD_PAIR_UNSIGNED("SessionFileDescriptor", fifo_fd_idx),
134116
SD_JSON_BUILD_PAIR_UNSIGNED("UID", s->user->user_record->uid),
135117
SD_JSON_BUILD_PAIR_CONDITION(!!s->seat, "Seat", SD_JSON_BUILD_STRING(s->seat ? s->seat->id : NULL)),
136118
SD_JSON_BUILD_PAIR_CONDITION(s->vtnr > 0, "VTNr", SD_JSON_BUILD_UNSIGNED(s->vtnr)),
@@ -167,7 +149,7 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
167149

168150
static const sd_json_dispatch_field dispatch_table[] = {
169151
{ "UID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(CreateSessionParameters, uid), SD_JSON_MANDATORY },
170-
{ "PID", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, offsetof(CreateSessionParameters, pid), SD_JSON_RELAX },
152+
{ "PID", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref, offsetof(CreateSessionParameters, pid), SD_JSON_STRICT },
171153
{ "Service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(CreateSessionParameters, service), 0 },
172154
{ "Type", SD_JSON_VARIANT_STRING, json_dispatch_session_type, offsetof(CreateSessionParameters, type), SD_JSON_MANDATORY },
173155
{ "Class", SD_JSON_VARIANT_STRING, json_dispatch_session_class, offsetof(CreateSessionParameters, class), SD_JSON_MANDATORY },
@@ -252,6 +234,9 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
252234
return log_debug_errno(r, "Failed to get peer pidref: %m");
253235
}
254236

237+
if (p.pid.fd < 0)
238+
return sd_varlink_error(link, "io.systemd.Login.NoSessionPIDFD", /* parameters= */ NULL);
239+
255240
Session *session;
256241
r = manager_create_session(
257242
m,

0 commit comments

Comments
 (0)