diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c index 24288f09fd405b0f9dc9229b189f4e3a8ebb1d46..90ed82324f594c9be3c87923bf9fe09c1faedd1e 100644 --- a/pressure-vessel/runtime.c +++ b/pressure-vessel/runtime.c @@ -2084,8 +2084,8 @@ pv_runtime_take_from_provider (PvRuntime *self, if (flags & TAKE_FROM_PROVIDER_FLAGS_COPY_FALLBACK) { glnx_autofd int file_fd = -1; + glnx_autofd int dest_fd = -1; glnx_autofd int sysroot_fd = -1; - struct stat stat_buf; if (!glnx_opendirat (-1, self->provider_in_current_namespace, FALSE, &sysroot_fd, error)) @@ -2095,22 +2095,36 @@ pv_runtime_take_from_provider (PvRuntime *self, SRT_RESOLVE_FLAGS_READABLE, NULL, error); if (file_fd < 0) - return FALSE; - - if (fstat (file_fd, &stat_buf) != 0) { - return glnx_throw_errno_prefix (error, - "An error occurred using fstat for %s", - source_in_provider); + g_prefix_error (error, + "Unable to make \"%s\" available in container: ", + source_in_provider); + return FALSE; } - g_autofree gchar *proc_fd = g_strdup_printf ("/proc/self/fd/%d", file_fd); + /* We already deleted ${parent_dirfd}/${base}, and we don't + * care about atomicity or durability here, so we can just + * write in-place. The permissions are uninteresting because + * we're not expecting other users to read this temporary + * sysroot anyway, so use 0600 just in case the source file + * has restrictive permissions. */ + dest_fd = TEMP_FAILURE_RETRY (openat (parent_dirfd, base, + O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT|O_EXCL, + 0600)); + + if (dest_fd < 0) + return glnx_throw_errno_prefix (error, + "Unable to open \"%s\" for writing", + dest_in_container); + if (glnx_regfile_copy_bytes (file_fd, dest_fd, (off_t) -1) < 0) + return glnx_throw_errno_prefix (error, + "Unable to copy contents of \"%s/%s\" to \"%s\"", + self->provider_in_current_namespace, + source_in_provider, + dest_in_container); - return glnx_file_copy_at (AT_FDCWD, proc_fd, &stat_buf, - parent_dirfd, base, - GLNX_FILE_COPY_OVERWRITE, - NULL, error); + return TRUE; } else { @@ -2461,9 +2475,11 @@ pv_runtime_take_ld_so_from_provider (PvRuntime *self, &ld_so_relative_to_provider, error); if (path_fd < 0) - return glnx_throw_errno_prefix (error, - "Unable to determine provider path to %s", - arch->ld_so); + { + g_prefix_error (error, "Unable to determine provider path to %s: ", + arch->ld_so); + return FALSE; + } ld_so_in_provider = g_build_filename (self->provider_in_host_namespace, ld_so_relative_to_provider, NULL); diff --git a/steam-runtime-tools/resolve-in-sysroot.c b/steam-runtime-tools/resolve-in-sysroot.c index 21965157ee34bc16262527ab77dfc6487fe2496e..c4dbb581d213483b9f20993ba2e05e7870ecbdba 100644 --- a/steam-runtime-tools/resolve-in-sysroot.c +++ b/steam-runtime-tools/resolve-in-sysroot.c @@ -313,12 +313,20 @@ _srt_resolve_in_sysroot (int sysroot, if (flags & SRT_RESOLVE_FLAGS_DIRECTORY) { if (!glnx_opendirat (-1, proc_fd_name, TRUE, &fd, error)) - return -1; + { + g_prefix_error (error, "Unable to open \"%s\" as directory: ", + current_path->str); + return -1; + } } else { if (!glnx_openat_rdonly (-1, proc_fd_name, TRUE, &fd, error)) - return -1; + { + g_prefix_error (error, "Unable to open \"%s\": ", + current_path->str); + return -1; + } } if (real_path_out != NULL) diff --git a/tests/pressure-vessel/resolve-in-sysroot.c b/tests/pressure-vessel/resolve-in-sysroot.c index b578399961d2f49bb6e2c7ad90b76a71c042243c..ec6e928a9ef5f7984be554c1a6bb5833115864db 100644 --- a/tests/pressure-vessel/resolve-in-sysroot.c +++ b/tests/pressure-vessel/resolve-in-sysroot.c @@ -120,6 +120,7 @@ test_resolve_in_sysroot (Fixture *f, { "a/b/symlink_to_c", "c" }, { "a/b/symlink_to_b2", "../b2" }, { "a/b/symlink_to_c2", "../../a/b2/c2" }, + { "a/b/symlink_to_itself", "." }, { "a/b/abs_symlink_to_run", "/run" }, { "a/b/long_symlink_to_dev", "../../../../../../../../../../../dev" }, { "x", "create_me" }, @@ -178,6 +179,15 @@ test_resolve_in_sysroot (Fixture *f, { { "a/b/symlink_to_b2" }, { "a/b2" } }, { { "a/b/symlink_to_c2" }, { "a/b2/c2" } }, { { "a/b/abs_symlink_to_run" }, { NULL, G_IO_ERROR_NOT_FOUND } }, + { + { "a/b/symlink_to_itself", SRT_RESOLVE_FLAGS_KEEP_FINAL_SYMLINK }, + { "a/b/symlink_to_itself" }, + }, + { + { "a/b/symlink_to_itself", + SRT_RESOLVE_FLAGS_KEEP_FINAL_SYMLINK|SRT_RESOLVE_FLAGS_READABLE }, + { NULL, G_IO_ERROR_TOO_MANY_LINKS }, + }, { { "a/b/abs_symlink_to_run", SRT_RESOLVE_FLAGS_KEEP_FINAL_SYMLINK }, { "a/b/abs_symlink_to_run" } @@ -282,6 +292,7 @@ test_resolve_in_sysroot (Fixture *f, else { g_assert_error (error, G_IO_ERROR, it->expect.code); + g_test_message ("Got error as expected: %s", error->message); g_assert_cmpint (fd, ==, -1); if (out_path != NULL)