1

I override the libc open() function like this and compile it to a shared library called libc_custom.so:


struct sys_funcs_t
{
    sys_funcs_t()
    {
        libc_hdl = dlopen("/usr/lib64/libc.so.6", RTLD_NOW);
        sys_open = (int (*)(const char *str, int flags, ...))dlsym(libc_hdl, "open");
    }
    ~sys_funcs_t()
    {
        dlclose(libc_hdl);
    }
    int (*sys_open)(const char *, int, ...);

private:
    void *libc_hdl;
};

static sys_funcs_t g_sys_funcs;

static int realopen(const char *path, int flags, va_list args)
{

    if (flags & (O_CREAT | O_TMPFILE))
    {
        mode_t mode = va_arg(args, mode_t);
        return g_sys_funcs.sys_open(path, flags, mode);
    }
    else
    {
        return g_sys_funcs.sys_open(path, flags);
    }
}

extern "C" __attribute__((visibility ("default")))
int open(const char *pathname, int flags, ...)
{
    printf("---- custom open %s\n", pathname);
    va_list args;
    va_start(args, flags);
    int fd = realopen(pathname, flags, args);
    va_end(args);
    return fd;
}

It is quite strange that the following simple python code hangs with LD_PRELOAD=libc_custom.so:

import os
ret=os.popen("uname -p").read()
print(ret)

the uname -p can be any other command, the gdb shows that it hangs at __read_nocancel():

(gdb) bt
#0  0x00007f4064e91700 in __read_nocancel () from /lib64/libpthread.so.0
#1  0x0000000000439876 in _Py_read ()
#2  0x00000000005b837e in ?? ()
#3  0x00000000004bded3 in _PyCFunction_FastCallDict ()
#4  0x0000000000455ff1 in _PyObject_FastCallDict ()
#5  0x00000000004573f4 in PyObject_CallMethodObjArgs ()
#6  0x00000000005bf95e in ?? ()
#7  0x00000000004bde8b in _PyCFunction_FastCallDict ()
#8  0x000000000044ee2e in ?? ()
#9  0x0000000000457278 in _PyObject_CallMethodId_SizeT ()
#10 0x00000000005c55fa in ?? ()
#11 0x00000000004be28d in _PyCFunction_FastCallKeywords ()
#12 0x0000000000545f34 in ?? ()
#13 0x000000000054aa3e in _PyEval_EvalFrameDefault ()
#14 0x0000000000545b31 in ?? ()
#15 0x0000000000546b03 in PyEval_EvalCode ()
#16 0x00000000004272f5 in PyRun_FileExFlags ()
#17 0x00000000004274c5 in PyRun_SimpleFileExFlags ()
#18 0x000000000043e9e5 in Py_Main ()
#19 0x000000000041e160 in main ()

when I press "Enter" 4 times, the code can continue executing.

python version: 3.6.10

libc version: 2.17

Alex
  • 44
  • 5
  • 1
    Possibly relevant: https://stackoverflow.com/a/7775433 (as I noticed you aren't passing the third parameter correctly) – Hasturkun May 18 '21 at 15:05
  • @Hasturkun, the `realopen` is a wrapper function, I updated the code, it seems correct comparing with https://stackoverflow.com/questions/7775317/how-do-i-wrap-around-open/7775433#7775433 – Alex May 19 '21 at 04:50
  • 1
    `static sys_funcs_t g_sys_funcs;` How do you know it's constructed before your callback is called? Try putting `static sys_funcs_t g_sys_funcs;` inside `realopen()` so that it is constructed when called. – KamilCuk May 19 '21 at 04:54
  • @KamilCuk, thanks for your advice, this is indeed a potential problem. I tried it but the code still hangs. Actually, in my real case, the code works well except for the `os.popen()` one. – Alex May 19 '21 at 05:22
  • Could you please add missing `#include`s and how you compile it and how you run your python script? || I copied your code and it works on my system, except the needed change `printf` to `write` calls and it works - I see `/dev/tty` is being opened. Please consider adding a makefile with steps to compile and test and add as detailed possible [MCVE]. What linux distribution are you using? – KamilCuk May 19 '21 at 05:37
  • On my system, no code interpreted by Python goes through `custom_open`, even though the Python executable itself does when it opens various files like inputrc and history. When I put a breakpoint on `open`, Python stops at a function named `__libc_open64` in `libc.so.6`. Attempts to override `__libc_open64` in the same way do not work. "Do not mess with glibc". – n. m. could be an AI May 19 '21 at 06:26
  • A note: hardcoding `/usr/lib64/libc.so.6` is not portable, on other Linux-versions it can be `/lib/x86_64-linux-gnu/libc.so.6` (or something else). – Lorinczy Zsigmond May 19 '21 at 07:47

0 Answers0