NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: LD_PRELOAD and mixed architectures



On 6/22/2014 12:19 PM, Gary Duzan wrote:
In Message <53A6F6D7.5040300%grammatech.com@localhost>,
    Dave Vitek <dvitek%grammatech.com@localhost>wrote:

=>Hi all,
=>
=>I'm on an amd64 machine that has a mixture of i386 and amd64 binaries
=>present.  I want to build a shared object file and use LD_PRELOAD to
=>inject it into every process in some process tree. The executables in
=>the tree could be a mixture of amd64 and i386 executables.  Many other
=>operating systems have a way of using LD_PRELOAD in a mixed architecture
=>environment, but I'm not seeing a path to victory on netbsd.
=>
=>I had a look at the source code for ld.so (the elf one anyway).  It
=>doesn't search search LD_LIBRARY_PATH -- it just tries to open() the
=>filename in LD_PRELOAD relative to CWD and blows up if the architecture
=>doesn't match the process.  Other operating systems facilitate this sort
=>of thing in various ways:
=>
=>Solaris: LD_PRELOAD_32 and LD_PRELOAD_64
=>Linux: Search LD_LIBRARY_PATH, only fail if every attempt fails. Also,
=>"$LIB" is magical.
=>Mac OS X: Universal binaries
=>
=>One (ugly) thought I had is to have the shared object file hook every
=>function in the "exec" family and fix LD_PRELOAD so it points at the
=>architecture of the binary about to be exec'd before delegating to the
=>real exec.  Anyone have a less ugly alternative that doesn't require
=>modifying system files (e.g., adjusting ld.so)?

    Just a thought, but have you tried putting a 32-bit version of
the library under /emul/netbsd32 ?

                                Gary Duzan


Looks like things loaded due to LD_PRELOAD don't search /emul. Here is a short experiment:

$ echo "int main(){ return 0; }" > nop.c
$ gcc -m32 nop.c -o nop
$ LD_PRELOAD=app/lib64/libhook.so ./nop
app/lib64/libhook.so: unrecognized file format2 [2 != 1]
$ LD_PRELOAD=app/lib/libhook.so ./nop
$ ls /emul/netbsd32/
libhook.so
$ LD_PRELOAD=libhook.so ./nop
Cannot open "libhook.so"
$ gcc -m64 nop.c -o nop
$ LD_PRELOAD=libhook.so ./nop
Cannot open "libhook.so"

It occurs to me that linux emulation processes may have similar challenges.

There is an existing problem report here:
http://gnats.netbsd.org/47509

Relevant code from ld.so_elf confirms that it just does a straight up open() of the values in the environment variable and doesn't search anywhere:

// ld_preload is raw value of env variable


        if (ld_preload) {
                /*
                 * Pre-load user-specified objects after the main program
                 * but before any shared object dependencies.
                 */
                dbg(("preloading objects"));
                if (_rtld_preload(ld_preload) == -1)
                        _rtld_die();
        }
...


int
_rtld_preload(const char *preload_path)
{
        const char *path;
        char *cp, *buf;
        int status = 0;

        if (preload_path != NULL && *preload_path != '\0') {
                cp = buf = xstrdup(preload_path);
                while ((path = strsep(&cp, " :")) != NULL && status == 0) {
                        if (!_rtld_load_object(path, _RTLD_MAIN))
                                status = -1;
                        else
                                dbg((" preloaded \"%s\"", path));
                }
                xfree(buf);
        }

        return status;
}


...

Obj_Entry *
_rtld_load_object(const char *filepath, int flags)
{
        Obj_Entry *obj;
        int fd = -1;
        struct stat sb;
        size_t pathlen = strlen(filepath);

        for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
                if (pathlen == obj->pathlen && !strcmp(obj->path, filepath))
                        break;

        /*
         * If we didn't find a match by pathname, open the file and check
         * again by device and inode.  This avoids false mismatches caused
         * by multiple links or ".." in pathnames.
         *
         * To avoid a race, we open the file and use fstat() rather than
         * using stat().
         */
        if (obj == NULL) {
                if ((fd = open(filepath, O_RDONLY)) == -1) {
                        _rtld_error("Cannot open \"%s\"", filepath);
                        return NULL;
                }




Home | Main Index | Thread Index | Old Index