Skip to content

Commit

Permalink
Merge pull request #16030 from abbradar/fhs-refactor
Browse files Browse the repository at this point in the history
Improvements for FHS user chrootenv
  • Loading branch information
abbradar committed Jun 11, 2016
2 parents 9fbd5cf + 75ea052 commit b341de8
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 308 deletions.
84 changes: 33 additions & 51 deletions doc/functions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -171,42 +171,18 @@ c = lib.makeOverridable f { a = 1; b = 2; }</programlisting>


<section xml:id="sec-fhs-environments">
<title>buildFHSChrootEnv/buildFHSUserEnv</title>
<title>buildFHSUserEnv</title>

<para>
<function>buildFHSChrootEnv</function> and
<function>buildFHSUserEnv</function> provide a way to build and run
FHS-compatible lightweight sandboxes. They get their own isolated root with
binded <filename>/nix/store</filename>, so their footprint in terms of disk
<function>buildFHSUserEnv</function> provides a way to build and run
FHS-compatible lightweight sandboxes. It creates an isolated root with
bound <filename>/nix/store</filename>, so its footprint in terms of disk
space needed is quite small. This allows one to run software which is hard or
unfeasible to patch for NixOS -- 3rd-party source trees with FHS assumptions,
games distributed as tarballs, software with integrity checking and/or external
self-updated binaries.
</para>

<para>
<function>buildFHSChrootEnv</function> allows to create persistent
environments, which can be constructed, deconstructed and entered by
multiple users at once. A downside is that it requires
<literal>root</literal> access for both those who create and destroy and
those who enter it. It can be useful to create environments for daemons that
one can enter and observe.
</para>

<para>
<function>buildFHSUserEnv</function> uses Linux namespaces feature to create
self-updated binaries. It uses Linux namespaces feature to create
temporary lightweight environments which are destroyed after all child
processes exit. It does not require root access, and can be useful to create
sandboxes and wrap applications.
</para>

<para>
Those functions both rely on <function>buildFHSEnv</function>, which creates
an actual directory structure given a list of necessary packages and extra
build commands.
<function>buildFHSChrootEnv</function> and <function>buildFHSUserEnv</function>
both accept those arguments which are passed to
<function>buildFHSEnv</function>:
processes exit, without root user rights requirement. Accepted arguments are:
</para>

<variablelist>
Expand All @@ -220,14 +196,16 @@ c = lib.makeOverridable f { a = 1; b = 2; }</programlisting>
<term><literal>targetPkgs</literal></term>

<listitem><para>Packages to be installed for the main host's architecture
(i.e. x86_64 on x86_64 installations).</para></listitem>
(i.e. x86_64 on x86_64 installations). Along with libraries binaries are also
installed.</para></listitem>
</varlistentry>

<varlistentry>
<term><literal>multiPkgs</literal></term>

<listitem><para>Packages to be installed for all architectures supported by
a host (i.e. i686 and x86_64 on x86_64 installations).</para></listitem>
a host (i.e. i686 and x86_64 on x86_64 installations). Only libraries are
installed by default.</para></listitem>
</varlistentry>

<varlistentry>
Expand All @@ -240,29 +218,33 @@ c = lib.makeOverridable f { a = 1; b = 2; }</programlisting>
<varlistentry>
<term><literal>extraBuildCommandsMulti</literal></term>

<listitem><para>Like <literal>extraBuildCommandsMulti</literal>, but
<listitem><para>Like <literal>extraBuildCommands</literal>, but
executed only on multilib architectures.</para></listitem>
</varlistentry>

<varlistentry>
<term><literal>extraOutputsToInstall</literal></term>

<listitem><para>Additional derivation outputs to be linked for both
target and multi-architecture packages.</para></listitem>
</varlistentry>

<varlistentry>
<term><literal>extraInstallCommands</literal></term>

<listitem><para>Additional commands to be executed for finalizing the
derivation with runner script.</para></listitem>
</varlistentry>

<varlistentry>
<term><literal>runScript</literal></term>

<listitem><para>A command that would be executed inside the sandbox and
passed all the command line arguments. It defaults to
<literal>bash</literal>.</para></listitem>
</varlistentry>
</variablelist>

<para>
Additionally, <function>buildFHSUserEnv</function> accepts
<literal>runScript</literal> parameter, which is a command that would be
executed inside the sandbox and passed all the command line arguments. It
default to <literal>bash</literal>.
</para>
<para>
It also uses <literal>CHROOTENV_EXTRA_BINDS</literal> environment variable
for binding extra directories in the sandbox to outside places. The format of
the variable is <literal>/mnt=test-mnt:/data</literal>, where
<literal>/mnt</literal> would be mounted as <literal>/test-mnt</literal>
and <literal>/data</literal> would be mounted as <literal>/data</literal>.
<literal>extraBindMounts</literal> array argument to
<function>buildFHSUserEnv</function> function is prepended to this variable.
Latter entries take priority if defined several times -- i.e. in case of
<literal>/data=data1:/data=data2</literal> the actual bind path would be
<literal>/data2</literal>.
</para>
<para>
One can create a simple environment using a <literal>shell.nix</literal>
like that:
Expand Down
48 changes: 0 additions & 48 deletions pkgs/build-support/build-fhs-chrootenv/default.nix

This file was deleted.

22 changes: 0 additions & 22 deletions pkgs/build-support/build-fhs-chrootenv/destroy.sh.in

This file was deleted.

22 changes: 0 additions & 22 deletions pkgs/build-support/build-fhs-chrootenv/init.sh.in

This file was deleted.

13 changes: 0 additions & 13 deletions pkgs/build-support/build-fhs-chrootenv/load.sh.in

This file was deleted.

34 changes: 0 additions & 34 deletions pkgs/build-support/build-fhs-chrootenv/mount.sh.in

This file was deleted.

6 changes: 0 additions & 6 deletions pkgs/build-support/build-fhs-chrootenv/umount.sh.in

This file was deleted.

38 changes: 11 additions & 27 deletions pkgs/build-support/build-fhs-userenv/chroot-user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@

# Bind mounts hierarchy: from => to (relative)
# If 'to' is nil, path will be the same
mounts = { '/nix/store' => nil,
'/dev' => nil,
mounts = { '/' => 'host',
'/proc' => nil,
'/sys' => nil,
'/etc' => 'host-etc',
'/tmp' => 'host-tmp',
'/home' => nil,
'/nix' => nil,
'/tmp' => nil,
'/var' => nil,
'/run' => nil,
'/root' => nil,
'/dev' => nil,
'/home' => nil,
}

# Propagate environment variables
Expand Down Expand Up @@ -62,12 +61,15 @@ def make_fcall(name, args, output)
Fiddle::TYPE_INT

# Read command line args
abort "Usage: chrootenv swdir program args..." unless ARGV.length >= 2
swdir = Pathname.new ARGV[0]
execp = ARGV.drop 1
abort "Usage: chrootenv program args..." unless ARGV.length >= 1
execp = ARGV

# Populate extra mounts
if not ENV["CHROOTENV_EXTRA_BINDS"].nil?
$stderr.puts "CHROOTENV_EXTRA_BINDS is discussed for deprecation."
$stderr.puts "If you have a usecase, please drop a note in issue #16030."
$stderr.puts "Notice that we now bind-mount host FS to '/host' and symlink all directories from it to '/' by default."

for extra in ENV["CHROOTENV_EXTRA_BINDS"].split(':')
paths = extra.split('=')
if not paths.empty?
Expand Down Expand Up @@ -132,24 +134,6 @@ def make_fcall(name, args, output)
Dir.chroot root
Dir.chdir '/'

# Symlink swdir hierarchy
mount_dirs = Set.new mounts.map { |_, v| Pathname.new v }
link_swdir = lambda do |swdir, prefix|
swdir.find do |path|
rel = prefix.join path.relative_path_from(swdir)
# Don't symlink anything in binded or symlinked directories
Find.prune if mount_dirs.include? rel or rel.symlink?
if not rel.directory?
# File does not exist; make a symlink and bail out
rel.make_symlink path
Find.prune
end
# Recursively follow symlinks
link_swdir.call path.readlink, rel if path.symlink?
end
end
link_swdir.call swdir, Pathname.new('')

# New environment
new_env = Hash[ envvars.map { |x| [x, ENV[x]] } ]

Expand Down
31 changes: 16 additions & 15 deletions pkgs/build-support/build-fhs-userenv/default.nix
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
{ runCommand, lib, writeText, writeScriptBin, stdenv, ruby } :
{ env, runScript ? "bash", extraBindMounts ? [], extraInstallCommands ? "", meta ? {}, passthru ? {} } :
{ callPackage, runCommand, lib, writeScript, stdenv, coreutils, ruby }:

let buildFHSEnv = callPackage ./env.nix { }; in

args@{ name, runScript ? "bash", extraBindMounts ? [], extraInstallCommands ? "", meta ? {}, passthru ? {}, ... }:

let
name = env.pname;
env = buildFHSEnv (removeAttrs args [ "runScript" "extraBindMounts" "extraInstallCommands" "meta" "passthru" ]);

# Sandboxing script
chroot-user = writeScriptBin "chroot-user" ''
chroot-user = writeScript "chroot-user" ''
#! ${ruby}/bin/ruby
${builtins.readFile ./chroot-user.rb}
'';

init = run: writeText "${name}-init" ''
source /etc/profile
# Make /tmp directory
mkdir -m 1777 /tmp
# Expose sockets in /tmp
for i in /host-tmp/.*-unix; do
ln -s "$i" "/tmp/$(basename "$i")"
init = run: writeScript "${name}-init" ''
#! ${stdenv.shell}
for i in ${env}/* /host/*; do
path="/''${i##*/}"
[ -e "$path" ] || ${coreutils}/bin/ln -s "$i" "$path"
done
[ -d "$1" ] && [ -r "$1" ] && cd "$1"
shift
source /etc/profile
exec ${run} "$@"
'';

Expand All @@ -32,7 +33,7 @@ in runCommand name {
env = runCommand "${name}-shell-env" {
shellHook = ''
export CHROOTENV_EXTRA_BINDS="${lib.concatStringsSep ":" extraBindMounts}:$CHROOTENV_EXTRA_BINDS"
exec ${chroot-user}/bin/chroot-user ${env} bash ${init "bash"} "$(pwd)"
exec ${chroot-user} ${init "bash"} "$(pwd)"
'';
} ''
echo >&2 ""
Expand All @@ -46,7 +47,7 @@ in runCommand name {
cat <<EOF >$out/bin/${name}
#! ${stdenv.shell}
export CHROOTENV_EXTRA_BINDS="${lib.concatStringsSep ":" extraBindMounts}:\$CHROOTENV_EXTRA_BINDS"
exec ${chroot-user}/bin/chroot-user ${env} bash ${init runScript} "\$(pwd)" "\$@"
exec ${chroot-user} ${init runScript} "\$(pwd)" "\$@"
EOF
chmod +x $out/bin/${name}
${extraInstallCommands}
Expand Down

0 comments on commit b341de8

Please sign in to comment.