From e88193492771f6d3c9f6d9d7b9b2b21b1a04e92d Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 18 Mar 2021 10:45:50 +0000 Subject: [PATCH] os-wrappers-test.c: Correctly forward arguments to fcntl We can't just unconditionally read the optional arguments (and also read it as a void* despite actually being an int). While this happens to work on most architectures because the first few variadic arguments are passed in registers, this is non-portable and causes a crash on architectures that set bounds on variadic function arguments (for example CHERI-enabled architectures). It could also cause problems on big-endian architectures that pass variadic arguments on the stack rather than in registers. For CHERI-MIPS, reading sizeof(void*) causes a read of 16 bytes from the bounded varargs capability. This always crashes since even calls with the optional argument only have 4 bytes available. Signed-off-by: Alex Richardson Reviewed-by: Simon Ser --- tests/os-wrappers-test.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 102622c..4d5de31 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -85,7 +85,8 @@ __attribute__ ((visibility("default"))) int fcntl(int fd, int cmd, ...) { va_list ap; - void *arg; + int arg; + int has_arg; wrapped_calls_fcntl++; @@ -93,12 +94,27 @@ fcntl(int fd, int cmd, ...) errno = EINVAL; return -1; } + switch (cmd) { + case F_DUPFD_CLOEXEC: + case F_DUPFD: + case F_SETFD: + va_start(ap, cmd); + arg = va_arg(ap, int); + has_arg = 1; + va_end(ap); + break; + case F_GETFD: + has_arg = 0; + break; + default: + fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd); + abort(); + } - va_start(ap, cmd); - arg = va_arg(ap, void*); - va_end(ap); - - return real_fcntl(fd, cmd, arg); + if (has_arg) { + return real_fcntl(fd, cmd, arg); + } + return real_fcntl(fd, cmd); } __attribute__ ((visibility("default"))) ssize_t -- 2.7.4