aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSv. Lockal <lockalsash@gmail.com>2024-01-27 10:44:55 +0000
committerMike Gilbert <floppym@gentoo.org>2024-01-27 13:04:16 -0500
commit1f7d3654498e17e0a91c83f57e6265e08628d5fe (patch)
tree07f1f2554f394aec8f1daa2631cc8fbab0fa6bd3
parentlibsandbox: stat the original path for EEXIST hackaround (diff)
downloadsandbox-1f7d3654498e17e0a91c83f57e6265e08628d5fe.tar.gz
sandbox-1f7d3654498e17e0a91c83f57e6265e08628d5fe.tar.bz2
sandbox-1f7d3654498e17e0a91c83f57e6265e08628d5fe.zip
Fix SIGSEGV in gtest death tests due to small stack
In https://github.com/google/googletest/blob/v1.14.0/googletest/src/gtest-death-test.cc#L1307 on x86-64 gtest sallocates 8192 bytes for `clone`: ``` static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { const auto stack_size = static_cast<size_t>(getpagesize() * 2); ... child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); ``` After that attempt to call execv is intercepted by libsandbox.so, which allocates 8192 + more bytes multiple times on stack, causing SIGSEGV (instead of expected types of crashes). This PR moves all allocations for related function to heap, so now call path fits `getpagesize() * 2` with large margin. Bug: https://bugs.gentoo.org/923013 Closes: https://github.com/gentoo/sandbox/pull/26 Signed-off-by: Sv. Lockal <lockalsash@gmail.com> Signed-off-by: Mike Gilbert <floppym@gentoo.org>
-rw-r--r--libsandbox/libsandbox.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/libsandbox/libsandbox.c b/libsandbox/libsandbox.c
index 9705db1..acd8585 100644
--- a/libsandbox/libsandbox.c
+++ b/libsandbox/libsandbox.c
@@ -132,7 +132,8 @@ int resolve_dirfd_path(int dirfd, const char *path, char *resolved_path,
save_errno();
- char fd_path[SB_PATH_MAX];
+ char *fd_path = xmalloc(SB_PATH_MAX * sizeof(char));
+
size_t at_len = resolved_path_len - 1 - 1 - (path ? strlen(path) : 0);
if (trace_pid) {
sprintf(fd_path, "/proc/%i/fd/%i", trace_pid, dirfd);
@@ -148,12 +149,14 @@ int resolve_dirfd_path(int dirfd, const char *path, char *resolved_path,
/* see comments at end of check_syscall() */
if (errno_is_too_long()) {
restore_errno();
+ free(fd_path);
return 2;
}
sb_debug_dyn("AT_FD LOOKUP fail: %s: %s\n", fd_path, strerror(errno));
/* If the fd isn't found, some guys (glibc) expect errno */
if (errno == ENOENT)
errno = EBADF;
+ free(fd_path);
return -1;
}
resolved_path[ret] = '/';
@@ -162,6 +165,7 @@ int resolve_dirfd_path(int dirfd, const char *path, char *resolved_path,
strcat(resolved_path, path);
restore_errno();
+ free(fd_path);
return 0;
}
@@ -286,7 +290,7 @@ static char *resolve_path(const char *path, int follow_link)
}
if (!ret) {
- char tmp_str1[SB_PATH_MAX];
+ char *tmp_str1 = xmalloc(SB_PATH_MAX * sizeof(char));
snprintf(tmp_str1, SB_PATH_MAX, "%s", path);
dname = dirname(tmp_str1);
@@ -304,7 +308,7 @@ static char *resolve_path(const char *path, int follow_link)
filtered_path = NULL;
}
} else {
- char tmp_str2[SB_PATH_MAX];
+ char *tmp_str2 = xmalloc(SB_PATH_MAX * sizeof(char));
/* OK, now add the basename to keep our access
* checking happy (don't want '/usr/lib' if we
* tried to do something with non-existing
@@ -316,7 +320,10 @@ static char *resolve_path(const char *path, int follow_link)
snprintf(filtered_path + len, SB_PATH_MAX - len, "%s%s",
(filtered_path[len - 1] != '/') ? "/" : "",
bname);
+ free(tmp_str2);
}
+
+ free(tmp_str1);
}
}
@@ -1034,10 +1041,24 @@ bool is_sandbox_on(void)
return result;
}
+static int resolve_dirfd_path_alloc(int dirfd, const char *path, char **resolved_path)
+{
+ size_t resolved_path_size = SB_PATH_MAX * sizeof(char);
+ *resolved_path = xmalloc(resolved_path_size);
+ int result = resolve_dirfd_path(dirfd, path, *resolved_path, resolved_path_size);
+
+ if (result) {
+ free(*resolved_path);
+ *resolved_path = NULL;
+ }
+
+ return result;
+}
+
bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, int flags)
{
int result;
- char at_file_buf[SB_PATH_MAX];
+ char *at_file_buf;
/* Some funcs operate on a fd directly and so filename is NULL, but
* the rest should get rejected as "file/directory does not exist".
@@ -1056,7 +1077,7 @@ bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, in
}
}
- switch (resolve_dirfd_path(dirfd, file, at_file_buf, sizeof(at_file_buf))) {
+ switch (resolve_dirfd_path_alloc(dirfd, file, &at_file_buf)) {
case -1: return false;
case 0: file = at_file_buf; break;
case 2: return true;
@@ -1079,6 +1100,9 @@ bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, in
result = check_syscall(&sbcontext, sb_nr, func, file, flags);
+ if (at_file_buf)
+ free(at_file_buf);
+
sb_unlock();
if (0 == result) {