Wednesday, August 31, 2022

[SOLVED] Fixing dynamic linker errors when using libc with openssl

Issue

Here's a simple hello world sha1-hasher that's using the openssl library.

#include <openssl/sha.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    system("printf '%s' 'hello world' | sha1sum");

    unsigned char digest[SHA_DIGEST_LENGTH];
    char digest_pr[(SHA_DIGEST_LENGTH)*2+1];
    SHA_CTX ctx;
    if(!SHA1_Init(&ctx)) return 1;
#define STR_STRLEN(A) A, (sizeof(A)/sizeof(*(A))-1)
    if(!SHA1_Update(&ctx,STR_STRLEN("hello"))) return EXIT_FAILURE;
    if(!SHA1_Update(&ctx,STR_STRLEN(" world"))) return EXIT_FAILURE;
    if(!SHA1_Final(digest,&ctx)) return EXIT_FAILURE;
    #define DIGITS "0123456789abcdef"
    for(size_t i=0;i<sizeof(digest);i++){
        digest_pr[i*2+0]=DIGITS[digest[i]/16];
        digest_pr[i*2+1]=DIGITS[digest[i]%16];
    }
    digest_pr[(SHA_DIGEST_LENGTH)*2]='\0';
    puts(digest_pr);
}

On a Mint/Ubuntu with libssl-dev installed, I can compile and link it with $CC sha.c (where CC is one of gcc, tcc, or clang) and then successfully run it, but this didn't work with musl so I grabbed the openssl source (git clone https://github.com/openssl/openssl), configured it with ./config --prefix=/usr/local/musl, built it and installed it and now musl-gcc sha.c -lcrypto works but running LD_LIBRARY_PATH=/usr/local/musl/lib a.out gets me:

Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __fprintf_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: makecontext: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: setcontext: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __register_atfork: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __memcpy_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __strcat_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: secure_getenv: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __vfprintf_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __syslog_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __memset_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __fread_chk: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: getcontext: symbol not found
Error relocating /usr/local/musl/lib/libcrypto.so.1.1: __sprintf_chk: symbol not found

What's causing this and how can I fix it?


Solution

It seems that your OpenSSL is not built against musl-libc.

The musl-libc has its own dynamic linker (see https://wiki.musl-libc.org/faq.html), we could create a soft link for the musl dynamic linker. (-syslibdir is the directory in which the dynamic library, e.g. ld-musl-x86_64.so.1, is, see https://wiki.musl-libc.org/getting-started.html)

sudo ln -sf <YOUR-MUSL-LIBC-syslibdir/ld-musl-x86_64.so.1> /usr/bin/musl-ldd  

Then you could see whether openssl is built against musl-libc. When I build OpenSSL using glibc, it shows the following error

$ musl-ldd <YOUR-OPENSSL-SRC>/libcrypto.so.1.1
        musl-ldd (0x7fcd5a749000)
        libdl.so.2 => musl-ldd (0x7fcd5a749000)
        libpthread.so.0 => musl-ldd (0x7fcd5a749000)
        libc.so.6 => musl-ldd (0x7fcd5a749000)
Error relocating ./libcrypto.so.1.1: makecontext: symbol not found
Error relocating ./libcrypto.so.1.1: setcontext: symbol not found
Error relocating ./libcrypto.so.1.1: __register_atfork: symbol not found
Error relocating ./libcrypto.so.1.1: getcontext: symbol not found

And the glib dynamic linker works fine,

$ ldd <YOUR-OPENSSL-SRC>/libcrypto.so.1.1
        linux-vdso.so.1 (0x00007ffd395a6000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff6e6e64000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff6e6e41000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff6e6c4f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff6e71d7000)

To build OpenSSL using musl-libc, we have to also specify the location of linux headers to avoid errors like <linux/mman.h>

I only have attempted to build OpenSSL using Clang and Musl-libc, here is the clang wrapper I used https://gist.github.com/randoruf/d1aa4e8acb0a852addcd2b84fc003719.

(taken from https://qiita.com/kakinaguru_zo/items/399ab7ea716a56aef50c which is written by kakinaguru_zo)

But there are still a few issues in the clang-wrapper.

This wrapper will link the startfile (e.g. Scrt1.o) regardless of building libraries or executables. Apparently, only executables need startfile. Hence, if you use this wrapper, you may encounter the following strange error (main symbol not found):

$ musl-clang mylibrary.c -shared -fPIC -o libmylibrary.so
$ musl-ldd libmylibrary.so
        ld-musl-x86_64.so.1 (0x7f49faef7000)
        libc.so => ld-musl-x86_64.so.1 (0x7f49faef7000)
Error relocating libmylibrary.so: main: symbol not found

Since the library has the startfile, it may have an entry to main. This is the reason why the main symbol is not found.

Another issue is that test_errstr, test_ca, test_ssl_new will not pass due to the fact that the operating system and its software are built against glibc. Details are posted on my blog https://randoruf.github.io/2022/08/23/musl-libc-ubuntu.html#about-the-test-case-in-openssl

The final issue is that this wrapper only supports c language. Another wrapper may be helpful see https://github.com/esjeon/musl-clang/blob/master/musl-clang



Answered By - Randolph
Answer Checked By - Terry (WPSolving Volunteer)