nixpkgs/lib
aszlig df475092e9
lib: Make escapeShellArg more robust
Quoting various characters that the shell *may* interpret specially is a
very fragile thing to do.

I've used something more robust all over the place in various Nix
expression I've written just because I didn't trust escapeShellArg.

Here is a proof of concept showing that I was indeed right in
distrusting escapeShellArg:

with import <nixpkgs> {};

let
  payload = runCommand "payload" {} ''
    # \x00 is not allowed for Nix strings, so let's begin at 1
    for i in $(seq 1 255); do
      echo -en "\\x$(printf %02x $i)"
    done > "$out"
  '';

  escapers = with lib; {
    current = escapeShellArg;
    better = arg: let
      backslashEscapes = stringToCharacters "\"\\ ';$`()|<>\r\t*[]&!~#";
      search = backslashEscapes ++ [ "\n" ];
      replace = map (c: "\\${c}") backslashEscapes ++ [ "'\n'" ];
    in replaceStrings search replace (toString arg);
    best = arg: "'${replaceStrings ["'"] ["'\\''"] (toString arg)}'";
  };

  testWith = escaper: let
    escaped = escaper (builtins.readFile payload);
  in runCommand "test" {} ''
    if ! r="$(bash -c ${escapers.best "echo -nE ${escaped}"} 2> /dev/null)"
    then
      echo bash eval error > "$out"
      exit 0
    fi
    if echo -n "$r" | cmp -s "${payload}"; then
      echo success > "$out"
    else
      echo failed > "$out"
    fi
  '';

in runCommand "results" {} ''
  echo "Test results:"
  ${lib.concatStrings (lib.mapAttrsToList (name: impl: ''
    echo "  ${name}: $(< "${testWith impl}")"
  '') escapers)}
  exit 1
''

The resulting output is the following:

Test results:
  best: success
  better: success
  current: bash eval error

I did the "better" implementation just to illustrate that the method of
quoting only "harmful" characters results in madness in terms of
implementation and performance.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Cc: @edolstra, @zimbatm
2016-06-20 23:53:36 +02:00
..
tests lib: alphabetize things 2016-02-26 22:15:41 +00:00
attrsets.nix add get* helper functions and mass-replace manual outputs search with them 2016-04-25 13:24:39 +03:00
composable-derivation.nix treewide: Make explicit that 'dev' output of curl is used 2016-05-19 10:00:29 +02:00
customisation.nix nixos systemPackages: rework default outputs 2016-01-28 11:24:18 +01:00
debug.nix lib: cleanup a little bit, add traceIf 2015-03-26 12:43:42 +00:00
default.nix cherry-pick lib.sandbox into master 2015-11-19 11:33:21 -08:00
deprecated.nix Update deprecated.nix 2015-11-15 03:41:39 +08:00
licenses.nix epson_201207w: init at 1.0.0 2016-03-09 15:25:53 -03:00
lists.nix Remove unecessary branching on old nix versions 2016-06-17 11:06:48 +01:00
maintainers.nix adapta-gtk-theme: Init at 3.21.2 2016-06-18 23:33:29 +12:00
meta.nix Make appendToName do the right thing 2014-03-10 15:01:56 +01:00
minver.nix Expose minimum required Nix version. 2015-11-26 23:11:11 +08:00
modules.nix Fix display of deprecated option definition warnings 2016-06-01 12:55:46 +02:00
options.nix Revert "Add the tool "nixos-typecheck" that can check an option declaration to:" 2016-03-01 20:52:06 +01:00
platforms.nix lib.platforms: alphabetize 2016-02-26 22:15:40 +00:00
sandbox.nix cherry-pick lib.sandbox into master 2015-11-19 11:33:21 -08:00
sources.nix nixos/modules/misc/version.nix: check that .git is a directory 2016-06-03 13:38:41 +01:00
strings-with-deps.nix Replace references to all-packages.nix, by references to the top-level of nixpkgs repository. 2016-03-13 18:25:52 +00:00
strings.nix lib: Make escapeShellArg more robust 2016-06-20 23:53:36 +02:00
systems.nix lib: alphabetize things 2016-02-26 22:15:41 +00:00
tests.nix add helper to lib/attrsets: hasAttrByPath 2015-12-07 11:04:14 +01:00
trivial.nix lib.trivial: add a new importJSON function 2016-02-29 11:21:56 +00:00
types.nix Use shell packages to select the user's shell 2016-06-12 20:35:34 +01:00