Skip to content

Commit

Permalink
Add openat2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
multun authored and rocallahan committed Nov 25, 2023
1 parent c5abc07 commit dea5bc6
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 5 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,7 @@ set(BASIC_TESTS
numa
x86/old_fork
orphan_process
openat2
packet_mmap_disable
x86/patch_syscall_restart
pause
Expand Down
2 changes: 1 addition & 1 deletion src/AutoRemoteSyscalls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ void AutoRemoteSyscalls::check_syscall_result(long ret, int syscallno, bool allo
string extra_msg;
if (is_open_syscall(syscallno, arch())) {
extra_msg = " opening " + t->read_c_str(t->regs().arg1());
} else if (is_openat_syscall(syscallno, arch())) {
} else if (is_openat_syscall(syscallno, arch()) || is_openat2_syscall(syscallno, arch())) {
extra_msg = " opening " + t->read_c_str(t->regs().arg2());
} else if (is_mremap_syscall(syscallno, arch()) ||
is_mmap_syscall(syscallno, arch())) {
Expand Down
37 changes: 37 additions & 0 deletions src/preload/syscallbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,40 @@ static long sys_openat(struct syscall_info* call) {
return check_file_open_ok(call, ret, state);
}

#if defined(SYS_openat2)
static long sys_openat2(struct syscall_info* call) {
if (force_traced_syscall_for_chaos_mode()) {
/* Opening a FIFO could unblock a higher priority task */
return traced_raw_syscall(call);
}

const int syscallno = SYS_openat2;
int dirfd = call->args[0];
const char* pathname = (const char*)call->args[1];
struct open_how *how = (struct open_how *)call->args[2];
size_t how_size = call->args[3];

void* ptr;
long ret;

assert(syscallno == call->no);

if (!supported_open(pathname, how->flags)) {
return traced_raw_syscall(call);
}

ptr = prep_syscall();
if (!start_commit_buffered_syscall(syscallno, ptr, MAY_BLOCK)) {
return traced_raw_syscall(call);
}

ret = untraced_syscall4(syscallno, dirfd, pathname, how, how_size);
struct check_open_state state = capture_check_open_state();
ret = commit_raw_syscall(syscallno, ptr, ret);
return check_file_open_ok(call, ret, state);
}
#endif

#if defined(SYS_poll) || defined(SYS_ppoll)
/**
* Make this function external so desched_ticks.py can set a breakpoint on it.
Expand Down Expand Up @@ -4080,6 +4114,9 @@ case SYS_epoll_wait:
#endif
case SYS_epoll_pwait:
return sys_epoll_wait(call);
#if defined(SYS_openat2)
CASE(openat2);
#endif
#if defined(SYS_epoll_pwait2)
CASE(epoll_pwait2);
#endif
Expand Down
21 changes: 18 additions & 3 deletions src/record_syscall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4003,6 +4003,7 @@ static Switchable rec_prepare_syscall_arch(RecordTask* t,
case Arch::msync:
case Arch::open:
case Arch::openat:
case Arch::openat2:
case Arch::semop:
case Arch::semtimedop_time64:
case Arch::semtimedop:
Expand Down Expand Up @@ -6599,18 +6600,32 @@ static void rec_process_syscall_arch(RecordTask* t,
}

case Arch::open:
case Arch::openat: {
case Arch::openat:
case Arch::openat2: {
Registers r = t->regs();
if (r.syscall_failed()) {
uintptr_t path = syscallno == Arch::openat ? r.arg2() : r.orig_arg1();
uintptr_t path = syscallno == Arch::open ? r.orig_arg1() : r.arg2();
string pathname = t->read_c_str(remote_ptr<char>(path));
if (is_gcrypt_deny_file(pathname.c_str())) {
fake_gcrypt_file(t, &r);
t->set_regs(r);
}
} else {
int fd = r.syscall_result_signed();
int flags = syscallno == Arch::openat ? r.arg3() : r.arg2();

int flags;
switch (syscallno) {
case Arch::open:
flags = r.arg2();
break;
case Arch::openat:
flags = r.arg3();
break;
case Arch::openat2:
flags = t->read_mem(remote_ptr<int64_t>(r.arg3()));
break;
}

string pathname = handle_opened_file(t, fd, flags);
bool gcrypt = is_gcrypt_deny_file(pathname.c_str());
if (gcrypt || is_blacklisted_filename(pathname.c_str())) {
Expand Down
3 changes: 3 additions & 0 deletions src/replay_syscall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,9 @@ static void rep_process_syscall_arch(ReplayTask* t, ReplayTraceStep* step,
case Arch::openat:
handle_opened_files(t, t->regs().arg3());
break;
case Arch::openat2:
handle_opened_files(t, t->read_mem(remote_ptr<int64_t>(t->regs().arg3())));
break;
case Arch::open:
handle_opened_files(t, t->regs().arg2());
break;
Expand Down
2 changes: 1 addition & 1 deletion src/syscalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -1726,7 +1726,7 @@ def __init__(self, **kwargs):
fspick = UnsupportedSyscall(x86=433, x64=433, generic=433)
pidfd_open = EmulatedSyscall(x86=434, x64=434, generic=434)
clone3 = IrregularEmulatedSyscall(x86=435, x64=435, generic=435)
openat2 = UnsupportedSyscall(x86=437, x64=437, generic=437)
openat2 = IrregularEmulatedSyscall(x86=437, x64=437, generic=437)
pidfd_getfd = EmulatedSyscall(x86=438, x64=438, generic=438)
process_madvise = UnsupportedSyscall(x86=440, x64=440, generic=440)
epoll_pwait2 = IrregularEmulatedSyscall(x86=441, x64=441, generic=441)
Expand Down
48 changes: 48 additions & 0 deletions src/test/openat2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */

#include "util.h"

#include <fcntl.h> /* Definition of O_* and S_* constants */
#include <linux/openat2.h> /* Definition of RESOLVE_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
#include <errno.h>

#define TEST_DIR "test_dir"
#define FILENAME "foo"
#define REL_FILENAME "../" TEST_DIR "/" FILENAME

int main(void) {
mkdir(TEST_DIR, 0700);
int dirfd = open(TEST_DIR, O_DIRECTORY, 0755);
test_assert(dirfd > 0);

int filefd = openat(dirfd, FILENAME, O_CREAT | O_RDWR, 0600);
test_assert(filefd > 0);
test_assert(close(filefd) == 0);

struct open_how how = {0};
how.flags = O_CREAT | O_RDONLY;
how.mode = 0600;

how.resolve = RESOLVE_BENEATH;
filefd = syscall(SYS_openat2, dirfd, REL_FILENAME, &how, sizeof(how));
test_assert(filefd == -1);

// openat2 was introduced by Linux 5.6
// if the syscall isn't supported, return immediatly
if (errno == ENOSYS) {
atomic_puts("EXIT-SUCCESS");
return 0;
}

test_assert(errno == EXDEV);

how.resolve = 0;
filefd = syscall(SYS_openat2, dirfd, REL_FILENAME, &how, sizeof(how));
test_assert(filefd > 0);
test_assert(close(filefd) == 0);

atomic_puts("EXIT-SUCCESS");
return 0;
}

0 comments on commit dea5bc6

Please sign in to comment.