如何使用LD_PRELOAD包装ioctl(int d,unsigned long request,...)?

d33*_*tah 6 c linux system-calls ld-preload

这是我用于使用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);
}
Run Code Online (Sandbox Code Playgroud)

我意识到ioctl似乎有以下签名:

   int ioctl(int d, unsigned long request, ...);
Run Code Online (Sandbox Code Playgroud)

考虑...到签名中的内容,我怎么能以类似的方式包装呢?

Han*_*Lub 7

虽然约翰·布林是正确的,根据它的原型ioctl.h,ioctl()是一个可变参数函数,在实践中,事实并非如此.

请参阅Linux设备驱动程序一书中的引用

由于点的原因,原型在Unix系统调用列表中脱颖而出,这通常将函数标记为具有可变数量的参数.但是,在实际系统中,系统调用实际上不能具有可变数量的参数.系统调用必须具有明确定义的原型,因为用户程序只能通过硬件"门"访问它们.因此,原型中的点不代表可变数量的参数,而是代表一个可选参数,传统上标识为char*argp.这些点只是为了防止在编译期间进行类型检查.

所以你可以写下自己的内容ioctl()如下:

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

如果你只是想构建一个包装库供你使用LD_PRELOAD,那么你的ioctl签名与那个签名相矛盾的事实sys/ioctl.h是无关紧要的:链接器不会检查类型,你的包装库的伪造ioctl将被调用与真正的参数完全相同的参数无LD_PRELOAD