logind: when we cannot attach a passed fd to a device, close it

Replaces: #8532
This commit is contained in:
Lennart Poettering
2019-04-02 11:52:58 +02:00
parent 883d1b01b0
commit efc19ee485
+62 -62
View File
@@ -378,73 +378,75 @@ static int parse_fdname(const char *fdname, char **session_id, dev_t *dev) {
return 0;
}
static int deliver_fd(Manager *m, const char *fdname, int fd) {
_cleanup_free_ char *id = NULL;
SessionDevice *sd;
struct stat st;
Session *s;
dev_t dev;
int r;
assert(m);
assert(fd >= 0);
r = parse_fdname(fdname, &id, &dev);
if (r < 0)
return log_debug_errno(r, "Failed to parse fd name %s: %m", fdname);
s = hashmap_get(m->sessions, id);
if (!s)
/* If the session doesn't exist anymore, the associated session device attached to this fd
* doesn't either. Let's simply close this fd. */
return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Failed to attach fd for unknown session: %s", id);
if (fstat(fd, &st) < 0)
/* The device is allowed to go away at a random point, in which case fstat() failing is
* expected. */
return log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id);
if (!S_ISCHR(st.st_mode) || st.st_rdev != dev)
return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "Device fd doesn't point to the expected character device node");
sd = hashmap_get(s->devices, &dev);
if (!sd)
/* Weird, we got an fd for a session device which wasn't recorded in the session state
* file... */
return log_warning_errno(SYNTHETIC_ERRNO(ENODEV), "Got fd for missing session device [%u:%u] in session %s",
major(dev), minor(dev), s->id);
log_debug("Attaching fd to session device [%u:%u] for session %s",
major(dev), minor(dev), s->id);
session_device_attach_fd(sd, fd, s->was_active);
return 0;
}
static int manager_attach_fds(Manager *m) {
_cleanup_strv_free_ char **fdnames = NULL;
int n, i, fd;
int n;
/* Upon restart, PID1 will send us back all fds of session devices
* that we previously opened. Each file descriptor is associated
* with a given session. The session ids are passed through FDNAMES. */
/* Upon restart, PID1 will send us back all fds of session devices that we previously opened. Each
* file descriptor is associated with a given session. The session ids are passed through FDNAMES. */
n = sd_listen_fds_with_names(true, &fdnames);
if (n <= 0)
return n;
if (n < 0)
return log_warning_errno(n, "Failed to acquire passed fd list: %m");
if (n == 0)
return 0;
for (i = 0; i < n; i++) {
_cleanup_free_ char *id = NULL;
dev_t dev;
struct stat st;
SessionDevice *sd;
Session *s;
int r;
for (int i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i;
fd = SD_LISTEN_FDS_START + i;
r = parse_fdname(fdnames[i], &id, &dev);
if (r < 0) {
log_debug_errno(r, "Failed to parse fd name %s: %m", fdnames[i]);
close_nointr(fd);
if (deliver_fd(m, fdnames[i], fd) >= 0)
continue;
}
s = hashmap_get(m->sessions, id);
if (!s) {
/* If the session doesn't exist anymore, the associated session
* device attached to this fd doesn't either. Let's simply close
* this fd. */
log_debug("Failed to attach fd for unknown session: %s", id);
close_nointr(fd);
continue;
}
/* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd */
safe_close(fd);
if (fstat(fd, &st) < 0) {
/* The device is allowed to go away at a random point, in which
* case fstat failing is expected. */
log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id);
close_nointr(fd);
continue;
}
if (!S_ISCHR(st.st_mode) || st.st_rdev != dev) {
log_debug("Device fd doesn't point to the expected character device node");
close_nointr(fd);
continue;
}
sd = hashmap_get(s->devices, &dev);
if (!sd) {
/* Weird, we got an fd for a session device which wasn't
* recorded in the session state file... */
log_warning("Got fd for missing session device [%u:%u] in session %s",
major(dev), minor(dev), s->id);
close_nointr(fd);
continue;
}
log_debug("Attaching fd to session device [%u:%u] for session %s",
major(dev), minor(dev), s->id);
session_device_attach_fd(sd, fd, s->was_active);
/* Remove from fdstore as well */
(void) sd_notifyf(false,
"FDSTOREREMOVE=1\n"
"FDNAME=%s", fdnames[i]);
}
return 0;
@@ -492,11 +494,9 @@ static int manager_enumerate_sessions(Manager *m) {
r = k;
}
/* We might be restarted and PID1 could have sent us back the
* session device fds we previously saved. */
k = manager_attach_fds(m);
if (k < 0)
log_warning_errno(k, "Failed to reattach session device fds: %m");
/* We might be restarted and PID1 could have sent us back the session device fds we previously
* saved. */
(void) manager_attach_fds(m);
return r;
}