Skip to content

Commit

Permalink
fix:解决变长参数方法(fcntl, ioctl)hook后参数转发实现不正确导致使用异常问题。
Browse files Browse the repository at this point in the history
Update the implementation of hooked fcntl & ioctl to fix the problem.
  • Loading branch information
ltmit authored Dec 29, 2021
1 parent 4a33724 commit 403b50b
Showing 1 changed file with 45 additions and 26 deletions.
71 changes: 45 additions & 26 deletions src/co/hook.cc
Original file line number Diff line number Diff line change
Expand Up @@ -240,42 +240,59 @@ int pipe2(int pipefd[2], int flags) {
#define F_DUPFD_CLOEXEC F_DUPFD
#endif

/*
For system IO functions which take a variable number of arguments (like fcntl, ioctl),
we assume that the variadic parameters part's memory usage <= 8*sizeof(intptr_t) .
So, we can use 'a1'..'a8' to hold the stack memory data of variadic parameters passed from function caller (with va_star/va_arg/va_end).
Then, pass these parameters to destination function (raw function) in the prescribed order.
If the parameters is more than actually what the caller passed, it is just OK,
because the extra part only takes some stack memory space and will be ignored.
If the parameters is LESS than actually what the caller passed, some missed parameters cannot be passed!
It will cause error/fatal!
Ref:
https://docs.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
https://baike.baidu.com/item/__cdecl/9518056
*/
#define VARG_8_GET(st) intptr_t a1,a2,a3,a4,a5,a6,a7,a8;\
{va_list ap; va_start(ap,st); \
a1=va_arg(ap,intptr_t); a2=va_arg(ap,intptr_t); a3=va_arg(ap,intptr_t); a4=va_arg(ap,intptr_t); \
a5=va_arg(ap,intptr_t); a6=va_arg(ap,intptr_t); a7=va_arg(ap,intptr_t); a8=va_arg(ap,intptr_t); \
va_end(ap);}

#define VARG_8_PARAMS a1,a2,a3,a4,a5,a6,a7,a8


int fcntl(int fd, int cmd, ... /* arg */) {
init_hook(fcntl);
if (fd < 0) { errno = EBADF; return -1; }

va_list args;
va_start(args, cmd);
VARG_8_GET(cmd);

int r, v;
auto& ctx = gHook().get_hook_ctx(fd);
if (!ctx.is_sock_or_pipe()) {
r = CO_RAW_API(fcntl)(fd, cmd, args);
va_end(args);
return r;
return CO_RAW_API(fcntl)(fd, cmd, VARG_8_PARAMS);
}

int r;

if (cmd == F_SETFL) {
v = va_arg(args, int);
va_end(args);
r = CO_RAW_API(fcntl)(fd, cmd, v);
// 'F_SETFL' only need one extra parameter
r = CO_RAW_API(fcntl)(fd, cmd, a1);
if (r != -1) {
ctx.set_non_blocking(v & O_NONBLOCK);
HOOKLOG << "hook fcntl F_SETFL, fd: " << fd << ", non_block: " << (v & O_NONBLOCK);
ctx.set_non_blocking(a1 & O_NONBLOCK);
HOOKLOG << "hook fcntl F_SETFL, fd: " << fd << ", non_block: " << (a1 & O_NONBLOCK);
}

} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
v = va_arg(args, int);
va_end(args);
r = CO_RAW_API(fcntl)(fd, cmd, v);
// 'F_DUPFD'/'F_DUPFD_CLOEXEC' only need one extra parameter
r = CO_RAW_API(fcntl)(fd, cmd, a1);
if (r != -1) {
gHook().get_hook_ctx(r) = ctx;
HOOKLOG << "hook fcntl F_DUPFD, fd: " << fd << ", r: " << r;
}

} else {
r = CO_RAW_API(fcntl)(fd, cmd, args);
va_end(args);
r = CO_RAW_API(fcntl)(fd, cmd, VARG_8_PARAMS);
}

HOOKLOG << "hook fcntl cmd: " << cmd << ", fd: " << fd << ", r: " << r;
Expand All @@ -286,18 +303,20 @@ int ioctl(int fd, co::ioctl_param<ioctl_fp_t>::type request, ...) {
init_hook(ioctl);
if (fd < 0) { errno = EBADF; return -1; }

va_list args;
va_start(args, request);
void* arg = va_arg(args, void*);
va_end(args);
VARG_8_GET(request);

int r;
auto& ctx = gHook().get_hook_ctx(fd);
int r = CO_RAW_API(ioctl)(fd, request, arg);
if (r != -1) {
if (request == FIONBIO && ctx.is_sock_or_pipe()) {
ctx.set_non_blocking(*(int*)arg);
HOOKLOG << "hook ioctl FIONBIO, fd: " << fd << ", non_block: " << *(int*)arg;

if (request == FIONBIO && ctx.is_sock_or_pipe()) {
int v=*(int*)a1;
r = CO_RAW_API(ioctl)(fd, request, v);
if (r != -1) {
ctx.set_non_blocking(v);
HOOKLOG << "hook ioctl FIONBIO, fd: " << fd << ", non_block: " << v;
}
}else {
r = CO_RAW_API(ioctl)(fd, request, VARG_8_PARAMS);
}

HOOKLOG << "hook ioctl, fd: " << fd << ", req: " << request << ", r: " << r;
Expand Down

0 comments on commit 403b50b

Please sign in to comment.