Shipping Gnu/Linux Firefox Plugin with Shared Libraries (For Installation with No Root Access)

Shipping GNU/Linux Firefox plugin with shared libraries (for installation with no root access)

Set RPATH to $ORIGIN/lib so the loader will look for libraries relative to the my file.

Script just unpacks the plugin to $HOME/.mozilla/plugins/myplugin.so and libraries to $HOME/.mozilla/plugins/lib/

rpath can be specified to linker though the gcc by adding Wl,-rpath,'$ORIGIN/lib' ($ should be doubled in a Makefile) and can also be changed after compilation by patchelf.

How to tell Firefox where to find my plugin?

You need to use the pluginspage attribute to tell the browser where to find the plugin. This article will help.

Is it possible to block network access for a shared/dynamic library?

What you ask in the title is not possible, but you can create an API for plugin network access which has a blocking feature on a per plugin base. This means you will not be using Qt's networking classes directly, but create wrappers around them which check if that particular plugin has permission, and if not simply does nothing as networking commands are issued. This also means you have to provide that API to people who will potentially be writing plugins for your application, and forbid them from using Qt's network classes directly, and instead use your wrappers.

Error loading shared libraries with dlopen()

What conditions could cause this behavior?

When you call dlopen("/path_to_plugin/libservices.so", ...), the loader does this:

  1. Open the given path, verify it's a suitable ELF file with correct architecture
  2. Read the dynamic section of that file. For each DT_NEEDED (libconfig.so here),
  3. Scan the list of already opened DSOs, looking for exact match (this fails for you),
    1. If found, increment reference count
    2. Else try to find the needed library on disk.

Since step 3 is failing for you, it's a pretty safe bet that something has corrupted the loader list of already opened DSOs, or someone called dlclose on libconfig.so.

If GDB info shared still lists libconfig.so at step 3, then it's the former. If it doesn't, then it's the latter.

You should be able to verify corruption by looking at _r_debug->r_map elements in GDB, and comparing the entries with GDB info shared output.

The first entries in that list will have the main executable, the VDSO, and directly-linked shared libraries (e.g. libc.so.6 and libdl.so.2). Then you should see the entry for libconfig.so, except its l_name will probably be mangled in some way.

If this is indeed the case, you can find who corrupts the loader list by setting a breakpoint on dlopen("/path/to/libconfig.so",...), verifying that the r_map is correct at that point, and then setting a watchpoint on the memory that gets corrupted later.

On the other hand if you have a rogue dlclose somewhere, then just setting a breakpoint on dlclose should quickly lead you to the problem.

Update:

I'm having a difficult time figuring out how to see the contents of _r_debug->r_map

There are two ways to get access to it:

  1. Install debuginfo packages for your GLIBC. On Ubuntu, apt-get install libc6-dbg should do, or
  2. Compile your program in such a way that the debug info for _r_debug is included in it. For example:

    cat t.c
    int main() { return 0; }

    gcc -g t.c && gdb -q ./a.out
    (gdb) start
    Temporary breakpoint 1 at 0x4004e1: file t.c, line 1.
    Starting program: /tmp/a.out

    Temporary breakpoint 1, main () at t.c:1
    1 int main() { return 0; }
    (gdb) p _r_debug
    $1 = 1 # The program does not reference _r_debug itself,
    # and debuginfo is not installed. This is probably what you see.

Let's fix that:

cat t2.c
#include <link.h>

int main() { return _r_debug.r_version; } // reference needed for debug info

gcc -g t2.c && gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x400561: file t2.c, line 3.
Starting program: /tmp/a.out

Temporary breakpoint 1, main () at t2.c:3
3 int main() { return _r_debug.r_version; }
(gdb) p _r_debug
$1 = {r_version = 1, r_map = 0x7ffff7ffe1c8, r_brk = 140737351960640, r_state = RT_CONSISTENT, r_ldbase = 140737351884800}
(gdb) p _r_debug.r_map[0]
$2 = {l_addr = 0, l_name = 0x7ffff7df6c3d "", l_ld = 0x600e18, l_next = 0x7ffff7ffe758, l_prev = 0x0}


Related Topics



Leave a reply



Submit