diff --git a/lix/libutil/archive.cc b/lix/libutil/archive.cc index eb6a7a0b9..cf9b5295c 100644 --- a/lix/libutil/archive.cc +++ b/lix/libutil/archive.cc @@ -367,14 +367,20 @@ struct Parser buffer.clear(); \ u; \ }) -#define READ_STRING_LIMITED(limit) \ - ({ \ - size_t len = FETCH_INT(size_t); \ - co_yield WantBytes{len + (8 - len % 8) % 8}; \ - StringSource src(std::string_view(buffer.data(), buffer.size())); \ - auto str = readString(src, (limit)); \ - buffer.clear(); \ - std::move(str); \ +#define READ_STRING_LIMITED(limit) \ + ({ \ + size_t len = FETCH_INT(size_t); \ + if (len > (limit)) { \ + throw SerialisationError( \ + "found malformed string tag. input may be a compressed NAR, which cannot be read " \ + "directly" \ + ); \ + } \ + co_yield WantBytes{len + (8 - len % 8) % 8}; \ + StringSource src(std::string_view(buffer.data(), buffer.size())); \ + auto str = readString(src, (limit)); \ + buffer.clear(); \ + std::move(str); \ }) #define READ_STRING() READ_STRING_LIMITED(std::numeric_limits::max()) #define READ_PADDING(size) \ @@ -487,14 +493,13 @@ struct Parser std::string version; try { version = READ_STRING_LIMITED(narVersionMagic1.size()); + if (version != narVersionMagic1) { + throw SerialisationError("bad NAR version tag"); + } + co_yield parse(); } catch (SerialisationError & e) { - /* This generally means the integer at the start couldn't be - decoded. Ignore and throw the exception below. */ + throw badArchive(fmt("input doesn't look like a Nix archive (%s)", e.info().msg.str())); } - if (version != narVersionMagic1) { - throw badArchive("input doesn't look like a Nix archive"); - } - co_yield parse(); } #undef FETCH_INT diff --git a/tests/functional/nar-access.sh b/tests/functional/nar-access.sh index 5bcdf8ed3..3ee5bd34a 100644 --- a/tests/functional/nar-access.sh +++ b/tests/functional/nar-access.sh @@ -62,6 +62,12 @@ if nix-store --dump $storePath >/dev/full ; then exit -1 fi +# compressed nars should cause a useful error message. we use ascii +# text input because the salient point is the initial length field. +echo 'not a real nar' > bad.nar +expect 1 nix nar ls bad.nar / 2>&1 | fgrep "doesn't look like a Nix archive (found malformed string tag" + + # Test reading from remote nar listings if available nix copy --to "file://$cacheDir?write-nar-listing=true" $storePath