Opened 4 years ago

Last modified 3 years ago

#863 new Bug / Defect

cannot link against static openssl library

Reported by: K. C. Tessarek Owned by:
Priority: major Milestone:
Component: Building / Compiling Version: OpenVPN 2.4.0 (Community Ed)
Severity: Not set (select this one, unless your'e a OpenVPN developer) Keywords:
Cc: Steffan Karger

Description

I compile my own openssl (1.0.2k) and create only a static library.

Then I set the PKG_CONFIG_PATH env var, so my openssl version is used:
export PKG_CONFIG_PATH=/usr/local/ssl/lib/pkgconfig/

When I try to configure openvpn 2.4.0 and 2.4.1 (trac has no version for 2.4.1 yet), I get the following error:

checking for SSL_CTX_new... no
configure: error: openssl check failed

(see also attach config.log file)

As soon as I also create a dynamic library for openssl, everything works like a charm. Thus it seems that there's a bug somewhere in checking the availability of SSL_CTX_new in the static lib. I know for a fact that my static library has the symbol SSL_CTX_new.

Attachments (3)

config.log.gz (40.4 KB) - added by K. C. Tessarek 4 years ago.
log file
0001-configure.ac-change-libcrypto-libssl-pkgconfig-disco.patch (984 bytes) - added by Steffan Karger 4 years ago.
0002-configure.ac-fix-building-against-static-openssl.patch (1.6 KB) - added by Steffan Karger 4 years ago.

Download all attachments as: .zip

Change History (24)

Changed 4 years ago by K. C. Tessarek

Attachment: config.log.gz added

log file

comment:1 Changed 4 years ago by Gert Döring

something in your static lib isn't working - if you look into the config log, you'll see that we try to link it, and it fails due to unreferenced symbols inside the library:

/usr/local/ssl/lib/libssl.a(ssl_rsa.o): In function `SSL_CTX_use_serverinfo':
ssl_rsa.c:(.text+0x1e2e): undefined reference to `CRYPTO_realloc'
ssl_rsa.c:(.text+0x1f4d): undefined reference to `ERR_put_error'
ssl_rsa.c:(.text+0x1f7d): undefined reference to `ERR_put_error'

this is outside our control.

It might be the link order - configure calls:

configure:16095: gcc -o conftest -g -O2 -std=c99 -I/usr/local/ssl/include    conftest.c  -L/usr/local/ssl/lib -lcrypto -lssl  >&5

but it *should* call -lssl -lcrypto - from what I read in configure, this is pkg_config's job to provide properly.

As a workaround, it should work to just tell configure what you want:

configure OPENSSL_CFLAGS=-I/usr/local/ssl/include OPENSSL_LIBS="-L/usr/local/ssl/lib -lssl -lcrypto"

and forget about pkg_config.

comment:2 Changed 4 years ago by tincantech

CC: tincantech

comment:3 Changed 4 years ago by Gert Döring

Cc: Steffan Karger added

comment on IRC

19:53 < t355u5> cron2: Just tried your configure workaround and it did not work. Same error as before.
19:53 < t355u5> Your explanation has me a bit puzzled, because I use this library and pkg_config for every other software relying on openssl (Apache httpd, php, dovecot, sendmail, ...), including openvpn 2.3.14. Every other software configures and compiles just fine.
19:53 < t355u5> So how can it work with openvpn 2.3.14 and not with openvpn 2.4.x?
19:53 < t355u5> Please note that using a dynamic ssl lib works fine as well. I really think this is not a problem on my end. If I had issues with any other software, I'd be willing to accept that I screwed up somewhere, but it even works with openvpn 2.3.x.

cc'ing syzzer... maybe he has an idea.

comment:4 Changed 4 years ago by Steffan Karger

Hm, seems like PKG_CHECK_MODULES expects dependecies between modules in the same right-to-left order as the linker expects them. I think the attached patch should resolve your issue. Can you test whether this patch fixes the problem for you too?

comment:5 Changed 4 years ago by K. C. Tessarek

Unfortunatelty the patch did not help.

comment:6 Changed 4 years ago by Steffan Karger

I just created a setup to reproduce the problem, and it showed that changing the linking order was a step in the right direction, but not enough. OpenSSL also needs libdl, but the linker can't detect that based on the .a (it can based on the .so).

The attached patch fixes the problem for me, could you test that it fixes it for you too?

comment:7 Changed 4 years ago by K. C. Tessarek

Great, this worked. Thank you very much.

The final patch should be more generic though. libdl only needs to be linked, if configure encounters a static lib.

comment:8 in reply to:  6 ; Changed 4 years ago by Gert Döring

Replying to syzzer:

I just created a setup to reproduce the problem, and it showed that changing the linking order was a step in the right direction, but not enough. OpenSSL also needs libdl, but the linker can't detect that based on the .a (it can based on the .so).

Why is pkgconfig not telling us that?

comment:9 in reply to:  8 Changed 4 years ago by K. C. Tessarek

Replying to cron2:

Why is pkgconfig not telling us that?

Actually it does.

pkg-config --libs openssl vs pkg-config --libs --static openssl

The problem is with configure.ac. It always assumes dynamic libs. I believe this comes from the fact that if you have a library as static and dynamic versions, the linker will always pick the dynamic lib, unless you explicitly specify the static library.
This logic must have been adopted by the autoconf tools.

You can check if only static libraries are available and if so link libdl as well.

Most packages just link it anyway and put something like this in configure.ac:

AC_SEARCH_LIBS([dlopen], [dl], [LDFLAGS="-ldl $LDFLAGS"], [], [])

comment:10 Changed 4 years ago by Steffan Karger

This is indeed the problem. To me this seems like a pkg-config bug; if pkg-config has only found static libraries, and knows what to link for static libraries, it should do so. The pkg-config developers however seem to think that this is an end-user problem: https://bugs.freedesktop.org/show_bug.cgi?id=19541.

I'm not sure what to do with this, but it seems that this is not easy to fix without a lot of ugliness in configure.ac...

As a side note: for the openvpn executable, we only link to libdl by default 'by accident', because plugins are enabled by default:

configure.ac:

AC_CHECK_LIB(
    [dl],
    [dlopen],
    [DL_LIBS="-ldl"]
)
AC_SUBST([DL_LIBS])

if test "${enable_plugins}" = "yes"; then
    OPTIONAL_DL_LIBS="${DL_LIBS}"
fi

src/openvpn/Makefile.am:

openvpn_LDADD = \
    $(top_builddir)/src/compat/libcompat.la \
    $(SOCKETS_LIBS) \
    $(OPTIONAL_LZO_LIBS) \
    $(OPTIONAL_LZ4_LIBS) \
    $(OPTIONAL_PKCS11_HELPER_LIBS) \
    $(OPTIONAL_CRYPTO_LIBS) \
    $(OPTIONAL_SELINUX_LIBS) \
    $(OPTIONAL_SYSTEMD_LIBS) \
    $(OPTIONAL_DL_LIBS)

I have no idea why our configure.ac is set up this way, and whether a major overhaul should be considered.

comment:11 Changed 4 years ago by K. C. Tessarek

Hmm, a complete overhaul might take a very long time.

It's interesting that I was the first who ran into this problem. It's hard to believe that noone ever tried to link against a static library before.
Usually using dynamic libs is better anway, but sometimes there are reasons for linking against static libs.

I don't know where this leaves fixing this issue. In any case, I suggest to at least change [libcrypto >= 0.9.8, libssl >= 0.9.8], to [openssl >= 0.9.8], on line 862.
Pretty awesome that the ticket id is almost the line number. :-)

I can add libdl when invoking configure.

comment:12 Changed 4 years ago by Steffan Karger

The more I look at pkg-config, the more I believe it's not the right tool when you want to link statically. In the end, I think the best solution is Gert's workaround, but including -ldl:

./configure OPENSSL_CFLAGS=-I/usr/local/ssl/include OPENSSL_LIBS="-L/usr/local/ssl/lib -lssl -lcrypto -ldl"

That's also how I link to static OpenSSL.

(Also note that your export PKG_CONFIG_PATH=/usr/local/ssl/lib/pkgconfig/ approach means that if you also want to link against e.g. lzo or pkcs11-helper, that you should make sure that those .pc files are located there too.)

So I'm tempted to close this ticket a 'wontfix'.

comment:13 Changed 4 years ago by Gert Döring

I wouldn't oppose to wontfix, but we should document the "if you link static openssl libs, you need -ldl" bit somewhere.

comment:14 in reply to:  12 ; Changed 4 years ago by K. C. Tessarek

Replying to syzzer:

The more I look at pkg-config, the more I believe it's not the right tool when you want to link statically.

It all depends on how you call pkgconfig. That's why there's a --static option.
But it needs to know that you want to use and link against static libs.

So the cleanest solution would be to add a configure flag --use-static-libs, in which case you add -ldl. But adding it no matter what works too, since it doesn't hurt to link it. t won't affect the rest of the build at all.

But as you have mentioned earlier, the following change is necessary, otherwise configure will always fail with a static lib, because checking the lib version doesn't work with static libs.

[libcrypto >= 0.9.8, libssl >= 0.9.8] ---> [openssl >= 0.9.8]

comment:15 Changed 4 years ago by K. C. Tessarek

Any update on this? What are your plans?

comment:16 in reply to:  14 ; Changed 4 years ago by Steffan Karger

Replying to tessus:

Replying to syzzer:

The more I look at pkg-config, the more I believe it's not the right tool when you want to link statically.

It all depends on how you call pkgconfig. That's why there's a --static option.
But it needs to know that you want to use and link against static libs.

So the cleanest solution would be to add a configure flag --use-static-libs, in which case you add -ldl. But adding it no matter what works too, since it doesn't hurt to link it. t won't affect the rest of the build at all.

Hm I do not agree there. I'd say the cleanest solution would be if the creator of the openssl.pc file that points to a location where only static openssl libs are placed changes the .pc to always add the -ldl flags. The whole idea of tools like pkg-config is that I do not have to worry about that stuff :)

Since we supply people with a back-up in the form of OPENSSL_CFLAGS and OPENSSL_LIBS, we'll advise people to use that, and leave it at that .

But as you have mentioned earlier, the following change is necessary, otherwise configure will always fail with a static lib, because checking the lib version doesn't work with static libs.

[libcrypto >= 0.9.8, libssl >= 0.9.8] ---> [openssl >= 0.9.8]

This change make sense even outside the scope of this problem, so I'll follow-up to get this into the master and release/2.4 branches.

comment:17 in reply to:  16 Changed 4 years ago by K. C. Tessarek

Replying to syzzer:

Since we supply people with a back-up in the form of OPENSSL_CFLAGS and OPENSSL_LIBS, we'll advise people to use that, and leave it at that .

I totally forgot about those. In that case it makes sense not changing configure.ac.

[libcrypto >= 0.9.8, libssl >= 0.9.8] ---> [openssl >= 0.9.8]

This change make sense even outside the scope of this problem, so I'll follow-up to get this into the master and release/2.4 branches.

Great. Thank you. You can close the ticket, if you want. I don't seem to be able to close it, even though I created it.

comment:18 Changed 4 years ago by David Sommerseth

I think this actually makes a "bigger" issue surface. Our configure script is not targeting static building at all. Yes, we could add some tricks to resolve this for OpenSSL. But this issue is bigger than just that.

We do, as syzzer mentioned, link in a few other libraries as well. The majority of them (OpenSSL, pkcs11-helper, p11-kit, systemd) are most commonly "managed" via pkg-config.

But we also check for these libraries: dl, nsl, socket, resolv, selinux, mbed TLS (mbedtls, mbedx509, mbedcrypto), lzo2, lzo, lz4.

So to fully support static linking properly, we need to do a bigger overhaul of configure.ac. In the case of pkg-config, it is needed to add the --static argument when pkg-config is run. But for the rest of the libraries - it's a bigger job to identify the requirements. Also considering that some of them are for dedicated to their own OS alone (like socket, selinux).

First step would actually be to move as much of these ones over to pkg-config. I don't know anything about libsocket. But libselinux and liblz4 should be doable. For the rest not having a pkg-config file available, special rules needs to be applied when doing a static build.

That said ... just overriding PKG_CONFIG_PATH is not a clever way to go for static linking today. It may or may not work, depending on which options you enable (PKCS#11, systemd at least now). As syzzer already said, their .pc files must also be copied into your new PKG_CONFIG_PATH.

For the time being, I fear the closest to we get to a static build today is just partially static. Which is, IMO, the worst outcome. I can't even think of the troubles ahead if pkcs11-helper is loaded dynamically while OpenSSL is statically linked into the OpenVPN binary.

comment:19 in reply to:  18 Changed 4 years ago by K. C. Tessarek

Replying to dazo:

That said ... just overriding PKG_CONFIG_PATH is not a clever way to go for static linking today. It may or may not work, depending on which options you enable (PKCS#11, systemd at least now). As syzzer already said, their .pc files must also be copied into your new PKG_CONFIG_PATH.

Nope, actually you don't have to do that, unless the libs you want to use are not in the standard /usr/lib64 directory. I only wanted to use a different version of OpenSSL, because the system's one is too old.

For the time being, I fear the closest to we get to a static build today is just partially static. Which is, IMO, the worst outcome. I can't even think of the troubles ahead if pkcs11-helper is loaded dynamically while OpenSSL is statically linked into the OpenVPN binary.

No issues at all, at least none that I could find. I only use static OpenSSL libraries linked to openvpn. Everything else is dynamically linked.
I do the same with OpenSSH, PHP, Apache httpd.

OpenSSL, prior to version 1.1.0, only built a static version unless you explicitly specified it otherwise. At one point security experts suggested to use static OpenSSL libraries, but I'm not sure, if that security paradigm still holds.

comment:20 Changed 3 years ago by K. C. Tessarek

Unfortunately 2.4.2 still does not include the patch.

Do you have an update on this?

comment:21 Changed 3 years ago by Steffan Karger

Hm, commit 79ea67f77ca3afe91222f62e17df885a30409285 did include the [libcrypto >= 0.9.8, libssl >= 0.9.8] ---> [openssl >= 0.9.8] change, but I totally missed that this commit was not backported to release/2.4. It doesn't make sense to backport it either, so I'll create a separate patch for release/2.4. Apologies.

Note: See TracTickets for help on using tickets.