Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: Ensure that binaries are run against their build-time ABI #897

Merged
merged 2 commits into from
Oct 21, 2021

Conversation

debarshiray
Copy link
Member

@debarshiray debarshiray commented Oct 21, 2021

The /usr/bin/toolbox binary is not only used to interact with toolbox
containers and images from the host. It's also used as the entry point
of the containers by bind mounting the binary from the host into the
container. This means that the /usr/bin/toolbox binary on the host must
also work inside the container, even if they have different operating
systems.

In the past, this worked perfectly well with the POSIX shell
implementation because it got intepreted by whichever /bin/sh was
available. However, the Go implementation, can run into ABI
compatibility issues because binaries built on newer toolchains aren't
meant to be run against older runtimes.

The previous approach [1] of restricting the versions of the glibc
symbols that are linked against isn't actually supported by glibc, and
breaks if the early process start-up code changes. This is seen in
glibc-2.34, which is used by Fedora 35 onwards, where a new version of
the __libc_start_main symbol [2] was added as part of some security
hardening:

  $ objdump -T ./usr/bin/toolbox | grep GLIBC_2.34
  0000000000000000      DF *UND*        0000000000000000  GLIBC_2.34
    __libc_start_main
  0000000000000000      DF *UND*        0000000000000000  GLIBC_2.34
    pthread_detach
  0000000000000000      DF *UND*        0000000000000000  GLIBC_2.34
    pthread_create
  0000000000000000      DF *UND*        0000000000000000  GLIBC_2.34
    pthread_attr_getstacksize

This means that /usr/bin/toolbox binaries built against glibc-2.34 on
newer Fedoras fail to run against older glibcs in older Fedoras.

Another option is to make the host's runtime available inside the
toolbox container and ensure that the binary always runs against it.

Luckily, almost all supported containers have the host's /usr available
at /run/host/usr. This is exploited by embedding RPATHs or RUNPATHs to
/run/host/usr/lib and /run/host/usr/lib64 in the binary, and changing
the path of the dynamic linker (ie., PT_INTERP) to the one inside
/run/host.

Unfortunately, there can only be one PT_INTERP entry inside the
binary, so there must be a /run/host on the host too. Therefore, a
/run/host symbolic link is created on the host that points to the
host's /.

Based on ideas from Alexander Larsson and Ray Strode.

[1] Commit 6ad9c63
#534

[2] glibc commit 035c012e32c11e84
https://sourceware.org/git/?p=glibc.git;a=commit;h=035c012e32c11e84
https://sourceware.org/bugzilla/show_bug.cgi?id=23323

#821

The subsequent commit will add an entry to create a /run/host symbolic
link on the host that points to /, and it will require explicitly
skipping some of the columns. Doing the same for the existing entry
will make the file more readable.

containers#821
@debarshiray
Copy link
Member Author

It's necessary to copy data/tmpfiles.d/toolbox.conf to /usr/lib/tmpfiles.d/toolbox.conf and run sudo systemd-tmpfiles --create before testing this out.

@softwarefactory-project-zuul
Copy link

Build failed.

@HarryMichal HarryMichal added 2. Under The Hood Multiple areas of the app are influenced by this ticket 3. Bugfix Fixes a bug 6. Major Change May cause breakage labels Oct 21, 2021
@HarryMichal HarryMichal force-pushed the wip/rishi/run-host-glibc branch from 917c3ec to b17f6c2 Compare October 21, 2021 19:17
@softwarefactory-project-zuul
Copy link

Build failed.

@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from b17f6c2 to 9d0aa90 Compare October 21, 2021 20:03
@HarryMichal HarryMichal force-pushed the wip/rishi/run-host-glibc branch from 9d0aa90 to 0f8987d Compare October 21, 2021 20:12
@softwarefactory-project-zuul
Copy link

Build failed.

@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from 0f8987d to cc357eb Compare October 21, 2021 20:34
@softwarefactory-project-zuul
Copy link

Build failed.

@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from cc357eb to e15c359 Compare October 21, 2021 20:52
@softwarefactory-project-zuul
Copy link

Build failed.

@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from e15c359 to 2f82dac Compare October 21, 2021 22:02
@softwarefactory-project-zuul
Copy link

Build failed.

HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 21, 2021
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 21, 2021
@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from 2f82dac to 022f818 Compare October 21, 2021 23:12
The /usr/bin/toolbox binary is not only used to interact with toolbox
containers and images from the host. It's also used as the entry point
of the containers by bind mounting the binary from the host into the
container. This means that the /usr/bin/toolbox binary on the host must
also work inside the container, even if they have different operating
systems.

In the past, this worked perfectly well with the POSIX shell
implementation because it got intepreted by whichever /bin/sh was
available. However, the Go implementation, can run into ABI
compatibility issues because binaries built on newer toolchains aren't
meant to be run against older runtimes.

The previous approach [1] of restricting the versions of the glibc
symbols that are linked against isn't actually supported by glibc, and
breaks if the early process start-up code changes. This is seen in
glibc-2.34, which is used by Fedora 35 onwards, where a new version of
the __libc_start_main symbol [2] was added as part of some security
hardening:
  $ objdump -T ./usr/bin/toolbox | grep GLIBC_2.34
  0000000000000000      DF *UND*	0000000000000000  GLIBC_2.34
    __libc_start_main
  0000000000000000      DF *UND*	0000000000000000  GLIBC_2.34
    pthread_detach
  0000000000000000      DF *UND*	0000000000000000  GLIBC_2.34
    pthread_create
  0000000000000000      DF *UND*	0000000000000000  GLIBC_2.34
    pthread_attr_getstacksize

This means that /usr/bin/toolbox binaries built against glibc-2.34 on
newer Fedoras fail to run against older glibcs in older Fedoras.

Another option is to make the host's runtime available inside the
toolbox container and ensure that the binary always runs against it.

Luckily, almost all supported containers have the host's /usr available
at /run/host/usr. This is exploited by embedding RPATHs or RUNPATHs to
/run/host/usr/lib and /run/host/usr/lib64 in the binary, and changing
the path of the dynamic linker (ie., PT_INTERP) to the one inside
/run/host.

Unfortunately, there can only be one PT_INTERP entry inside the
binary, so there must be a /run/host on the host too. Therefore, a
/run/host symbolic link is created on the host that points to the
host's /.

Based on ideas from Alexander Larsson and Ray Strode.

[1] Commit 6ad9c63
    containers#534

[2] glibc commit 035c012e32c11e84
    https://sourceware.org/git/?p=glibc.git;a=commit;h=035c012e32c11e84
    https://sourceware.org/bugzilla/show_bug.cgi?id=23323

containers#821
@debarshiray debarshiray force-pushed the wip/rishi/run-host-glibc branch from 022f818 to 6063eb2 Compare October 21, 2021 23:20
@softwarefactory-project-zuul
Copy link

Build failed.

@debarshiray debarshiray merged commit 6063eb2 into containers:main Oct 21, 2021
@debarshiray debarshiray deleted the wip/rishi/run-host-glibc branch October 21, 2021 23:50
@debarshiray
Copy link
Member Author

We still need to unbreak the CI but let's at least unblock the users now.

HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
adjustmnets to the Toolbx binary that it requires presence of /run/host
in both the host filesystem and the filesystem in a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. This lead
to the realization that the playbook structure is needlessly
separated and can be unified as there is close to no benefit in keeping
it separated.

containers#898
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
adjustmnets to the Toolbx binary that it requires presence of /run/host
in both the host filesystem and the filesystem in a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. This lead
to the realization that the playbook structure is needlessly
separated and can be unified as there is close to no benefit in keeping
it separated.

containers#898
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
adjustmnets to the Toolbx binary that it requires presence of /run/host
in both the host filesystem and the filesystem in a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. This lead
to the realization that the playbook structure is needlessly
separated and can be unified as there is close to no benefit in keeping
it separated.

containers#898
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
PR containers#897 made adjustmnets to the Toolbx binary that it requires presence
of /run/host in both the host filesystem and the filesystem in
a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. For the run
to be effective 'data/tmpfiles.d/toolbox.conf' has to be installed in
a location visible to systemd-tmpfiles. Therefore, the call to
'systemd-tmpfiles --create' had to be placed after the install step.
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
PR containers#897 made adjustmnets to the Toolbx binary that it requires presence
of /run/host in both the host filesystem and the filesystem in
a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. For the run
to be effective 'data/tmpfiles.d/toolbox.conf' has to be installed in
a location visible to systemd-tmpfiles. Therefore, the call to
'systemd-tmpfiles --create' had to be placed after the install step.
HarryMichal added a commit to HarryMichal/toolbox that referenced this pull request Oct 22, 2021
PR containers#897 made adjustmnets to the Toolbx binary that it requires presence
of /run/host in both the host filesystem and the filesystem in
a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. For the run
to be effective 'data/tmpfiles.d/toolbox.conf' has to be installed in
a location visible to systemd-tmpfiles. Therefore, the call to
'systemd-tmpfiles --create' had to be placed after the install step.

containers#898
HarryMichal added a commit that referenced this pull request Oct 22, 2021
PR #897 made adjustmnets to the Toolbx binary that it requires presence
of /run/host in both the host filesystem and the filesystem in
a container.

The presence of the directory is assured by systemd-tmpfiles by
running it before the binary is started for the first time. For the run
to be effective 'data/tmpfiles.d/toolbox.conf' has to be installed in
a location visible to systemd-tmpfiles. Therefore, the call to
'systemd-tmpfiles --create' had to be placed after the install step.

#898
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2. Under The Hood Multiple areas of the app are influenced by this ticket 3. Bugfix Fixes a bug 6. Major Change May cause breakage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants