emk / rust-musl-builder

Docker images for compiling static Rust binaries using musl-libc and musl-gcc, with static versions of useful C libraries. Supports openssl and diesel crates.
Apache License 2.0
1.54k stars 193 forks source link

Ubuntu 20.04 #120

Closed asaaki closed 2 years ago

asaaki commented 3 years ago

Use latest ubuntu LTS release (20.04)

Also:


Travis CI checks can be found under my PR of the fork: asaaki/rust-musl-builder#1 If you want to use the image already:

FROM ghcr.io/asaaki/rust-musl-builder:latest

Closes #98

asaaki commented 3 years ago

Running ./test-image gave me a fail though:

--- Test case for sqlx:
ldd says:
    /lib/ld-musl-x86_64.so.1 (0x7f87879d6000)
[FAIL] Executable is not static!
The command "bash ./test-image" exited with 1.

As you also mention in #98.

But I think that might be a red herring.

Here's an output of another binary (randomly chosen from /usr/bin) which does seem to be not fully static as it needs a libc on the system:

$ ldd /usr/bin/getconf
        /lib/ld-musl-x86_64.so.1 (0x7fa18cd57000)
        libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fa18cd57000)

Interwebz says that we should also check the output of readelf and look for INTERP in the headers It's part of the binutils, so has to be installed into the alpine stage.

$ readelf -l /usr/local/bin/using-sqlx 

Elf file type is DYN (Shared object file)
Entry point 0x63062
There are 10 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000062750 0x0000000000062750  R      0x1000
  LOAD           0x0000000000063000 0x0000000000063000 0x0000000000063000
                 0x00000000002442bf 0x00000000002442bf  R E    0x1000
  LOAD           0x00000000002a8000 0x00000000002a8000 0x00000000002a8000
                 0x000000000013c4d0 0x000000000013c4d0  R      0x1000
  LOAD           0x00000000003e4e20 0x00000000003e5e20 0x00000000003e5e20
                 0x0000000000053440 0x00000000000551e0  RW     0x1000
  DYNAMIC        0x0000000000435c78 0x0000000000436c78 0x0000000000436c78
                 0x0000000000000130 0x0000000000000130  RW     0x8
  NOTE           0x0000000000000270 0x0000000000000270 0x0000000000000270
                 0x0000000000000024 0x0000000000000024  R      0x4
  TLS            0x00000000003e4e20 0x00000000003e5e20 0x00000000003e5e20
                 0x0000000000000005 0x00000000000002d8  R      0x20
  GNU_EH_FRAME   0x0000000000377950 0x0000000000377950 0x0000000000377950
                 0x000000000000ba1c 0x000000000000ba1c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x00000000003e4e20 0x00000000003e5e20 0x00000000003e5e20
                 0x00000000000531e0 0x00000000000531e0  R      0x1

using-sqlx has no INTERP there.

While …

readelf -l /usr/bin/getconf 

Elf file type is DYN (Shared object file)
Entry point 0x22e8
There are 10 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x0000000000000230 0x0000000000000230  R      0x8
  INTERP         0x0000000000000270 0x0000000000000270 0x0000000000000270
                 0x0000000000000019 0x0000000000000019  R      0x1
      [Requesting program interpreter: /lib/ld-musl-x86_64.so.1]
<snip>

… does have it, and you can even see a path encoded there.

From https://greek0.net/elf.html:

If an INTERP entry is present, the interpreter is loaded too. Statically linked binaries can do without an interpreter; […]

Another way to check is to run readelf -d <path/to/executable> and look for (NEEDED), only dynamically linked programs should have entries, statically linked ones have none.

And yet another option is to use scanelf from pax-utils (scanelf -n <path>, scanelf -i <path>).

I also ran an example app in different variations of busybox:

FROM busybox
FROM busybox:musl
FROM busybox:uclibs
FROM busybox:glibc

And there are no problems, which I would expect if it was not truly static.

Even FROM scratch works fine.

Fun fact:

ldd on alpine/musl is the following shell script:

$ cat /usr/bin/ldd
#!/bin/sh
exec /lib/ld-musl-x86_64.so.1 --list "$@"

So I believe that this lib/executable is injecting itself into the ldd output.

Last but not least I ran it under a debian:stretch-slim and called ldd there:

ldd /usr/local/bin/using-sqlx
        statically linked

(debian's ldd is a slightly more elaborate script.)


I adjusted the test-image script and the Dockerfiles of both static tests to use debian:stretch-slim for the better ldd checker.


Under asaaki/rust-musl-builder#1 you can see my travis runs, which are green for the proposed changes.

jman-schief commented 3 years ago

I've tested this updated image to build the diesel_cli and it seems to work (thanks @asaaki !)

I wouldn't mind seeing this reviewed and merged (notable change: the updated openssl library)

EDIT: worth mentioning that perhaps openssl could also be safely upgraded to latest 1.1.1k (I've tested it and the built binary seems to be fine)

asaaki commented 3 years ago

@jman-schief Updated to have 1.1.1k used.

emk commented 2 years ago

Thank you to everyone for working on this, and to @asaaki for figuring out the static linking check! I've prepared a new PR inspired by this one but based off the latest main branch. You can find it at https://github.com/emk/rust-musl-builder/pull/134.

I plan to release this when Rust 1.58.0 is released, to allowing existing users to easily stick with 1.57.0 if they want.

asaaki commented 2 years ago

For some of the tiny tweaks and consistency changes do you want me to open new PRs after you merged your update PR?

(btw this one was already rebased to latest main, I can also undo some changes you don't like to make it into a mergeable state)