diff options
Diffstat (limited to 'pkgs/build-support/build-fhs-userenv-bubblewrap')
-rw-r--r-- | pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix | 134 | ||||
-rw-r--r-- | pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix | 23 |
2 files changed, 123 insertions, 34 deletions
diff --git a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix index c7cfd27d3fa..23718bf636c 100644 --- a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix +++ b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix @@ -1,28 +1,43 @@ -{ callPackage, runCommandLocal, writeShellScriptBin, stdenv, coreutils, bubblewrap }: +{ lib, callPackage, runCommandLocal, writeShellScriptBin, glibc, pkgsi686Linux, coreutils, bubblewrap }: let buildFHSEnv = callPackage ./env.nix { }; in args @ { - name, - runScript ? "bash", - extraInstallCommands ? "", - meta ? {}, - passthru ? {}, - ... + name +, runScript ? "bash" +, extraInstallCommands ? "" +, meta ? {} +, passthru ? {} +, unshareUser ? true +, unshareIpc ? true +, unsharePid ? true +, unshareNet ? false +, unshareUts ? true +, unshareCgroup ? true +, dieWithParent ? true +, ... }: with builtins; let + buildFHSEnv = callPackage ./env.nix { }; + env = buildFHSEnv (removeAttrs args [ - "runScript" "extraInstallCommands" "meta" "passthru" + "runScript" "extraInstallCommands" "meta" "passthru" "dieWithParent" + "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc" ]); - chrootenv = callPackage ./chrootenv {}; - etcBindFlags = let files = [ # NixOS Compatibility "static" + "nix" # mainly for nixUnstable users, but also for access to nix/netrc + # Shells + "bashrc" + "zshenv" + "zshrc" + "zinputrc" + "zprofile" # Users, Groups, NSS "passwd" "group" @@ -30,6 +45,8 @@ let "hosts" "resolv.conf" "nsswitch.conf" + # User profiles + "profiles" # Sudo & Su "login.defs" "sudoers" @@ -45,60 +62,115 @@ let # Fonts "fonts" # ALSA + "alsa" "asound.conf" # SSL "ssl/certs" "pki" ]; - in concatStringsSep " \\\n " + in concatStringsSep "\n " (map (file: "--ro-bind-try /etc/${file} /etc/${file}") files); + # Create this on the fly instead of linking from /nix + # The container might have to modify it and re-run ldconfig if there are + # issues running some binary with LD_LIBRARY_PATH + createLdConfCache = '' + cat > /etc/ld.so.conf <<EOF + /lib + /lib/x86_64-linux-gnu + /lib64 + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/lib64 + /lib/i386-linux-gnu + /lib32 + /usr/lib/i386-linux-gnu + /usr/lib32 + EOF + ldconfig &> /dev/null + ''; init = run: writeShellScriptBin "${name}-init" '' source /etc/profile + ${createLdConfCache} exec ${run} "$@" ''; bwrapCmd = { initArgs ? "" }: '' - blacklist="/nix /dev /proc /etc" - ro_mounts="" + blacklist=(/nix /dev /proc /etc) + ro_mounts=() + symlinks=() for i in ${env}/*; do path="/''${i##*/}" if [[ $path == '/etc' ]]; then - continue + : + elif [[ -L $i ]]; then + symlinks+=(--symlink "$(${coreutils}/bin/readlink "$i")" "$path") + blacklist+=("$path") + else + ro_mounts+=(--ro-bind "$i" "$path") + blacklist+=("$path") fi - ro_mounts="$ro_mounts --ro-bind $i $path" - blacklist="$blacklist $path" done if [[ -d ${env}/etc ]]; then for i in ${env}/etc/*; do path="/''${i##*/}" - ro_mounts="$ro_mounts --ro-bind $i /etc$path" + # NOTE: we're binding /etc/fonts and /etc/ssl/certs from the host so we + # don't want to override it with a path from the FHS environment. + if [[ $path == '/fonts' || $path == '/ssl' ]]; then + continue + fi + ro_mounts+=(--ro-bind "$i" "/etc$path") done fi - auto_mounts="" + declare -a auto_mounts # loop through all directories in the root for dir in /*; do # if it is a directory and it is not in the blacklist - if [[ -d "$dir" ]] && grep -v "$dir" <<< "$blacklist" >/dev/null; then + if [[ -d "$dir" ]] && [[ ! "''${blacklist[@]}" =~ "$dir" ]]; then # add it to the mount list - auto_mounts="$auto_mounts --bind $dir $dir" + auto_mounts+=(--bind "$dir" "$dir") fi done - exec ${bubblewrap}/bin/bwrap \ - --dev-bind /dev /dev \ - --proc /proc \ - --chdir "$(pwd)" \ - --unshare-all \ - --share-net \ - --die-with-parent \ - --ro-bind /nix /nix \ - ${etcBindFlags} \ - $ro_mounts \ - $auto_mounts \ + cmd=( + ${bubblewrap}/bin/bwrap + --dev-bind /dev /dev + --proc /proc + --chdir "$(pwd)" + ${lib.optionalString unshareUser "--unshare-user"} + ${lib.optionalString unshareIpc "--unshare-ipc"} + ${lib.optionalString unsharePid "--unshare-pid"} + ${lib.optionalString unshareNet "--unshare-net"} + ${lib.optionalString unshareUts "--unshare-uts"} + ${lib.optionalString unshareCgroup "--unshare-cgroup"} + ${lib.optionalString dieWithParent "--die-with-parent"} + --ro-bind /nix /nix + # Our glibc will look for the cache in its own path in `/nix/store`. + # As such, we need a cache to exist there, because pressure-vessel + # depends on the existence of an ld cache. However, adding one + # globally proved to be a bad idea (see #100655), the solution we + # settled on being mounting one via bwrap. + # Also, the cache needs to go to both 32 and 64 bit glibcs, for games + # of both architectures to work. + --tmpfs ${glibc}/etc \ + --symlink /etc/ld.so.conf ${glibc}/etc/ld.so.conf \ + --symlink /etc/ld.so.cache ${glibc}/etc/ld.so.cache \ + --ro-bind ${glibc}/etc/rpc ${glibc}/etc/rpc \ + --remount-ro ${glibc}/etc \ + --tmpfs ${pkgsi686Linux.glibc}/etc \ + --symlink /etc/ld.so.conf ${pkgsi686Linux.glibc}/etc/ld.so.conf \ + --symlink /etc/ld.so.cache ${pkgsi686Linux.glibc}/etc/ld.so.cache \ + --ro-bind ${pkgsi686Linux.glibc}/etc/rpc ${pkgsi686Linux.glibc}/etc/rpc \ + --remount-ro ${pkgsi686Linux.glibc}/etc \ + ${etcBindFlags} + "''${ro_mounts[@]}" + "''${symlinks[@]}" + "''${auto_mounts[@]}" ${init runScript}/bin/${name}-init ${initArgs} + ) + exec "''${cmd[@]}" ''; bin = writeShellScriptBin name (bwrapCmd { initArgs = ''"$@"''; }); diff --git a/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix b/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix index 8b2d46c4ae9..b9c719a4c78 100644 --- a/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix +++ b/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix @@ -1,4 +1,4 @@ -{ stdenv, buildEnv, writeText, pkgs, pkgsi686Linux }: +{ stdenv, lib, buildEnv, writeText, writeShellScriptBin, pkgs, pkgsi686Linux }: { name, profile ? "" , targetPkgs ? pkgs: [], multiPkgs ? pkgs: [] @@ -49,6 +49,9 @@ let [ (toString gcc.cc.lib) ]; + ldconfig = writeShellScriptBin "ldconfig" '' + exec ${pkgs.glibc.bin}/bin/ldconfig -f /etc/ld.so.conf -C /etc/ld.so.cache "$@" + ''; etcProfile = writeText "profile" '' export PS1='${name}-chrootenv:\u@\h:\w\$ ' export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive' @@ -86,7 +89,8 @@ let # Composes a /usr-like directory structure staticUsrProfileTarget = buildEnv { name = "${name}-usr-target"; - paths = [ etcPkg ] ++ basePkgs ++ targetPaths; + # ldconfig wrapper must come first so it overrides the original ldconfig + paths = [ etcPkg ldconfig ] ++ basePkgs ++ targetPaths; extraOutputsToInstall = [ "out" "lib" "bin" ] ++ extraOutputsToInstall; ignoreCollisions = true; }; @@ -132,7 +136,20 @@ let mkdir -m0755 usr cd usr ${setupLibDirs} - for i in bin sbin share include; do + ${lib.optionalString isMultiBuild '' + if [ -d "${staticUsrProfileMulti}/share" ]; then + cp -rLf ${staticUsrProfileMulti}/share share + fi + ''} + if [ -d "${staticUsrProfileTarget}/share" ]; then + if [ -d share ]; then + chmod -R 755 share + cp -rLTf ${staticUsrProfileTarget}/share share + else + cp -rLf ${staticUsrProfileTarget}/share share + fi + fi + for i in bin sbin include; do if [ -d "${staticUsrProfileTarget}/$i" ]; then cp -rsHf "${staticUsrProfileTarget}/$i" "$i" fi |