Skip to content

Commit

Permalink
Handle cases where the kernel incorrectly reports the filename for an…
Browse files Browse the repository at this point in the history
… execed binary is "/"

Resolves #3648
  • Loading branch information
rocallahan committed Nov 25, 2023
1 parent 9554df6 commit 18a1c1e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,7 @@ set(BASIC_TESTS
x86/modify_ldt
mount_ns_exec
mount_ns_exec2
mount_ns_execveat
mprotect
mprotect_heterogenous
mprotect_none
Expand Down
12 changes: 12 additions & 0 deletions src/record_syscall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5526,6 +5526,17 @@ static pair<remote_ptr<void>, remote_ptr<void>> get_exe_entry_interp_base(Task*
*/
static string try_make_process_file_name(RecordTask* t,
const std::string& file_name) {
if (file_name == "/") {
// The kernel sometimes returns "/" as the file name of a mapped
// segment. (We've seen this when the actual file was a bind-mount
// that has been opened with O_PATH and then lazily unmounted, then
// the O_PATH fd was execed with `execveat`.)
// In that case, we have no idea what the actual file is so
// return a name that will never work instead "/proc/.../root/"
// which can be stat(), causing confusion.
return "";
}

char proc_root[32];
// /proc/<pid>/root has magical properties; not only is it a link, but
// it links to a view of the filesystem as the process sees it, taking into
Expand Down Expand Up @@ -5703,6 +5714,7 @@ static void process_execve(RecordTask* t, TaskSyscallState& syscall_state) {
continue;
}
struct stat st;
// Maybe we should use /proc/.../map_files instead?
string file_name = try_make_process_file_name(t, km.fsname());
if (stat(file_name.c_str(), &st) != 0) {
st = km.fake_stat();
Expand Down
30 changes: 30 additions & 0 deletions src/test/mount_ns_execveat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */

#include "nsutils.h"
#include "util.h"

int main(int argc, char* argv[]) {
if ((argc > 1 && strcmp(argv[1], "in_copy") == 0) ||
-1 == try_setup_ns(CLONE_NEWNS)) {
atomic_puts("EXIT-SUCCESS");
return 0;
}

test_assert(0 == mkdir("mountpoint", 0700));
test_assert(0 == mount("none", "mountpoint", "tmpfs", 0, NULL));

int fd = open("mountpoint/the_copy", O_RDWR | O_CREAT | O_EXCL, 0600);
test_assert(fd >= 0);
test_assert(0 == close(fd));
test_assert(0 == mount(argv[0], "mountpoint/the_copy",
"", MS_BIND, NULL));
int dst_fd = open("mountpoint/the_copy", O_RDONLY | O_PATH);
test_assert(dst_fd != -1);

test_assert(0 == umount2("mountpoint/the_copy", MNT_DETACH));

char* const new_argv[] = { "mountpoint/the_copy", "in_copy", NULL };
execveat(dst_fd, "", new_argv, environ, AT_EMPTY_PATH);
test_assert(0);
return 1;
}

0 comments on commit 18a1c1e

Please sign in to comment.