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

provide an option to set argv[0] #91

Closed
cgwalters opened this issue Aug 12, 2016 · 2 comments · Fixed by #598
Closed

provide an option to set argv[0] #91

cgwalters opened this issue Aug 12, 2016 · 2 comments · Fixed by #598

Comments

@cgwalters
Copy link
Collaborator

In some cases, programs vary behavior based on argv[0], but we currently do:

  if (execvp (argv[0], argv) == -1)

requiring them to be the same. We should add --argv0 /usr/bin/blah or so.

@cgwalters
Copy link
Collaborator Author

(I hit this when porting rpm-ostree code to use bwrap that had an API that took argv0 and char **argv separately, and while I think we can just conflate them, there's no reason not to support this)

@rhatdan
Copy link
Member

rhatdan commented Aug 12, 2016

Sounds reasonable.

quag added a commit to quag/bubblewrap that referenced this issue Sep 27, 2023
Fixes containers#91

I realise that an initial Github issue was created for this feature in
2016 and it doesn't appear to have come up again since. However, NixOS
is weird and creates a usecase for separating the executable path in the
container from the command name. The nix-bubblewrap project also ran
into the same issue, and has a note about it in their README:
https://github.com/fgaz/nix-bubblewrap#troubeshooting

Explanation

NixOS doesn't install executable binaries into /usr/bin, and instead
installs each package into it's own immutable folder under
/nix/store/${hash}-${package}-${version}/bin. NixOS also provides a
command to list the packages a given package depends on. This makes it
trivial to use bwrap to only --ro-bind the packages required for a given
executable.

This all works wonderfully, except for two complications. To create a
$PATH for a user's shell to use, NixOS creates folders of symlinks
(often to other symlinks) for $PATH to reference. These folders of
symlinks to executables could be --ro-bind into the container, but
they're only needed to locate the initial executable for the command. We
can just $(realpath $(which command)) and pass that to bwrap, except
that fails for executables that change their behavior based on the
command name used (say, bash behaving as sh, xz behaving as unxz, or
coreutils behaving as date, df, cat, ...).

We could also have NixOS build a $PATH for just the packages needed, and
use that when running bwrap, but we've already located the binary, and
have the command name, we just need to have bwrap use the executable
path and the argv[0] provided.

Concrete example

The $PATH points to a folder of symlinks to symlinks to symlinks. The
two levels of symlink folders don't need to be in the container, they're
just needed to locate the executable for the command. In this case, date
command is actually a symlink to the coreutils executable.

% which date
/home/quag/.nix-profile/bin/date
% readlink $(which date)
/nix/store/8nzn8ghzknqgjsg1iv124qy0fjli3dwn-home-manager-path/bin/date
% readlink $(readlink $(which date))
/nix/store/apn3p2b40xvirn7w740wv2gy330ppib5-coreutils-9.3/bin/date
% readlink $(readlink $(readlink $(which date)))
/nix/store/apn3p2b40xvirn7w740wv2gy330ppib5-coreutils-9.3/bin/coreutils

Coreutils only needs the following file system to be able to execute.

% nix-store --query --requisites $(realpath $(which coreutils))
/nix/store/3wwfqhdym0sbis4bad1may3ll8rki8y1-gcc-12.3.0-libgcc
/nix/store/jbwb8d8l28lg9z0xzl784wyb9vlbwss6-xgcc-12.3.0-libgcc
/nix/store/s2gi8pfjszy6rq3ydx0z1vwbbskw994i-libunistring-1.1
/nix/store/k8ivghpggjrq1n49xp8sj116i4sh8lia-libidn2-2.3.4
/nix/store/aw2fw9ag10wr9pf0qk4nk5sxi0q0bn56-glibc-2.37-8
/nix/store/srrs7gn04rwa4f6zhsjkdacxydwrmzhj-attr-2.5.1
/nix/store/aj6gbshd8hvifpa1d8vy0iv688sm81wp-acl-2.3.1
/nix/store/xpxln7rqi3pq4m0xpnawhxb2gs0mn1s0-gcc-12.3.0-lib
/nix/store/yqa5m326a0ynn4whm4fikyjfljfc6i3q-gmp-with-cxx-6.3.0
/nix/store/apn3p2b40xvirn7w740wv2gy330ppib5-coreutils-9.3

These ten directories can be --ro-bind into the container and the
--ro-binds can be generated with sed.

% function nix-bwrap-args() {
    nix-store --query --requisites $(realpath $(which $1)) \
    | sed 's/.*/--ro-bind & &/' \
    | tr '\n' ' '
}

However, despite having all the files needed in the container, bwrap
resolves date using $PATH to /home/quag/.nix-profile/bin/date which
isn't in the container.

% bwrap $(nix-bwrap-args date) date
bwrap: execvp date: No such file or directory

If we resolve the date command to the executable in the container (the
coreutils binary), then that fails, as it doesn't know which command it
is meant to be impersonating.

% bwrap $(nix-bwrap-args date) $(realpath $(which date))
Try '/nix/store/apn3p2b40xvirn7w740wv2gy330ppib5-coreutils-9.3/bin/coreutils --help' for more information.

If we add an --exec command that takes the executable within the
container to run, and then passes through the command without resolving
it, everything works. A minimal container, with executable resolution
happening before entering the container while retaining the command
name.

% bwrap $(nix-bwrap-args date) --exec $(realpath $(which date)) date
Wed Sep 27 05:50:49 UTC 2023

FAQ

Q1. Doesn't the running process need a valid $PATH to locate other
commands it depends on?

Surprisingly no. To support installing multiple versions of the same
package, all references to other packages (including executables) are
compiled into the binaries as paths into /nix/store/*/*. This means that
after the program starts, $PATH is not needed again.
quag added a commit to quag/bubblewrap that referenced this issue Sep 27, 2023
…v[0]

Fixes containers#91

Some tools change their behavior based on the value of argv[0], for
example bash behaves as sh when argv[0] is "sh", xz behaves as unxz, and
coreutils behaves as date, df, cat and so on.
quag added a commit to quag/bubblewrap that referenced this issue Sep 28, 2023
Fixes containers#91

Add the ability to overwrite argv[0] when starting a process in a
container. Using --argv0 to be consistent with ld.so --argv0.

Overwriting argv[0] is useful as some tools change their behavior based
on the value of argv[0]. For example, when bash is symlinked to sh it
behaves as sh. Similarly, unxz is a symlink to xz and changes the
default from compressing to decompressing. An extreme example is on many
systems, date, df, cat and so on are all symlinks to the coreutils
binary.

Example usage: bwrap --bind / / --argv0 sh bash

Signed-off-by: Jonathan Wright <[email protected]>
quag added a commit to quag/bubblewrap that referenced this issue Sep 28, 2023
Fixes containers#91

Add the ability to overwrite argv[0] when starting a process in a
container. Using --argv0 to be consistent with ld.so --argv0.

Overwriting argv[0] is useful as some tools change their behavior based
on the value of argv[0]. For example, when bash is symlinked to sh it
behaves as sh. Similarly, unxz is a symlink to xz and changes the
default from compressing to decompressing. An extreme example is on many
systems, date, df, cat and so on are all symlinks to the coreutils
binary.

Example usage: bwrap --bind / / --argv0 sh bash

Signed-off-by: Jonathan Wright <[email protected]>
quag added a commit to quag/bubblewrap that referenced this issue Sep 30, 2023
Fixes containers#91

Add the ability to overwrite argv[0] when starting a process in a
container. Using --argv0 to be consistent with ld.so --argv0.

Overwriting argv[0] is useful as some tools change their behavior based
on the value of argv[0]. For example, when bash is symlinked to sh it
behaves as sh. Similarly, unxz is a symlink to xz and changes the
default from compressing to decompressing. An extreme example is on many
systems, date, df, cat and so on are all symlinks to the coreutils
binary.

Example usage: bwrap --bind / / --argv0 sh bash

Signed-off-by: Jonathan Wright <[email protected]>
@smcv smcv closed this as completed in #598 Oct 1, 2023
quag added a commit to quag/nix-bubblewrap that referenced this issue Oct 2, 2023
Bubblewrap is adding a new --argv0 option. This means that the command
name can remain unchanged, while the exe to execute can have realpath
applied to it.

Test-1: nix-bwrap date    # coreutils provided on NixOS
Test-2: nix-bwrap find /  # /run/current-system/sw/bin/find on NixOS

Note that --argv0 was only merged into bubblewrap today and there has not
been an offical release. See:
containers/bubblewrap#91
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants