diff options
author | 2021-10-23 02:39:35 -0400 | |
---|---|---|
committer | 2021-10-23 18:18:03 -0400 | |
commit | 9b81814db56a02384e40f6e19576a4e9777628ac (patch) | |
tree | 6ecb906c4283f84abe7c4f47151a130053db0de6 /libsandbox | |
parent | tests: fix handling of srcdir vs abs_srcdir for dist creation (diff) | |
download | sandbox-9b81814db56a02384e40f6e19576a4e9777628ac.tar.gz sandbox-9b81814db56a02384e40f6e19576a4e9777628ac.tar.bz2 sandbox-9b81814db56a02384e40f6e19576a4e9777628ac.zip |
libsandbox: fix flags extraction for a few syscalls
While many syscalls follow similar patterns for dirfd & path handling,
the flags argument is less consistent -- it tends to be last with all
other arguments in between. As a result, a few syscalls were pulling
the wrong argument for the flags settings:
* fchmodat: the syscall interface has no flags at all
* fchownat: the flags come after uid & gid
* utimensat: the flags come after the timespec
These syscalls haven't been a problem in practice because no one ever
tries to chmod/chown/utimes on symlinks themselves.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'libsandbox')
-rw-r--r-- | libsandbox/trace.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/libsandbox/trace.c b/libsandbox/trace.c index 89bd591..7660d47 100644 --- a/libsandbox/trace.c +++ b/libsandbox/trace.c @@ -217,6 +217,7 @@ struct syscall_state { bool (*pre_check)(const char *func, const char *pathname, int dirfd); }; +/* Check syscall that only takes a path as its |ibase| argument. */ static bool _trace_check_syscall_C(struct syscall_state *state, int ibase) { char *path = do_peekstr(trace_arg(state->regs, ibase)); @@ -233,6 +234,7 @@ static bool _trace_check_syscall_C(struct syscall_state *state, int ibase) free(path); return ret; } +/* Check syscall that only takes a path as its first argument. */ static bool trace_check_syscall_C(struct syscall_state *state) { return _trace_check_syscall_C(state, 1); @@ -255,20 +257,24 @@ static bool __trace_check_syscall_DCF(struct syscall_state *state, int ibase, in free(path); return ret; } -static bool _trace_check_syscall_DCF(struct syscall_state *state, int ibase) +/* Check syscall that takes a dirfd & path starting at |ibase| argument, and flags at |fbase|. */ +static bool _trace_check_syscall_DCF(struct syscall_state *state, int ibase, int fbase) { - int flags = trace_arg(state->regs, ibase + 2); + int flags = trace_arg(state->regs, fbase); return __trace_check_syscall_DCF(state, ibase, flags); } +/* Check syscall that takes a dirfd, path, and flags as its first 3 arguments. */ static bool trace_check_syscall_DCF(struct syscall_state *state) { - return _trace_check_syscall_DCF(state, 1); + return _trace_check_syscall_DCF(state, 1, 3); } +/* Check syscall that takes a dirfd & path starting at |ibase| argument. */ static bool _trace_check_syscall_DC(struct syscall_state *state, int ibase) { return __trace_check_syscall_DCF(state, ibase, 0); } +/* Check syscall that takes a dirfd & path as its first 2 arguments (but no flags). */ static bool trace_check_syscall_DC(struct syscall_state *state) { return _trace_check_syscall_DC(state, 1); @@ -311,12 +317,13 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs) else if (nr == SB_NR_CHMOD) return trace_check_syscall_C (&state); else if (nr == SB_NR_CHOWN) return trace_check_syscall_C (&state); else if (nr == SB_NR_CREAT) return trace_check_syscall_C (&state); - else if (nr == SB_NR_FCHMODAT) return trace_check_syscall_DCF(&state); - else if (nr == SB_NR_FCHOWNAT) return trace_check_syscall_DCF(&state); + /* NB: Linux syscall does not have a flags argument. */ + else if (nr == SB_NR_FCHMODAT) return trace_check_syscall_DC (&state); + else if (nr == SB_NR_FCHOWNAT) return _trace_check_syscall_DCF(&state, 1, 5); else if (nr == SB_NR_FUTIMESAT) return trace_check_syscall_DC (&state); else if (nr == SB_NR_LCHOWN) return trace_check_syscall_C (&state); else if (nr == SB_NR_LINK) return _trace_check_syscall_C (&state, 2); - else if (nr == SB_NR_LINKAT) return _trace_check_syscall_DCF(&state, 3); + else if (nr == SB_NR_LINKAT) return _trace_check_syscall_DCF(&state, 3, 5); else if (nr == SB_NR_MKDIR) return trace_check_syscall_C (&state); else if (nr == SB_NR_MKDIRAT) return trace_check_syscall_DC (&state); else if (nr == SB_NR_MKNOD) return trace_check_syscall_C (&state); @@ -336,7 +343,7 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs) else if (nr == SB_NR_UNLINKAT) return trace_check_syscall_DCF(&state); else if (nr == SB_NR_UTIME) return trace_check_syscall_C (&state); else if (nr == SB_NR_UTIMES) return trace_check_syscall_C (&state); - else if (nr == SB_NR_UTIMENSAT) return _trace_check_syscall_DCF(&state, 1); + else if (nr == SB_NR_UTIMENSAT) return _trace_check_syscall_DCF(&state, 1, 4); else if (nr == SB_NR_ACCESS) { char *path = do_peekstr(trace_arg(regs, 1)); |