Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pika_migrate_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ int PikaMigrateThread::ReqMigrateOne(const std::string &key, const std::shared_p
NotifyRequestMigrate();
}

return 1;
return 0;
}

void PikaMigrateThread::GetMigrateStatus(std::string *ip, int64_t* port, int64_t *slot, bool *migrating, int64_t *moved,
Expand Down
24 changes: 21 additions & 3 deletions src/pika_slot_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1439,10 +1439,28 @@ void SlotsMgrtExecWrapperCmd::Do() {
res_.AppendArrayLen(2);
int ret = g_pika_server->SlotsMigrateOne(key_, db_);
switch (ret) {
case 0:
res_.AppendInteger(0);
res_.AppendInteger(0);
case 0: {
res_.AppendInteger(2);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Document the new 2 result code.

The contract immediately above Do() still says this wrapper only returns -1/0/1, but Line 1443 now emits 2. Please update the command contract/tests with the new discriminator so callers do not keep treating this path as an unknown response.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pika_slot_command.cc` at line 1443, The command wrapper now returns a new
discriminator value 2 (res_.AppendInteger(2)) but the Do() contract and related
tests still document/expect only -1/0/1; update the contract comment above Do()
to list and describe the new result code 2 and modify any unit/integration tests
that assert allowed responses to include 2 so callers handle it explicitly
(search for Do(), res_.AppendInteger(2), and tests referencing -1/0/1 to locate
all occurrences).

PikaCmdArgsType args;
for (size_t i = 2; i < argv_.size(); ++i) {
args.push_back(argv_[i]);
}
std::string opt = args[0];
pstd::StringToLower(opt);
std::shared_ptr<Cmd> c_ptr = g_pika_cmd_table_manager->GetCmd(opt);
if (!c_ptr) {
res_.SetRes(CmdRes::kErrOther, "unknown command");
return;
}
c_ptr->Initial(args, db_->GetDBName());
if (!c_ptr->res().ok()) {
res_.SetRes(CmdRes::kErrOther, c_ptr->res().message());
return;
}
c_ptr->Execute();
Comment on lines +1444 to +1460
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Reject wrapped commands that do not resolve back to key_.

This branch executes client-supplied args verbatim, but never checks that the parsed command actually targets the wrapper key. A request like slotsmgrtexecwrapper foo set bar 1 will route on foo and mutate bar, and multi-key/admin commands can also slip through this path. During slot migration that breaks the single-slot guarantee and can send writes to the wrong shard. Validate args before indexing args[0], then reject anything whose current_key() is empty, multi-key, or different from key_ before Execute().

🔒 Suggested guardrails
       PikaCmdArgsType args;
       for (size_t i = 2; i < argv_.size(); ++i) {
         args.push_back(argv_[i]);
       }
+      if (args.empty()) {
+        res_.SetRes(CmdRes::kWrongNum, kCmdNameSlotsMgrtExecWrapper);
+        return;
+      }
       std::string opt = args[0];
       pstd::StringToLower(opt);
       std::shared_ptr<Cmd> c_ptr = g_pika_cmd_table_manager->GetCmd(opt);
       if (!c_ptr) {
         res_.SetRes(CmdRes::kErrOther, "unknown command");
         return;
       }
       c_ptr->Initial(args, db_->GetDBName());
       if (!c_ptr->res().ok()) {
         res_.SetRes(CmdRes::kErrOther, c_ptr->res().message());
         return;
       }
+      const auto keys = c_ptr->current_key();
+      if (keys.size() != 1 || keys[0] != key_) {
+        res_.SetRes(CmdRes::kErrOther, "wrapped command must target the wrapper key");
+        return;
+      }
       c_ptr->Execute();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pika_slot_command.cc` around lines 1444 - 1460, The handler currently
builds args and then directly indexes args[0], gets a Cmd via
g_pika_cmd_table_manager->GetCmd(opt) and runs Initial()/Execute() without
verifying the resolved target key; change the flow to first ensure args is
non-empty, then lookup and call c_ptr->Initial(args, db_->GetDBName()), check
c_ptr->res().ok(), then inspect c_ptr->current_key(): if current_key() is empty,
indicates multi-key (or multi-key flag if available), or current_key() != key_,
reject by setting res_.SetRes(CmdRes::kErrOther, "wrapped command targets wrong
key") (or similar), and only call c_ptr->Execute() when current_key() is single
and equals key_; use the symbols args, opt, c_ptr, Initial, res().ok(),
current_key(), key_, and Execute to locate and implement this guard.

res_.AppendStringRaw(c_ptr->res().message());
return;
}
case 1:
res_.AppendInteger(1);
res_.AppendInteger(1);
Expand Down
Loading