Setting LD_PRELOAD path saves the process from getting Segmentation fault

97 Views Asked by At

My application obuspa is crashing when it is executing the standard OpenWRT library call uci_lookup_ptr of the libuci.so linked library. Loader is showing this library in the list of linked libraries as below

# /lib/ld-linux.so.3 --list /sbin/obuspa
        libmosquitto.so.1 => /usr/lib/libmosquitto.so.1 (0xb68de000)
        libubus.so => /usr/lib/libubus.so (0xb68cf000)
        libubox.so => /usr/lib/libubox.so (0xb68bb000)
        libblobmsg_json.so => /usr/lib/libblobmsg_json.so (0xb68b0000)
        libuci.so => /lib/libuci.so (0xb689e000)
        libc.so.6 => /lib/libc.so.6 (0xb6766000)
        /lib/ld-linux.so.3 (0xb6f2d000)

If the same library is set in shell environment using ld_preload like below, and application is restarted, the process is running fine and not recieving any SIGSEGV signal at all. Hence, no SEGFAULT.

export LD_PRELOAD=/lib/libuci.so 

Below is the code:

static int get_value_from_uci(char *path, char *value, size_t max_value_len)
{
    struct uci_context *uci_ctx;
    struct uci_ptr ptr;
    int ret = 0;

    if (!path || !value || max_value_len == 0)
            return -1;

    uci_ctx = uci_alloc_context();
    if (!uci_ctx)
            return -1;

    printf("%s, uci ctx : %p created, lookup for %s\n", __FUNCTION__, uci_ctx, path);
    if (uci_lookup_ptr(uci_ctx, &ptr, path, true) != UCI_OK) {
            ret = -1;
            uci_free_context(uci_ctx);
            printf("%s, uci lookup failed\n", __FUNCTION__);
            return ret;
    }
    printf("%s, uci ptr flag:%d\n", __FUNCTION__, ptr.flags);
    if ((ptr.flags & UCI_LOOKUP_COMPLETE)
            && (ptr.o != NULL)
            && (ptr.o->v.string!=NULL)) {
            ret = 0;
            USP_STRNCPY(value, ptr.o->v.string, max_value_len);
            printf("%s, uci lookup completed, value:%s\n", __FUNCTION__, value);
    }
    return ret;
}

int main()
{
    char cached_json_file[256] = {0};
    char uci_role_path[] = "obuspa.global.dm_caching_exclude";
    
    // Read rest of the roles from JSON, if defined
    printf("%s, GET UCI Role\n", __FUNCTION__);
    if (get_value_from_uci(uci_role_path, cached_json_file, 256) != 0)
            goto exit;
    ....
    return 0;
}

Library source code link: https://git.openwrt.org/?p=project/uci.git;a=tree

How setting same shared library path, save the process from crash.

2

There are 2 best solutions below

2
Mathieu On

You can make the export LD_PRELOAD=/lib/libuci.so with /etc/ld.so.preload file:

add just line /lib/libuci.so to file /etc/ld.so.preload, you may have to create it.

From man 8 ld.so:

/etc/ld.so.preload

File containing a whitespace-separated list of ELF shared objects to be loaded before the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and /etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to be preloaded for all programs that are executed on the system. (This is usually undesirable, and is typically employed only as an emergency remedy, for example, as a temporary workaround to a library misconfiguration issue.)


If you don’t want to use /etc/ld.so.preload file, you can create a script file that will set LD_PRELOAD each time you try to launch obuspa:

obuspa.sh

#! /bin/sh
export LD_PRELOAD=/lib/libuci.so
/sbin/obuspa "$@"
6
saintMath On

When you use LD_PRELOAD this changes the order in which the .so libs are loaded, in the sense that libuci.so is loaded first, then the other libs.

Now, there probably is some memory corruption in your code, which initially damaged the memory where libuci.so was loaded, or memory that libuci.so used and expected to have strict values, and when you called the function it crashed.

What happens now, probably, is that some other function in another lib (e.g. libc.so) gets corrupted. But since you never call that corrupted function, there is no crash.

You need to have a deeper look at your code: are you getting an error somewhere and passing a null pointer to another function? Are you passing a buffer to a function that writes more data than the buffer can hold?
These things are tricky and frustrating to track down, but finding the issue eventually is satisfying ;-) Good luck!