1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-13 20:41:04 +01:00

daemon: Add WorkerProto serialiser for GCAction

Previously the daemon didn't validate that it got a valid GCAction
and did a naive C-style cast to the enum. This is certainly unintentional,
albeit mostly harmless in practice.
This commit is contained in:
Sergei Zimmerman 2025-12-09 01:57:39 +03:00
parent 907a5761fa
commit f2465bccba
No known key found for this signature in database
5 changed files with 70 additions and 22 deletions

View file

@ -743,7 +743,7 @@ static void performOp(
case WorkerProto::Op::CollectGarbage: { case WorkerProto::Op::CollectGarbage: {
GCOptions options; GCOptions options;
options.action = (GCOptions::GCAction) readInt(conn.from); options.action = WorkerProto::Serialise<GCOptions::GCAction>::read(*store, rconn);
options.pathsToDelete = WorkerProto::Serialise<StorePathSet>::read(*store, rconn); options.pathsToDelete = WorkerProto::Serialise<StorePathSet>::read(*store, rconn);
conn.from >> options.ignoreLiveness >> options.maxFreed; conn.from >> options.ignoreLiveness >> options.maxFreed;
// obsolete fields // obsolete fields

View file

@ -13,8 +13,6 @@ typedef boost::unordered_flat_map<
std::hash<StorePath>> std::hash<StorePath>>
Roots; Roots;
struct GCOptions
{
/** /**
* Garbage collector operation: * Garbage collector operation:
* *
@ -29,12 +27,17 @@ struct GCOptions
* - `gcDeleteSpecific`: delete the paths listed in * - `gcDeleteSpecific`: delete the paths listed in
* `pathsToDelete`, insofar as they are not reachable. * `pathsToDelete`, insofar as they are not reachable.
*/ */
typedef enum { enum class GCAction {
gcReturnLive, gcReturnLive,
gcReturnDead, gcReturnDead,
gcDeleteDead, gcDeleteDead,
gcDeleteSpecific, gcDeleteSpecific,
} GCAction; };
struct GCOptions
{
using GCAction = nix::GCAction;
using enum GCAction;
GCAction action{gcDeleteDead}; GCAction action{gcDeleteDead};

View file

@ -37,6 +37,7 @@ struct ValidPathInfo;
struct UnkeyedValidPathInfo; struct UnkeyedValidPathInfo;
enum BuildMode : uint8_t; enum BuildMode : uint8_t;
enum TrustedFlag : bool; enum TrustedFlag : bool;
enum class GCAction;
/** /**
* The "worker protocol", used by unix:// and ssh-ng:// stores. * The "worker protocol", used by unix:// and ssh-ng:// stores.
@ -263,6 +264,8 @@ DECLARE_WORKER_SERIALISER(UnkeyedValidPathInfo);
template<> template<>
DECLARE_WORKER_SERIALISER(BuildMode); DECLARE_WORKER_SERIALISER(BuildMode);
template<> template<>
DECLARE_WORKER_SERIALISER(GCAction);
template<>
DECLARE_WORKER_SERIALISER(std::optional<TrustedFlag>); DECLARE_WORKER_SERIALISER(std::optional<TrustedFlag>);
template<> template<>
DECLARE_WORKER_SERIALISER(std::optional<std::chrono::microseconds>); DECLARE_WORKER_SERIALISER(std::optional<std::chrono::microseconds>);

View file

@ -694,7 +694,8 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
{ {
auto conn(getConnection()); auto conn(getConnection());
conn->to << WorkerProto::Op::CollectGarbage << options.action; conn->to << WorkerProto::Op::CollectGarbage;
WorkerProto::write(*this, *conn, options.action);
WorkerProto::write(*this, *conn, options.pathsToDelete); WorkerProto::write(*this, *conn, options.pathsToDelete);
conn->to << options.ignoreLiveness conn->to << options.ignoreLiveness
<< options.maxFreed << options.maxFreed

View file

@ -1,6 +1,7 @@
#include "nix/util/serialise.hh" #include "nix/util/serialise.hh"
#include "nix/store/path-with-outputs.hh" #include "nix/store/path-with-outputs.hh"
#include "nix/store/store-api.hh" #include "nix/store/store-api.hh"
#include "nix/store/gc-store.hh"
#include "nix/store/build-result.hh" #include "nix/store/build-result.hh"
#include "nix/store/worker-protocol.hh" #include "nix/store/worker-protocol.hh"
#include "nix/store/worker-protocol-impl.hh" #include "nix/store/worker-protocol-impl.hh"
@ -47,6 +48,46 @@ void WorkerProto::Serialise<BuildMode>::write(
}; };
} }
GCAction WorkerProto::Serialise<GCAction>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn)
{
auto temp = readNum<unsigned>(conn.from);
using enum GCAction;
switch (temp) {
case 0:
return gcReturnLive;
case 1:
return gcReturnDead;
case 2:
return gcDeleteDead;
case 3:
return gcDeleteSpecific;
default:
throw Error("Invalid GC action");
}
}
void WorkerProto::Serialise<GCAction>::write(
const StoreDirConfig & store, WorkerProto::WriteConn conn, const GCAction & action)
{
using enum GCAction;
switch (action) {
case gcReturnLive:
conn.to << unsigned{0};
break;
case gcReturnDead:
conn.to << unsigned{1};
break;
case gcDeleteDead:
conn.to << unsigned{2};
break;
case gcDeleteSpecific:
conn.to << unsigned{3};
break;
default:
assert(false);
}
}
std::optional<TrustedFlag> std::optional<TrustedFlag>
WorkerProto::Serialise<std::optional<TrustedFlag>>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn) WorkerProto::Serialise<std::optional<TrustedFlag>>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn)
{ {