Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap ioctl(int d, unsigned long request, ...) using LD_PRELOAD?

Here's the template I use for wrapping a function using LD_PRELOAD:

int gettimeofday(struct timeval *tv, struct timezone *tz) {
  static int (*gettimeofday_real)(struct timeval *tv, struct timezone *tz)=NULL;
  if (!gettimeofday_real) gettimeofday_real=dlsym(RTLD_NEXT,"gettimeofday");
  return gettimeofday_real(tv, tz);
}

I realized though that ioctl seems to have the following signature:

   int ioctl(int d, unsigned long request, ...);

How could I wrap it in a similar way, given the ... that's in the signature?

like image 726
d33tah Avatar asked Feb 11 '15 19:02

d33tah


2 Answers

Although John Bollinger is correct in that according to its prototype in ioctl.h, ioctl() is a variadic function, in practice, it is not.

See e.g this quote from the book Linux Device Drivers

The prototype stands out in the list of Unix system calls because of the dots, which usually mark the function as having a variable number of arguments. In a real system, however, a system call can't actually have a variable number of arguments. System calls must have a well-defined prototype, because user programs can access them only through hardware "gates." Therefore, the dots in the prototype represent not a variable number of arguments but a single optional argument, traditionally identified as char *argp. The dots are simply there to prevent type checking during compilation.

So you can write your susbtitute ioctl() as follows:

int ioctl(int d, unsigned long request, char *argp)
{
  /* follow the same recipe as for your example gettimeofday() */
  return ioctl_real(d, request, argp);
}

If you just want to build a wrapper library for use with LD_PRELOAD, the fact that your ioctl signature contradicts the one in sys/ioctl.h is irrelevant: linkers don't check types, and your wrapper library's fake ioctl will be called with exactly the same arguments as the real one would without LD_PRELOAD

like image 99
Hans Lub Avatar answered Sep 30 '22 11:09

Hans Lub


There is no portable way for one variadic function to forward its variadic arguments to another variadic function. In part this is because the number and size of the actual arguments must be known at compile time for the compiler to construct the variadic call, but they are not statically known (not even in parametric fashion) inside the called function.

like image 35
John Bollinger Avatar answered Sep 30 '22 12:09

John Bollinger