diff options
author | Mike Yuan <me@yhndnzj.com> | 2024-07-14 17:19:50 +0200 |
---|---|---|
committer | Mike Yuan <me@yhndnzj.com> | 2024-07-22 09:38:48 +0200 |
commit | 19eccb7667f316c94f08829809852158b6109528 (patch) | |
tree | 6d2b4ad4d62fdeafd09217907b2c17c302b45e7a /src/core/manager.c | |
parent | missing_socket: add SCM_PASSPIDFD and SCM_PIDFD (diff) | |
download | systemd-19eccb7667f316c94f08829809852158b6109528.tar.xz systemd-19eccb7667f316c94f08829809852158b6109528.zip |
core: pin notify sender through pidfd (potentially SCM_PIDFD)
Diffstat (limited to 'src/core/manager.c')
-rw-r--r-- | src/core/manager.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/src/core/manager.c b/src/core/manager.c index b8de50c2c0..39fbbfa470 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1104,6 +1104,11 @@ static int manager_setup_notify(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to enable SO_PASSCRED for notify socket: %m"); + r = setsockopt_int(fd, SOL_SOCKET, SO_PASSPIDFD, true); + if (r < 0 && r != -ENOPROTOOPT) + log_warning_errno(r, "Failed to enable SO_PASSPIDFD for notify socket, ignoring: %m"); + // TODO: maybe enforce SO_PASSPIDFD? + m->notify_fd = TAKE_FD(fd); log_debug("Using notification socket %s", m->notify_socket); @@ -2638,13 +2643,16 @@ static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) { static void manager_invoke_notify_message( Manager *m, Unit *u, + PidRef *pidref, const struct ucred *ucred, char * const *tags, FDSet *fds) { assert(m); assert(u); + assert(pidref_is_set(pidref)); assert(ucred); + assert(pidref->pid == ucred->pid); assert(tags); if (u->notifygen == m->notifygen) /* Already invoked on this same unit in this same iteration? */ @@ -2652,7 +2660,7 @@ static void manager_invoke_notify_message( u->notifygen = m->notifygen; if (UNIT_VTABLE(u)->notify_message) - UNIT_VTABLE(u)->notify_message(u, ucred, tags, fds); + UNIT_VTABLE(u)->notify_message(u, pidref, ucred, tags, fds); else if (DEBUG_LOGGING) { _cleanup_free_ char *joined = strv_join(tags, ", "); @@ -2723,7 +2731,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t .iov_base = buf, .iov_len = sizeof(buf)-1, }; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + + CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int)) /* SCM_PIDFD */ + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control; struct msghdr msghdr = { .msg_iov = &iovec, @@ -2755,6 +2763,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t * socket. */ return log_error_errno(n, "Failed to receive notification message: %m"); + _cleanup_close_ int pidfd = -EBADF; struct ucred *ucred = NULL; int *fd_array = NULL; size_t n_fds = 0; @@ -2773,6 +2782,9 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t assert(!ucred); ucred = CMSG_TYPED_DATA(cmsg, struct ucred); + } else if (cmsg->cmsg_type == SCM_PIDFD) { + assert(pidfd < 0); + pidfd = *CMSG_TYPED_DATA(cmsg, int); } } @@ -2794,6 +2806,28 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + + if (pidfd >= 0) + r = pidref_set_pidfd_consume(&pidref, TAKE_FD(pidfd)); + else + r = pidref_set_pid(&pidref, ucred->pid); + if (r < 0) { + if (r == -ESRCH) + log_debug_errno(r, "Notify sender died before message is processed. Ignoring."); + else + log_warning_errno(r, "Failed to pin notify sender, ignoring message: %m"); + return 0; + } + + if (pidref.pid != ucred->pid) { + assert(pidref.fd >= 0); + + log_warning("Got SCM_PIDFD for process " PID_FMT " but SCM_CREDENTIALS for process " PID_FMT ". Ignoring.", + pidref.pid, ucred->pid); + return 0; + } + if ((size_t) n >= sizeof(buf) || (msghdr.msg_flags & MSG_TRUNC)) { log_warning("Received notify message exceeded maximum size. Ignoring."); return 0; @@ -2824,9 +2858,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t /* Increase the generation counter used for filtering out duplicate unit invocations. */ m->notifygen++; - /* Generate lookup key from the PID (we have no pidfd here, after all) */ - PidRef pidref = PIDREF_MAKE_FROM_PID(ucred->pid); - /* Notify every unit that might be interested, which might be multiple. */ _cleanup_free_ Unit **array = NULL; @@ -2841,7 +2872,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t /* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle * duplicate units – making sure we only invoke each unit's handler once. */ FOREACH_ARRAY(u, array, n_array) - manager_invoke_notify_message(m, *u, ucred, tags, fds); + manager_invoke_notify_message(m, *u, &pidref, ucred, tags, fds); if (!fdset_isempty(fds)) log_warning("Got extra auxiliary fds with notification message, closing them."); |