在 C 中使用 LD_PRELOAD 拦截克隆,Linux
Intercept clone using LD_PRELOAD in C, Linux
我想拦截由一个简单的 pthread 程序发出的 clone 调用。我正在尝试使用 LD_PRELOAD 来实现这一点。但是无法处理 clone 调用。当我在 pthread 程序上 运行 strace 时,我可以看到
clone(child_stack=0x7f15b7fa3ef0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[8895], tls=0x7f15b7fa4640, child_tidptr=0x7f15b7fa4910) = 8895
但是 linux 的克隆签名以及我在共享对象中使用的签名是
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
/* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
无法获取克隆句柄的原因是由于 straced 和 linux 手动克隆签名之间的差异吗?
或
LD_PRELOAD 不是截取 pthread 程序进行的 clone 系统调用的正确方法吗?
共享对象代码
#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <sys/types.h>
#include <bits/fcntl.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
typedef int (*_clone_f_t)(int (*fn)(void *), void *stack, int flags, void *arg, ...);
static _clone_f_t _clone_f_ = NULL;
void __attribute__((constructor)) my_init();
void __attribute__((destructor)) my_fini();
void my_init(){
_clone_f_ = (_clone_f_t)dlsym(RTLD_NEXT,"clone");
}
void my_fini(){}
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...){
printf("called my clone\n");
va_list arglist;
pid_t * parent_tid;
void * tls;
pid_t * child_tid;
va_start(arglist,arg);
parent_tid = va_arg(arglist, pid_t*);
tls = va_arg(arglist, void*);
child_tid = va_arg(arglist, pid_t*);
va_end(arglist);
//removed rest of the code
}
使用
编译它
gcc -Wall -fPIC -shared -o myclone.so myclone.c -ldl
I want to intercept clone calls made by a simple pthread program.
如果你反汇编libpthread.so.0
(do_clone()
函数),你会发现它不调用clone()
,而是调用__clone()
.
您还可以在 nm -D libpthread.so.0
输出中观察到这一点:
nm -D /lib/x86_64-linux-gnu/libpthread.so.0 | grep clone
U __clone@GLIBC_2.2.5
更改 myclone.c
以在具有 GLIBC 2.31 的系统上提供 int __clone(...)
结果:
LD_PRELOAD=./myclone.so ./a.out
called my clone
注意你注释掉的代码:
//removed rest of the code
它的功能受到严格限制 -- 此代码在持有多个 GLIBC 内部锁时被调用,新创建的线程尚未完全初始化,等等。
如果您此时调用 GLIBC,您应该会遇到死锁、崩溃 and/or 神秘错误。
我想拦截由一个简单的 pthread 程序发出的 clone 调用。我正在尝试使用 LD_PRELOAD 来实现这一点。但是无法处理 clone 调用。当我在 pthread 程序上 运行 strace 时,我可以看到
clone(child_stack=0x7f15b7fa3ef0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[8895], tls=0x7f15b7fa4640, child_tidptr=0x7f15b7fa4910) = 8895
但是 linux 的克隆签名以及我在共享对象中使用的签名是
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
/* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
无法获取克隆句柄的原因是由于 straced 和 linux 手动克隆签名之间的差异吗?
或
LD_PRELOAD 不是截取 pthread 程序进行的 clone 系统调用的正确方法吗?
共享对象代码
#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <sys/types.h>
#include <bits/fcntl.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
typedef int (*_clone_f_t)(int (*fn)(void *), void *stack, int flags, void *arg, ...);
static _clone_f_t _clone_f_ = NULL;
void __attribute__((constructor)) my_init();
void __attribute__((destructor)) my_fini();
void my_init(){
_clone_f_ = (_clone_f_t)dlsym(RTLD_NEXT,"clone");
}
void my_fini(){}
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...){
printf("called my clone\n");
va_list arglist;
pid_t * parent_tid;
void * tls;
pid_t * child_tid;
va_start(arglist,arg);
parent_tid = va_arg(arglist, pid_t*);
tls = va_arg(arglist, void*);
child_tid = va_arg(arglist, pid_t*);
va_end(arglist);
//removed rest of the code
}
使用
编译它gcc -Wall -fPIC -shared -o myclone.so myclone.c -ldl
I want to intercept clone calls made by a simple pthread program.
如果你反汇编libpthread.so.0
(do_clone()
函数),你会发现它不调用clone()
,而是调用__clone()
.
您还可以在 nm -D libpthread.so.0
输出中观察到这一点:
nm -D /lib/x86_64-linux-gnu/libpthread.so.0 | grep clone
U __clone@GLIBC_2.2.5
更改 myclone.c
以在具有 GLIBC 2.31 的系统上提供 int __clone(...)
结果:
LD_PRELOAD=./myclone.so ./a.out
called my clone
注意你注释掉的代码:
//removed rest of the code
它的功能受到严格限制 -- 此代码在持有多个 GLIBC 内部锁时被调用,新创建的线程尚未完全初始化,等等。
如果您此时调用 GLIBC,您应该会遇到死锁、崩溃 and/or 神秘错误。