#6 dlsym() returns address of a function in library X when provided the handle of library Y

Open
opened 4 years ago by koutheir · 1 comments

Consider 3 libraries: libA, libB and libC. Only library libB implements and exports the function public_function().

A program dlopen()s libA then libB then libC. Then the program calls dlsym(libA, "public_function") then dlsym(libB, "public_function") then dlsym(libC, "public_function").

Expected behavior:

  • dlsym(libA, "public_function") and dlsym(libC, "public_function") return NULL, and
  • dlsym(libB, "public_function") returns a non-NULL address.

Erroneous behavior:

  • dlsym(libC, "public_function") return NULL, and
  • dlsym(libA, "public_function") and dlsym(libB, "public_function") returns the same non-NULL address.

Program to reproduce this issue:

// dlsym-test1.c

#include <stdio.h>
#include <dlfcn.h>

typedef void (*public_function_t)();

int main() {
    int i;
    void* lib[3] = {};
    void* lib_name[3] = {"liba.so", "libb.so", "libc.so"};
    public_function_t public_function[3] = {};

    for (i = 0; i < 3; ++i) {
        lib[i] = dlopen(lib_name[i], RTLD_NOW | RTLD_LOCAL);
    }

    for (i = 0; i < 3; ++i) {
        if (lib[i] != NULL) {
            public_function[i] = dlsym(lib[i], "public_function");
        }
    }

    for (i = 0; i < 3; ++i) {
        printf("%s:%#x public_function:%#x.\n", lib_name[i], lib[i], public_function[i]);
    }

    for (i = 0; i < 3; ++i) {
        if (public_function[i] != NULL) {
            (public_function[i])();
        }
    }

    return 0;
}
// libb.c

#include <stdio.h>

void public_function() __attribute__ ((visibility ("default")));

void public_function() {
    puts("libB::public_function()");
}
#!/bin/bash

CROSS_COMPILE=...

CC=${CROSS_COMPILE}gcc

CFLAGS='-fvisibility=hidden -O0 -g -Wextra -Werror'

rm *.so dlsym-test1

$CC $CFLAGS -fPIC -shared -o liba.so empty.c
$CC $CFLAGS -fPIC -shared -o libb.so libb.c
$CC $CFLAGS -fPIC -shared -o libc.so empty.c

$CC $CFLAGS -fPIE -pie '-Wl,-rpath=$ORIGIN' -o dlsym-test1 dlsym-test1.c
$ ./dlsym-test1
liba.so:0x80579160 public_function:0xb6eb9584.
libb.so:0x80579348 public_function:0xb6eb9584.
libc.so:0x80579520 public_function:0.
libB::public_function()
libB::public_function()
Consider 3 libraries: `libA`, `libB` and `libC`. Only library `libB` implements and exports the function `public_function()`. A program `dlopen()`s `libA` then `libB` then `libC`. Then the program calls `dlsym(libA, "public_function")` then `dlsym(libB, "public_function")` then `dlsym(libC, "public_function")`. Expected behavior: - `dlsym(libA, "public_function")` and `dlsym(libC, "public_function")` return `NULL`, and - `dlsym(libB, "public_function")` returns a non-`NULL` address. Erroneous behavior: - `dlsym(libC, "public_function")` return `NULL`, and - `dlsym(libA, "public_function")` and `dlsym(libB, "public_function")` returns **the same** non-`NULL` address. Program to reproduce this issue: ``` // dlsym-test1.c #include <stdio.h> #include <dlfcn.h> typedef void (*public_function_t)(); int main() { int i; void* lib[3] = {}; void* lib_name[3] = {"liba.so", "libb.so", "libc.so"}; public_function_t public_function[3] = {}; for (i = 0; i < 3; ++i) { lib[i] = dlopen(lib_name[i], RTLD_NOW | RTLD_LOCAL); } for (i = 0; i < 3; ++i) { if (lib[i] != NULL) { public_function[i] = dlsym(lib[i], "public_function"); } } for (i = 0; i < 3; ++i) { printf("%s:%#x public_function:%#x.\n", lib_name[i], lib[i], public_function[i]); } for (i = 0; i < 3; ++i) { if (public_function[i] != NULL) { (public_function[i])(); } } return 0; } ``` ``` // libb.c #include <stdio.h> void public_function() __attribute__ ((visibility ("default"))); void public_function() { puts("libB::public_function()"); } ``` ``` #!/bin/bash CROSS_COMPILE=... CC=${CROSS_COMPILE}gcc CFLAGS='-fvisibility=hidden -O0 -g -Wextra -Werror' rm *.so dlsym-test1 $CC $CFLAGS -fPIC -shared -o liba.so empty.c $CC $CFLAGS -fPIC -shared -o libb.so libb.c $CC $CFLAGS -fPIC -shared -o libc.so empty.c $CC $CFLAGS -fPIE -pie '-Wl,-rpath=$ORIGIN' -o dlsym-test1 dlsym-test1.c ``` ``` $ ./dlsym-test1 liba.so:0x80579160 public_function:0xb6eb9584. libb.so:0x80579348 public_function:0xb6eb9584. libc.so:0x80579520 public_function:0. libB::public_function() libB::public_function() ```

This project seems dead.

This project seems dead.
Sign in to join this conversation.
No Label
No Milestone
No assignee
1 Participants
Loading...
Cancel
Save
There is no content yet.