Thread: How to unset LD_PRELOAD in runtime for a particular process

  1. #1
    Registered User
    Join Date
    Nov 2012
    Posts
    17

    How to unset LD_PRELOAD in runtime for a particular process

    Hi,

    I am trying to write wrapper function for some libc functions. I am doing it by creating a library and setting it in LD_PRELOAD. For some applications I dont want to set LD_PRELOAD how to do this?

    Could anyone please help me on this?

    Thanks
    Josy

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Binaries are searched for in the directories named in the PATH environment variable. Typically, it contains at least /usr/local/bin, /usr/bin, and /bin, in this order. You can use this to create wrapper scripts that will be executed instead of the actual program.

    For example, if you wanted tail to run with LD_PRELOAD set to some value, you could create /usr/local/bin/tail:
    Code:
    #!/bin/sh
    exec /usr/bin/env LD_PRELOAD=something /usr/bin/tail "$@"
    Because the directory is listed first in the PATH, the script will be run whenever you use the tail ... command. The script adds the environment variable, replacing itself with the actual command.

    This approach does not work for e.g. bash, because the path to the actual binary is hardcoded (#!/bin/bash). In that case, you could move the actual binaries to a subdirectory (say, /bin/actual/and /usr/bin/actual), and replace the original binary with the script.

    If you have just a few exceptions to when the LD_PRELOAD is in effect, and a large number of binaries, the above approaches are not really feasible. (I'd do the above on a virtual machine I'd set up for testing, but not on my real workstation.)

    The other approach is to let LD_PRELOAD be effective for all binaries, but enable or disable the functionality at init time based on the executable name.

    To run a C function automatically when the library is loaded, mark a function __attribute__((constructor)) . (See here for a common issue when compiling.)

    To determine which program the library has been loaded by, use readlink("/proc/self/exe", buffer, sizeof buffer - 1) in Linux. For other OSes, see here.

    Write an init (constructor) function for your library that checks the program executable name, then sets a flag (or function pointers); your functions perform the extra behaviour only when the flag is set, otherwise they just execute the original functions without modifications.

  3. #3
    Registered User
    Join Date
    Nov 2012
    Posts
    17
    hi i am not clear about the extra behaviour here u had told. How to set that in the constructor. In the constructor i can find whether application should be excluded or not. but how to set unset LD_PRELOAD there?

  4. #4
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    No, you misunderstand.

    The LD_PRELOAD would be effective for all binaries; the library would just behave differently depending on the pathname of the actual executable.

    The extra behaviour is just what the LD_PRELOADed library does.

    One option would be to have the actual LD_PRELOADed library be just a stump, which checks the pathname of the actual executable, and based on that uses dlopen() et al. to dynamically load the library that contains the actual functionality.

  5. #5
    Registered User
    Join Date
    Nov 2012
    Posts
    17
    Using dlopen can i load the entire library??? i had seen examples where we can get the symbol name in the library using dlsym. Using dlsym also i tried to get the symbols from libc.so. But dlsym is getting one symbol at a time and it is getting confused with my own implimentation of memcpy. i m trying to get the symbol of memcpy when i checked using gdb dlsym is internally calling my own implimentation of memcpy its not calling libc memcpy

  6. #6
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    You can use handle = dlopen("library.so", RTLD_NOW | RTLD_GLOBAL); to load and bind all symbols in the named dynamic library. See man 3 dlopen for details.

    Because memcpy() is a very common function, your replacement should probably be something like the following:
    Code:
    static volatile int   active = 0;
    
    void *memcpy(void *dest, const void *src, size_t n)
    {
        if (!active) {
            unsigned char       *d = (unsigned char *)dest;
            const unsigned char *s = (const unsigned char *)src;
            const unsigned char *const z = n + (const unsigned char *)src;
    
            while (s < z)
                *(d++) = *(s++);
    
            return dest;
        }
    
        /*
         * The body of your memcpy() function goes here
        */
    }
    with your init/constructor functions setting active nonzero only after it has prepared everything for your custom memcpy() to work correctly.

    Quote Originally Posted by josymadamana View Post
    But dlsym is getting one symbol at a time and it is getting confused with my own implimentation of memcpy.
    You can obtain the address of the next occurrence of the symbol in the library order, using the GNU extension RTLD_NEXT:
    Code:
    #define _GNU_SOURCE
    #include <dlfcn.c>
    
    static void *(true_memcpy)(void *, const void *, size_t) = NULL;
    
    static void my_library_init(void) __attribute__((constructor));
    static void my_library_init(void)
    {
        /* In C99, you cannot cast a void pointer to a function pointer,
         * so you need to use the POSIX.1-2003 (Technical Corrigendum 1)
         * workaround, also shown in the 'man 3 dlopen' Linux manpage.
        */
        *(void **)(&true_memcpy) = dlsym(RTLD_NEXT, "memcpy");
    
        /*
         * Other initialization..
        */
    
        /* Initialization complete. */
        active = 1;
    }
    After the initialization, you can use true_memcpy(). Just remember that you still need that activation flag (you could set it after the assignment above, for example), because your function may be called before, and even during, your library initialization.

  7. #7
    Registered User
    Join Date
    Nov 2012
    Posts
    17
    thankyou it worked... thanks for ur timely help.... i had tried this but was getting a segmentation fault because i was not doing the typecast....

  8. #8
    Registered User
    Join Date
    Nov 2012
    Posts
    17
    hi it worked perfectly for the first time... but it crashed when i ran it again.......
    this time it was calling my own implimented libc. evenif i had kept RTLD_NEXT in memcpy. both of my codes are in same file. i m also calling strcpy and many other libc functions after this. for strcpy *(char **)(&true_strcpy) will do??????

  9. #9
    Registered User
    Join Date
    Nov 2012
    Posts
    17
    (gdb) where
    #0 0x0000005555561d74 in do_lookup_x () from /lib64/ld.so.1
    #1 0x00000055555622a8 in _dl_lookup_symbol_x () from /lib64/ld.so.1
    #2 0x000000555556ca84 in __dl_runtime_resolve () from /lib64/ld.so.1
    #3 0x000000555556c82c in _dl_runtime_resolve () from /lib64/ld.so.1
    Backtrace stopped: frame did not save the PC

    this is the backtrace information. libc.so it is not able to find that is the problem. any help???
    Last edited by josymadamana; 11-13-2012 at 03:46 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. LD_PRELOAD getting ignored .. can anyone tell me why ?
    By NetworkLearning in forum C Programming
    Replies: 2
    Last Post: 09-19-2012, 10:13 PM
  2. how to get process info ( to extract process thread id )
    By umen242 in forum C++ Programming
    Replies: 4
    Last Post: 02-12-2009, 01:08 PM
  3. Runtime formation and execution at runtime
    By Soham in forum C Programming
    Replies: 17
    Last Post: 08-27-2008, 08:45 AM
  4. strange behavior when intercepting read() with LD_PRELOAD
    By *DEAD* in forum Linux Programming
    Replies: 2
    Last Post: 05-25-2008, 03:58 AM
  5. Child Process & Parent Process Data :: Win32
    By kuphryn in forum Windows Programming
    Replies: 5
    Last Post: 09-11-2002, 12:19 PM