diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -71,3 +71,7 @@ FBSD_1.7 { _Fork; }; + +FBSD_1.8 { + vfcntl; +}; diff --git a/lib/libc/sys/fcntl.c b/lib/libc/sys/fcntl.c --- a/lib/libc/sys/fcntl.c +++ b/lib/libc/sys/fcntl.c @@ -3,6 +3,7 @@ * * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ * Authors: Doug Rabson + * Authors: Alex Richardson * Developed with Red Inc: Alfred Perlstein * * Copyright (c) 2014-2015 The FreeBSD Foundation. @@ -38,16 +39,39 @@ #include #include "libc_private.h" +#pragma weak vfcntl +int +vfcntl(int fd, int cmd, va_list args) +{ + intptr_t arg; + + /* + * fctnl() uses varargs to implement optional arguments, so some calls + * will not actually have an argument passed in this va_list. + * While it is undefined behaviour to call va_arg when no argument + * exists in the argument list, all currently supported architectures + * will give us a result even if no argument/an int was passed instead + * since va_arg() will generally read the next argument register or + * arbitrary data from the stack. This is not true for all architectures + * so once we support one that enforces checks on variadic args (e.g. + * CHERI), we will need to avoid reading non-existent arguments. + */ + arg = va_arg(args, intptr_t); + + return (INTERPOS_SYS(fcntl, fd, cmd, arg)); +} + #pragma weak fcntl int fcntl(int fd, int cmd, ...) { va_list args; - long arg; + int result; va_start(args, cmd); - arg = va_arg(args, long); + result = vfcntl(fd, cmd, args); va_end(args); - return (INTERPOS_SYS(fcntl, fd, cmd, arg)); + return (result); } + diff --git a/lib/libsys/fcntl.2 b/lib/libsys/fcntl.2 --- a/lib/libsys/fcntl.2 +++ b/lib/libsys/fcntl.2 @@ -37,6 +37,9 @@ .In fcntl.h .Ft int .Fn fcntl "int fd" "int cmd" "..." +.In stdarg.h +.Ft int +.Fn vfcntl "int fd" "int cmd" "va_list ap" .Sh DESCRIPTION The .Fn fcntl diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -376,6 +376,7 @@ int creat(const char *, mode_t); int fcntl(int, int, ...); #if __BSD_VISIBLE +int vfcntl(int, int, __va_list); int flock(int, int); int fspacectl(int, int, const struct spacectl_range *, int, struct spacectl_range *);