Arun Kp
Arun Kp

Reputation: 422

Intercept clone using LD_PRELOAD in C, Linux

I want to intercept clone calls made by a simple pthread program. I am trying to use the LD_PRELOAD to achieve this. But could not get handle to the clone calls. When I run strace on pthread program, I can see that

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

But the clone signature of linux as well as the one I used in shared object is

int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
                 /* pid_t *parent_tid, void *tls, pid_t *child_tid */ );

Is the reason for not getting handle to clone is due to the difference in clone signature between straced one and linux manual?

or

LD_PRELOAD is not the correct way to intercept clone system calls made by pthread program?

shared object code

#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
}

compiled it using

gcc -Wall -fPIC -shared -o myclone.so myclone.c -ldl

Upvotes: 1

Views: 381

Answers (1)

Employed Russian
Employed Russian

Reputation: 213879

I want to intercept clone calls made by a simple pthread program.

If you disassemble libpthread.so.0 (the do_clone() function), you'll discover that it doesn't call clone(), it calls __clone().

You can also observe this in nm -D libpthread.so.0 output:

nm -D /lib/x86_64-linux-gnu/libpthread.so.0 | grep clone
                 U __clone@GLIBC_2.2.5

Changing myclone.c to provide int __clone(...) on a system with GLIBC 2.31 results in:

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

Note that the code you commented out:

//removed rest of the code

is severely restricted in what it can do -- this code is called while holding several GLIBC-internal locks, the newly-created thread has not been fully initialized, etc. etc.

If you call into GLIBC at that point, you should expect deadlocks, crashes and/or mystery bugs.

Upvotes: 3

Related Questions