From: Waldemar Kozaczuk <[email protected]>
Committer: Nadav Har'El <[email protected]>
Branch: master
Fix the bug in SYSCALL implementation when called with 6 arguments
This patch fixes the bug identified during testing of golang support in OSv.
More specifically invocations of SYSCALL instruction involving 6 arguments
(plus syscall number) like pselect6 or mmap would often fail with last 6th
argument carrying wrong random value diffent from what caller would pass in.
As Nadav explains in OSv forum the original syscall_wrapper implementation
assumed that the arguments received would be passed correctly on the stack
to syscall function as is which was NOT the case and led to the corruption
of the 6th argument. So instead new syscall_wrapper implementation
explicitly calls syscall() function with all seven parameters explicitly
passed in.
The fix is authored by Nadav Har'El and new unit test in tst-syscall.cc
added by Waldemar Kozaczuk.
Signed-off-by: Waldemar Kozaczuk <[email protected]>
---
diff --git a/linux.cc b/linux.cc
--- a/linux.cc
+++ b/linux.cc
@@ -352,15 +352,20 @@ long syscall(long number, ...)
}
long __syscall(long number, ...) __attribute__((alias("syscall")));
-extern "C" long syscall_wrapper(long number, ...)
+// In x86-64, a SYSCALL instruction has exactly 6 parameters, because this
is the number of registers
+// alloted for passing them (additional parameters *cannot* be passed on
the stack). So we can get
+// 7 arguments to this function (syscall number plus its 6 parameters).
Because in the x86-64 ABI the
+// seventh argument is on the stack, we must pass the arguments explicitly
to the syscall() function
+// and can't just call it without any arguments and hope everything will
be passed on
+extern "C" long syscall_wrapper(long number, long p1, long p2, long p3,
long p4, long p5, long p6)
{
int errno_backup = errno;
// syscall and function return value are in rax
- auto ret = syscall(number);
+ auto ret = syscall(number, p1, p2, p3, p4, p5, p6);
int result = -errno;
errno = errno_backup;
if (ret < 0 && ret >= -4096) {
- return result;
+ return result;
}
return ret;
}
diff --git a/tests/tst-syscall.cc b/tests/tst-syscall.cc
--- a/tests/tst-syscall.cc
+++ b/tests/tst-syscall.cc
@@ -8,6 +8,11 @@
#include <syscall.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/mman.h>
+#include <cassert>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <iostream>
@@ -52,6 +57,34 @@ int main(int argc, char **argv)
expect(tid >= 0, true);
expect(tid, gettid());
+ // test mmap as it takes 6 parameters
+ int fd = open("/tests/tst-mmap.so", O_RDONLY, 0666);
+ assert(fd > 0);
+
+ void *addr = NULL;
+ size_t length = 8192;
+ int prot = PROT_READ;
+ int flags = MAP_PRIVATE;
+ off_t offset = 0;
+ void* buf = NULL;
+
+ asm ("movq %[addr], %%rdi\n"
+ "movq %[length], %%rsi\n"
+ "movl %[prot], %%edx\n"
+ "movq %[flags], %%r10\n"
+ "movq %[fd], %%r8\n"
+ "movq %[offset], %%r9\n"
+ "movq $9, %%rax\n"
+ "syscall\n"
+ "movq %%rax, %[buf]\n"
+ : [buf] "=m" (buf)
+ : [addr] "m" (addr), [length] "m" (length), [prot] "m" (prot),
[flags] "m" (flags), [fd] "m" (fd), [offset] "m" (offset));
+
+ assert(((long)buf) >= 0);
+ munmap(buf, length);
+
+ assert(close(fd) == 0);
+
// test that unknown system call results in a ENOSYS (see issue #757)
expect_errno_l(syscall(999), ENOSYS);
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.