From 47000b658e274141317ce8b711a3d64fe317528a Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sat, 11 Oct 2025 21:59:56 +0200 Subject: [PATCH] libutil: don't trust RemoteStore activity ids remotes can generate the same activity ids we might generate locally, especially if the remote is accessed over the network. in that case a pid collision is possible, and since activity ids are sequential it's very possible to create colliding activity ids on both sides as well. Change-Id: Id58074a41f5f7a59171b52818d1fb5a1beb4bf40 --- lix/libstore/remote-store.cc | 53 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/lix/libstore/remote-store.cc b/lix/libstore/remote-store.cc index 885763f9b..d72c38b8a 100644 --- a/lix/libstore/remote-store.cc +++ b/lix/libstore/remote-store.cc @@ -784,43 +784,54 @@ RemoteStore::Connection::processStderr(AsyncFdIoStream & stream) try { AsyncBufferedInputStream from{stream, fromBuf}; + std::map remoteActivities; + while (true) { auto msg = TRY_AWAIT(readNum(from)); if (msg == STDERR_ERROR) { co_return RemoteError{std::make_exception_ptr(TRY_AWAIT(readError(from)))}; - } - - else if (msg == STDERR_NEXT) + } else if (msg == STDERR_NEXT) { printError("%1%", Uncolored(chomp(TRY_AWAIT(readString(from))))); - - else if (msg == STDERR_START_ACTIVITY) { + } else if (msg == STDERR_START_ACTIVITY) { auto act = TRY_AWAIT(readNum(from)); auto lvl = (Verbosity) TRY_AWAIT(readNum(from)); auto type = (ActivityType) TRY_AWAIT(readNum(from)); auto s = TRY_AWAIT(readString(from)); auto fields = TRY_AWAIT(readFields(from)); - auto parent = TRY_AWAIT(readNum(from)); - logger->startActivity(act, lvl, type, s, fields, parent); - } - - else if (msg == STDERR_STOP_ACTIVITY) { - auto act = TRY_AWAIT(readNum(from)); - logger->stopActivity(act); - } - - else if (msg == STDERR_RESULT) { + const auto parentId = TRY_AWAIT(readNum(from)); + const auto parent = parentId == 0 ? nullptr : [&] { + const auto parent = get(remoteActivities, parentId); + if (!parent) { + printError( + "remote started child activity of %s that isn't currently known!", parentId + ); + } + return parent; + }(); + remoteActivities.emplace(act, Activity(*logger, lvl, type, s, fields, parent)); + } else if (msg == STDERR_STOP_ACTIVITY) { auto act = TRY_AWAIT(readNum(from)); + if (remoteActivities.erase(act) == 0) { + printError("remote stopped activity %s that isn't currently known!", act); + } + } else if (msg == STDERR_RESULT) { + const auto actId = TRY_AWAIT(readNum(from)); auto type = (ResultType) TRY_AWAIT(readNum(from)); auto fields = TRY_AWAIT(readFields(from)); - logger->result(act, type, fields); - } - - else if (msg == STDERR_LAST) + const auto act = get(remoteActivities, actId); + if (!act) { + printError( + "remote reported result for activity %s that isn't currently known!", actId + ); + continue; + } + act->result(type, fields); + } else if (msg == STDERR_LAST) { break; - - else + } else { throw Error("got unknown message type %x from Nix daemon", msg); + } } co_return RemoteError{nullptr};