【问题标题】:Intercept clone using LD_PRELOAD in C, Linux在 C、Linux 中使用 LD_PRELOAD 拦截克隆
【发布时间】:2021-08-05 07:27:53
【问题描述】:

我想拦截一个简单的 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 */ );

是不是因为straceed one和linux手册的clone签名不一样,导致无法获取到clone的句柄?

LD_PRELOAD不是拦截pthread程序克隆系统调用的正确方法吗?

共享目标代码

#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

【问题讨论】:

  • strace 告诉您进程执行的 系统调用。 LD_PRELOAD 允许您插入库函数调用。两者不一样。使用ltrace 而不是strace 来跟踪库函数调用,因此您可以找出需要插入的正确函数。 (我希望它是pthread_create(),它是在 C 库中使用 'clone' 系统调用实现的;而不是作为对 clone() C 库函数的调用。)要拦截系统调用,您可能需要(编写一个程序来) ptrace 目标进程。

标签: c linux ld-preload


【解决方案1】:

我想拦截一个简单的 pthread 程序进行的克隆调用。

如果你反汇编libpthread.so.0do_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

在具有 GLIBC 2.31 的系统上更改 myclone.c 以提供 int __clone(...) 会导致:

LD_PRELOAD=./myclone.so ./a.out
called my clone

注意你注释掉的代码:

//removed rest of the code

它可以做的事情受到严格限制——这段代码被调用时持有几个 GLIBC 内部锁,新创建的线程还没有完全初始化,等等。

如果您此时调用 GLIBC,您应该会遇到死锁、崩溃和/或神秘错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 2019-03-16
    • 2011-07-25
    相关资源
    最近更新 更多