summaryrefslogtreecommitdiff
path: root/src/core/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/execute.c')
-rw-r--r--src/core/execute.c173
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);