From af83c63ef1926a7571943926fbbd08c6c129d737 Mon Sep 17 00:00:00 2001 From: aszlig Date: Tue, 21 Nov 2017 07:06:08 +0100 Subject: pkgs/sandbox: Handle non-existing paths We now distinguish between paths that have to exist and paths that are fine to skip during bind mounting. So far we had hard failures whenever a path that needed to be mounted didn't exist, for example something like $XDG_CONFIG_HOME/unity3d failed whenever the directory didn't exist. Apart from that we now have a more clean attribute structure for sandbox parameters, which are now: * paths.required: Created prior to bind-mounting * paths.wanted: Skipped if it doesn't exist * paths.runtimeVars: Extracted from PATH-like environment variables Signed-off-by: aszlig --- pkgs/games/build-support/build-game.nix | 18 +++++++------ pkgs/games/build-support/build-sandbox/default.nix | 31 +++++++++++++++------- pkgs/games/build-support/build-sandbox/src/setup.c | 29 +++++++++++--------- pkgs/games/build-support/build-sandbox/src/setup.h | 2 +- pkgs/games/build-support/build-unity.nix | 11 ++++++-- 5 files changed, 59 insertions(+), 32 deletions(-) (limited to 'pkgs/games/build-support') diff --git a/pkgs/games/build-support/build-game.nix b/pkgs/games/build-support/build-game.nix index 51d3c7d5..b04309a5 100644 --- a/pkgs/games/build-support/build-game.nix +++ b/pkgs/games/build-support/build-game.nix @@ -12,8 +12,7 @@ assert withPulseAudio -> libpulseaudio != null; , setSourceRoot ? "" , installCheckPhase ? "" , runtimeDependencies ? [] -, extraSandboxPaths ? [ "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" ] -, extraRuntimePathVars ? [] +, sandbox ? {} , ... }@attrs: @@ -73,9 +72,12 @@ buildSandbox (stdenv.mkDerivation ({ dontPatchELF = true; } // removeAttrs attrs [ "buildInputs" "nativeBuildInputs" "preUnpack" "setSourceRoot" - "installCheckPhase" "runtimeDependencies" "extraSandboxPaths" - "extraRuntimePathVars" -])) { - inherit extraSandboxPaths; - runtimePathVars = lib.singleton "LD_LIBRARY_PATH" ++ extraRuntimePathVars; -} + "installCheckPhase" "runtimeDependencies" "sandbox" +])) (sandbox // { + paths = let + paths = sandbox.paths or {}; + in paths // { + required = paths.required or [ "$XDG_DATA_HOME" "$XDG_CONFIG_HOME" ]; + runtimeVars = [ "LD_LIBRARY_PATH" ] ++ paths.runtimeVars or []; + }; +}) diff --git a/pkgs/games/build-support/build-sandbox/default.nix b/pkgs/games/build-support/build-sandbox/default.nix index e4826405..fa4bac57 100644 --- a/pkgs/games/build-support/build-sandbox/default.nix +++ b/pkgs/games/build-support/build-sandbox/default.nix @@ -1,8 +1,23 @@ { stdenv, lib, pkgconfig, nix }: -drv: { extraSandboxPaths ? [], runtimePathVars ? [], ... }@attrs: - -stdenv.mkDerivation ({ +drv: { paths ? {}, ... }@attrs: + +let + # Extra paths that are required so they are created prior to bind-mounting. + pathsRequired = paths.required or []; + # Extra paths that are skipped if they don't exist. + pathsWanted = paths.wanted or []; + # Paths extracted from PATH-like environment variables, eg. LD_LIBRARY_PATH. + pathsRuntimeVars = paths.runtimeVars or []; + + # Create code snippets for params.c to add extra_mount() calls. + mkExtraMountParams = isRequired: lib.concatMapStringsSep "\n" (extra: let + escaped = lib.escape ["\\" "\""] extra; + reqBool = if isRequired then "true" else "false"; + code = "if (!extra_mount(\"${escaped}\", ${reqBool})) return false;"; + in "echo ${lib.escapeShellArg code} >> params.c"); + +in stdenv.mkDerivation ({ name = "${drv.name}-sandboxed"; src = ./src; @@ -37,10 +52,8 @@ stdenv.mkDerivation ({ echo 'if (!bind_mount("'"$dep"'", true, true)) return false;' >> params.c done - ${lib.concatMapStringsSep "\n" (extra: let - escaped = lib.escapeShellArg (lib.escape ["\\" "\""] extra); - result = "echo 'if (!extra_mount(\"'${escaped}'\")) return false;'"; - in "${result} >> params.c") extraSandboxPaths} + ${mkExtraMountParams true pathsRequired} + ${mkExtraMountParams false pathsWanted} echo 'return true; }' >> params.c @@ -50,7 +63,7 @@ stdenv.mkDerivation ({ escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar); fun = "mount_from_path_var"; result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'"; - in "${result} >> params.c") runtimePathVars} + in "${result} >> params.c") pathsRuntimeVars} echo 'return true; }' >> params.c ''; @@ -59,4 +72,4 @@ stdenv.mkDerivation ({ buildInputs = [ nix ]; makeFlags = [ "BINDIR=${drv}/bin" ]; -} // removeAttrs attrs [ "extraSandboxPaths" "runtimePathVars" ]) +} // removeAttrs attrs [ "paths" ]) diff --git a/pkgs/games/build-support/build-sandbox/src/setup.c b/pkgs/games/build-support/build-sandbox/src/setup.c index 0b582e92..f351ce19 100644 --- a/pkgs/games/build-support/build-sandbox/src/setup.c +++ b/pkgs/games/build-support/build-sandbox/src/setup.c @@ -91,7 +91,7 @@ bool write_maps(pid_t parent_pid) return true; } -static bool makedirs(const char *path) +static bool makedirs(const char *path, bool do_cache) { char *tmp, *segment; @@ -103,13 +103,13 @@ static bool makedirs(const char *path) segment = dirname(tmp); if (!(segment[0] == '/' && segment[1] == '\0')) { - if (!makedirs(segment)) { + if (!makedirs(segment, do_cache)) { free(tmp); return false; } } - if (cache_path(cached_paths, path)) + if (!do_cache || cache_path(cached_paths, path)) (void)mkdir(path, 0755); free(tmp); return true; @@ -138,17 +138,14 @@ bool bind_mount(const char *path, bool restricted, bool resolve) if (restricted) mflags |= MS_NOSUID | MS_NODEV | MS_NOATIME; - if (resolve) { - if (realpath(path, src) == NULL) { - fprintf(stderr, "realpath of %s: %s\n", path, strerror(errno)); - return false; - } - } + if (resolve ? realpath(path, src) == NULL : access(path, F_OK) == -1) + // Skip missing mount source + return true; if ((target = get_mount_target(resolve ? src : path)) == NULL) return false; - if (!makedirs(target)) { + if (!makedirs(target, false)) { free(target); return false; } @@ -173,6 +170,10 @@ static bool bind_file(const char *path) { char *target, *tmp; + if (access(path, R_OK) == -1) + // Skip missing mount source + return true; + if ((target = get_mount_target(path)) == NULL) return false; @@ -182,7 +183,7 @@ static bool bind_file(const char *path) return false; } - if (!makedirs(dirname(tmp))) { + if (!makedirs(dirname(tmp), true)) { free(target); free(tmp); return false; @@ -452,12 +453,16 @@ static char *replace_env(const char *path) return replace_env_offset_free(path, base); } -bool extra_mount(const char *path) +bool extra_mount(const char *path, bool is_required) { char *expanded; + if ((expanded = replace_env(path)) == NULL) return false; + if (is_required && !makedirs(expanded, false)) + return false; + if (!bind_mount(expanded, true, true)) { free(expanded); return false; diff --git a/pkgs/games/build-support/build-sandbox/src/setup.h b/pkgs/games/build-support/build-sandbox/src/setup.h index c3b69699..fe882dc5 100644 --- a/pkgs/games/build-support/build-sandbox/src/setup.h +++ b/pkgs/games/build-support/build-sandbox/src/setup.h @@ -7,7 +7,7 @@ bool write_maps(pid_t parent_pid); bool bind_mount(const char *path, bool restricted, bool resolve); -bool extra_mount(const char *path); +bool extra_mount(const char *path, bool is_required); bool mount_from_path_var(struct query_state *qs, const char *name); bool setup_sandbox(void); diff --git a/pkgs/games/build-support/build-unity.nix b/pkgs/games/build-support/build-unity.nix index 596c65be..6d7a6cb1 100644 --- a/pkgs/games/build-support/build-unity.nix +++ b/pkgs/games/build-support/build-unity.nix @@ -6,6 +6,7 @@ , nativeBuildInputs ? [] , buildInputs ? [] , runtimeDependencies ? [] +, sandbox ? {} , ... }@attrs: @@ -27,7 +28,13 @@ in buildGame ({ mesa xorg.libX11 xorg.libXcursor xorg.libXrandr libudev zlib ]; - extraSandboxPaths = [ "$XDG_CONFIG_HOME/unity3d" ]; + sandbox = sandbox // { + paths = (sandbox.paths or {}) // { + required = (sandbox.paths.required or []) ++ [ + "$XDG_CONFIG_HOME/unity3d" + ]; + }; + }; installPhase = '' runHook preInstall @@ -62,5 +69,5 @@ in buildGame ({ ''; } // removeAttrs attrs [ "name" "version" "fullName" "nativeBuildInputs" "buildInputs" - "runtimeDependencies" + "runtimeDependencies" "sandbox" ]) -- cgit 1.4.1