Shared Libraries

https://amir.rachum.com/shared-libraries/

Is an educational document, good to work through to better understand compiling and linking shared libraries. To recap, and using C instead of C++ one needs a program that uses a library, plus a few supporting scripts:

shared-libraries.tar.gz

ELF Spotting

Probably you do not need to know much about ELF unless you are getting deep into ELF guts. It may however be instructive to compare a program on OpenBSD with what they list for a Linux. The NEEDED libraries are good to know about:

    $ readelf -d main | fgrep NEEDED
     0x0000000000000001 (NEEDED)     Shared library: [libmyrand.so]
     0x0000000000000001 (NEEDED)     Shared library: [libc.so.97.0]
    $ readelf -d `which httpd` | fgrep NEEDED
     0x0000000000000001 (NEEDED)     Shared library: [libevent.so.4.1]
     0x0000000000000001 (NEEDED)     Shared library: [libtls.so.26.2]
     0x0000000000000001 (NEEDED)     Shared library: [libssl.so.53.2]
     0x0000000000000001 (NEEDED)     Shared library: [libcrypto.so.50.2]
     0x0000000000000001 (NEEDED)     Shared library: [libutil.so.16.0]
     0x0000000000000001 (NEEDED)     Shared library: [libc.so.97.0]
    $ readelf -d /bin/ksh | fgrep NEEDED
    $ 

This is from OpenBSD 7.3. It is good to see what other binaries on the system use by way of libraries. ksh(1) in particular is a static compile, which has pros and cons. Having a working shell might be nice if /usr is not mounted or libc is messed up, though if libc is messed up you may need to use ed(1) instead of your fancy text editor—or, more likely, to reinstall or to mount the bad partition on a system with usable tools.

LDD Sidequest

See ld.so(1) for how things are done on OpenBSD.

    $ ldd `which httpd`
    /usr/sbin/httpd:
     Start            End              Type  Open Ref GrpRef Name
      000000828e0c5000 000000828e0f5000 exe   1    0   0     /usr/sbin/httpd
      000001a3bb5bd000 000001a3bb5ce000 rlib  0    1   0     /usr/lib/libevent.so.4.1
    ... 
    $ ldd main
    main:
    ld.so: main: can't load library 'libmyrand.so'
    main: signal 9

ldd(1) may not be safe to run on untrusted binaries, by the way. The ELF tools are also pretty complicated and may have security vulns. So if you are inspecting untrusted binaries, maybe do that on an isolated test system?

LD_DEBUG may be good to know about, but is maybe less useful on OpenBSD. There are other environment variables detailed in ld.so(1).

    $ LD_DEBUG=1 ldd main
    ...
    loading: libmyrand.so required by main
    ld.so: main: can't load library 'libmyrand.so'
    main: signal 9
    doing dtors

There is also process tracing to show what a binary is up to; this should show the directory names that are searched through:

    $ ktrace ./main
    ...
    $ kdump | fgrep NAMI
    ...
    $ LD_LIBRARY_PATH=foobar ktrace ./main
    ...
    $ kdump | fgrep foobar
      3804 main     NAMI  "foobar"
      3804 main     NAMI  "foobar"

Run, path run!

    $ readelf -d main | egrep -i 'run|path'
     0x000000000000001d (RUNPATH)            Library runpath: [.]

rpath happens before LD_LIBRARY_PATH, and runpath after. So LD_LIBRARY_PATH can only modify runpath. I generally avoid using LD_LIBRARY_PATH where possible, as it slows down library searches for everything that is run with that environment variable set. This could lead to less than ideal performance should libraries be present on a NFS server, or if an application runs all sorts of other programs that then all go and check on the directories listed in LD_LIBRARY_PATH.

$ORIGIN

$ORIGIN is pretty neat, if you want a library relative to where the program lives. On OpenBSD this needs -Wl,-z,origin set for $ORIGIN to be honored:

    $ cc -o main main.o -lmyrand -L. -Wl,-z,origin -Wl,-rpath,\$ORIGIN
    $ readelf -d main | grep -i orig
     0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN]
     0x000000000000001e (FLAGS)              ORIGIN
     0x000000006ffffffb (FLAGS_1)            Flags: ORIGIN PIE

Various magical permission bits (suid, for example) will of course disable various linker tomfoolery. This avoids gaping security holes where an attacker could simply LD_PRELOAD a library of their choice. Duplicate environment variables can also be a problem here. Attacks may still possible if a user can trick a sysadmin into running something; it may be beneficial to first switch to their user account to run something they claim problems with.

More

https://begriffs.com/posts/2021-07-04-shared-libraries.html

tags #openbsd