namespace: Clone root dir descriptor before use

Before doing anything with the root directory file descriptor, let's
make sure we clone it first so that the caller can't mess with mount fd
attributes via mount_setattr() anymore.

We clone during parsing instead of in executor so that the caller can't
mess with the mount fd between invocations.
This commit is contained in:
Daan De Meyer
2025-12-14 11:32:06 +01:00
parent 273c6bc045
commit 5eb0639faa
3 changed files with 39 additions and 8 deletions
+30 -7
View File
@@ -502,16 +502,13 @@ static int bus_set_transient_exec_context_fd(
assert(name);
assert(p);
assert(b);
assert(verify_mode == O_DIRECTORY || (verify_mode & ~O_ACCMODE_STRICT) == 0);
assert((verify_mode & ~O_ACCMODE_STRICT) == 0);
r = sd_bus_message_read(message, "h", &fd);
if (r < 0)
return r;
if (verify_mode == O_DIRECTORY)
r = fd_verify_directory(fd);
else
r = fd_vet_accmode(fd, verify_mode);
r = fd_vet_accmode(fd, verify_mode);
if (r < 0)
return sd_bus_error_set_errnof(reterr_error, r, "%s passed is of incompatible type: %m", name);
@@ -813,8 +810,34 @@ static int bus_service_set_transient_property(
return 1;
}
if (streq(name, "RootDirectoryFileDescriptor"))
return bus_set_transient_exec_context_fd(u, name, &s->root_directory_fd, &s->exec_context.root_directory_as_fd, O_DIRECTORY, message, flags, reterr_error);
if (streq(name, "RootDirectoryFileDescriptor")) {
int fd;
r = sd_bus_message_read(message, "h", &fd);
if (r < 0)
return r;
r = fd_verify_directory(fd);
if (r < 0)
return sd_bus_error_set_errnof(reterr_error, r, "RootDirectoryFileDescriptor= is not a directory: %m");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
int fd_clone;
/* Note that this invalidates the fd we got from the client. They won't be able to
* move_mount() it themselves. If they already move_mount()'ed it themselves, this
* will fail to clone the fd. */
fd_clone = mount_fd_clone(fd, /* recursive= */ true, /* replacement_fd= */ NULL);
if (fd_clone < 0)
return fd_clone;
/* We're closing our own clone here, which shouldn't need an asynchronous_close(). */
close_and_replace(s->root_directory_fd, fd_clone);
s->exec_context.root_directory_as_fd = true;
}
return 1;
}
return 0;
}
+1
View File
@@ -2877,6 +2877,7 @@ void exec_params_shallow_clear(ExecParameters *p) {
p->fd_names = strv_free(p->fd_names);
p->files_env = strv_free(p->files_env);
p->fds = mfree(p->fds);
p->root_directory_fd = safe_close(p->root_directory_fd);
p->exec_fd = safe_close(p->exec_fd);
p->user_lookup_fd = -EBADF;
p->bpf_restrict_fs_map_fd = -EBADF;
+8 -1
View File
@@ -1951,7 +1951,14 @@ static int service_spawn_internal(
exec_params.stdin_fd = s->stdin_fd;
exec_params.stdout_fd = s->stdout_fd;
exec_params.stderr_fd = s->stderr_fd;
exec_params.root_directory_fd = s->root_directory_fd;
if (s->root_directory_fd >= 0) {
r = mount_fd_clone(s->root_directory_fd, /* recursive= */ true, &s->root_directory_fd);
if (r < 0)
return r;
exec_params.root_directory_fd = r;
}
r = exec_spawn(UNIT(s),
c,