diff options
Diffstat (limited to 'src/core/execute.c')
-rw-r--r-- | src/core/execute.c | 173 |
1 files changed, 166 insertions, 7 deletions
diff --git a/src/core/execute.c b/src/core/execute.c index 94c0e6a90d..ac3f096b0d 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -151,11 +151,14 @@ static int shift_fds(int fds[], size_t n_fds) { return 0; } -static int flags_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool nonblock) { - size_t n_fds; +static int flags_fds( + const int fds[], + size_t n_socket_fds, + size_t n_fds, + bool nonblock) { + int r; - n_fds = n_socket_fds + n_storage_fds; if (n_fds <= 0) return 0; @@ -1805,6 +1808,7 @@ static int build_environment( const ExecContext *c, const ExecParameters *p, size_t n_fds, + char **fdnames, const char *home, const char *username, const char *shell, @@ -1837,7 +1841,7 @@ static int build_environment( return -ENOMEM; our_env[n_env++] = x; - joined = strv_join(p->fd_names, ":"); + joined = strv_join(fdnames, ":"); if (!joined) return -ENOMEM; @@ -4105,6 +4109,123 @@ static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int fd, int return 1; } +static int connect_unix_harder(Unit *u, const OpenFile *of, int ofd) { + union sockaddr_union addr = { + .un.sun_family = AF_UNIX, + }; + socklen_t sa_len; + static const int socket_types[] = { SOCK_DGRAM, SOCK_STREAM, SOCK_SEQPACKET }; + int r; + + assert(u); + assert(of); + assert(ofd >= 0); + + r = sockaddr_un_set_path(&addr.un, FORMAT_PROC_FD_PATH(ofd)); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to set sockaddr for %s: %m", of->path); + + sa_len = r; + + for (size_t i = 0; i < ELEMENTSOF(socket_types); i++) { + _cleanup_close_ int fd = -EBADF; + + fd = socket(AF_UNIX, socket_types[i] | SOCK_CLOEXEC, 0); + if (fd < 0) + return log_unit_error_errno(u, errno, "Failed to create socket for %s: %m", of->path); + + r = RET_NERRNO(connect(fd, &addr.sa, sa_len)); + if (r == -EPROTOTYPE) + continue; + if (r < 0) + return log_unit_error_errno(u, r, "Failed to connect socket for %s: %m", of->path); + + return TAKE_FD(fd); + } + + return log_unit_error_errno(u, SYNTHETIC_ERRNO(EPROTOTYPE), "Failed to connect socket for \"%s\".", of->path); +} + +static int get_open_file_fd(Unit *u, const OpenFile *of) { + struct stat st; + _cleanup_close_ int fd = -EBADF, ofd = -EBADF; + + assert(u); + assert(of); + + ofd = open(of->path, O_PATH | O_CLOEXEC); + if (ofd < 0) + return log_error_errno(errno, "Could not open \"%s\": %m", of->path); + if (fstat(ofd, &st) < 0) + return log_error_errno(errno, "Failed to stat %s: %m", of->path); + + if (S_ISSOCK(st.st_mode)) { + fd = connect_unix_harder(u, of, ofd); + if (fd < 0) + return fd; + + if (FLAGS_SET(of->flags, OPENFILE_READ_ONLY) && shutdown(fd, SHUT_WR) < 0) + return log_error_errno(errno, "Failed to shutdown send for socket %s: %m", of->path); + + log_unit_debug(u, "socket %s opened (fd=%d)", of->path, fd); + } else { + int flags = FLAGS_SET(of->flags, OPENFILE_READ_ONLY) ? O_RDONLY : O_RDWR; + if (FLAGS_SET(of->flags, OPENFILE_APPEND)) + flags |= O_APPEND; + else if (FLAGS_SET(of->flags, OPENFILE_TRUNCATE)) + flags |= O_TRUNC; + + fd = fd_reopen(ofd, flags | O_CLOEXEC); + if (fd < 0) + return log_unit_error_errno(u, fd, "Failed to open file %s: %m", of->path); + + log_unit_debug(u, "file %s opened (fd=%d)", of->path, fd); + } + + return TAKE_FD(fd); +} + +static int collect_open_file_fds( + Unit *u, + OpenFile* open_files, + int **fds, + char ***fdnames, + size_t *n_fds) { + int r; + + assert(u); + assert(fds); + assert(fdnames); + assert(n_fds); + + LIST_FOREACH(open_files, of, open_files) { + _cleanup_close_ int fd = -EBADF; + + fd = get_open_file_fd(u, of); + if (fd < 0) { + if (FLAGS_SET(of->flags, OPENFILE_GRACEFUL)) { + log_unit_debug_errno(u, fd, "Failed to get OpenFile= file descriptor for %s, ignoring: %m", of->path); + continue; + } + + return fd; + } + + if (!GREEDY_REALLOC(*fds, *n_fds + 1)) + return -ENOMEM; + + r = strv_extend(fdnames, of->fdname); + if (r < 0) + return r; + + (*fds)[*n_fds] = TAKE_FD(fd); + + (*n_fds)++; + } + + return 0; +} + static int exec_child( Unit *unit, const ExecCommand *command, @@ -4114,7 +4235,7 @@ static int exec_child( DynamicCreds *dcreds, int socket_fd, const int named_iofds[static 3], - int *fds, + int *params_fds, size_t n_socket_fds, size_t n_storage_fds, char **files_env, @@ -4154,6 +4275,8 @@ static int exec_child( int secure_bits; _cleanup_free_ gid_t *gids_after_pam = NULL; int ngids_after_pam = 0; + _cleanup_free_ int *fds = NULL; + _cleanup_strv_free_ char **fdnames = NULL; assert(unit); assert(command); @@ -4196,6 +4319,24 @@ static int exec_child( /* In case anything used libc syslog(), close this here, too */ closelog(); + fds = newdup(int, params_fds, n_fds); + if (!fds) { + *exit_status = EXIT_MEMORY; + return log_oom(); + } + + fdnames = strv_copy((char**) params->fd_names); + if (!fdnames) { + *exit_status = EXIT_MEMORY; + return log_oom(); + } + + r = collect_open_file_fds(unit, params->open_files, &fds, &fdnames, &n_fds); + if (r < 0) { + *exit_status = EXIT_FDS; + return log_unit_error_errno(unit, r, "Failed to get OpenFile= file descriptors: %m"); + } + int keep_fds[n_fds + 3]; memcpy_safe(keep_fds, fds, n_fds * sizeof(int)); n_keep_fds = n_fds; @@ -4551,6 +4692,7 @@ static int exec_child( context, params, n_fds, + fdnames, home, username, shell, @@ -4766,7 +4908,7 @@ static int exec_child( /* If the user namespace was not set up above, try to do it now. * It's preferred to set up the user namespace later (after all other namespaces) so as not to be - * restricted by rules pertaining to combining user namspaces with other namespaces (e.g. in the + * restricted by rules pertaining to combining user namespaces with other namespaces (e.g. in the * case of mount namespaces being less privileged when the mount point list is copied from a * different user namespace). */ @@ -4843,7 +4985,7 @@ static int exec_child( if (r >= 0) r = shift_fds(fds, n_fds); if (r >= 0) - r = flags_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking); + r = flags_fds(fds, n_socket_fds, n_fds, context->non_blocking); if (r < 0) { *exit_status = EXIT_FDS; return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m"); @@ -5484,6 +5626,23 @@ int exec_context_destroy_credentials(const ExecContext *c, const char *runtime_p return 0; } +int exec_context_destroy_mount_ns_dir(Unit *u) { + _cleanup_free_ char *p = NULL; + + if (!u || !MANAGER_IS_SYSTEM(u->manager)) + return 0; + + p = path_join("/run/systemd/propagate/", u->id); + if (!p) + return -ENOMEM; + + /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent*/ + if (rmdir(p) < 0 && errno != ENOENT) + log_unit_debug_errno(u, errno, "Unable to remove propagation dir '%s', ignoring: %m", p); + + return 0; +} + static void exec_command_done(ExecCommand *c) { assert(c); |