diff options
author | Robert Hensing <robert@roberthensing.nl> | 2022-01-06 01:20:12 +0100 |
---|---|---|
committer | Robert Hensing <robert@roberthensing.nl> | 2022-01-19 15:21:56 +0100 |
commit | d038a67bd3c6ed0d6452d595cf0af3115e14c48f (patch) | |
tree | 38d423aa4332d1050a466adeb1b21af194cb36fc /src | |
parent | bc443511eb65420b51d10708e25427fe50de37a8 (diff) |
Fix segfault or stack overflow caused by large derivation fields
This removes a dynamic stack allocation, making the derivation
unparsing logic robust against overflows when large strings are
added to a derivation.
Overflow behavior depends on the platform and stack configuration.
For instance, x86_64-linux/glibc behaves as (somewhat) expected:
$ (ulimit -s 20000; nix-instantiate tests/lang/eval-okay-big-derivation-attr.nix)
error: stack overflow (possible infinite recursion)
$ (ulimit -s 40000; nix-instantiate tests/lang/eval-okay-big-derivation-attr.nix)
error: expression does not evaluate to a derivation (or a set or list of those)
However, on aarch64-darwin:
$ nix-instantiate big-attr.nix ~
zsh: segmentation fault nix-instantiate big-attr.nix
This indicates a slight flaw in the single stack protection page
approach that is not encountered with normal stack frames.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/derivations.cc | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index b926bb711..616e78076 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -272,7 +272,15 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi static void printString(string & res, std::string_view s) { - char buf[s.size() * 2 + 2]; + char * buf; + size_t bufSize = s.size() * 2 + 2; + std::unique_ptr<char[]> dynBuf; + if (bufSize < 0x10000) { + buf = (char *)alloca(bufSize); + } else { + dynBuf = decltype(dynBuf)(new char[bufSize]); + buf = dynBuf.get(); + } char * p = buf; *p++ = '"'; for (auto c : s) |