Fix GEORADIUS STORE ACL bypass via duplicate options#3971
Conversation
The ACL path (getKeysFromCommandWithSpecs) preferred the JSON keyword key specs, whose search stops at the first matching STORE keyword. With duplicate options like STORE scratch STORE protected, ACL checked only the first key while execution used the last, bypassing write ACLs on the real destination. Flag the STORE/STOREDIST key specs VARIABLE_FLAGS so ACL key extraction falls through to georadiusGetKeys, which resolves the effective last destination (mirrors MIGRATE); regenerate commands.def. Also set accurate key flags (RO/ACCESS on the source, OW/UPDATE on the store key) in georadiusGetKeys, which previously returned flags 0 and would have skipped the read/write direction check. Add regression tests for the ACL bypass and COMMAND GETKEYS last-destination behavior. Refs trailofbits/ptp-valkey#21 Signed-off-by: Tjaden Hess <tjade273@gmail.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughUpdates GEORADIUS and GEORADIUSBYMEMBER commands to correctly handle repeated STORE/STOREDIST options by using the final destination key for ACL enforcement. Command schemas are marked with VARIABLE_FLAGS, the key extraction helper is updated to report accurate per-key flags, and comprehensive unit and ACL regression tests validate the behavior. ChangesGEO Command Variable Flags
🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Problem
getKeysFromCommandWithSpecs()(used by the ACL path andCOMMAND GETKEYS) prefers a command's JSON key specs over itsget_keys_functionwhen the specs carry no VARIABLE_FLAGS. For GEORADIUS/GEORADIUSBYMEMBER theSTORE/STOREDISTspecs are keyword searches, andgetKeysUsingKeySpecs()stops at the first matching keyword. Thegeo.cparser, however, is last-one-wins. So forGEORADIUS ... STORE scratch:ok STORE protected:dst, ACL only checksscratch:ok, while the command writes (or, when the source is missing, deletes)protected:dst, bypassing key-level write ACLs.A user with
+georadius, read on the source pattern, and write on only one benign destination pattern can delete or overwrite a key outside their permitted patterns.Fix
Flag the
STORE/STOREDISTkey specs ingeoradius.json/georadiusbymember.jsonwith VARIABLE_FLAGS sogetKeysFromCommandWithSpecs()falls through togeoradiusGetKeys, which resolves the effective (last) destination. This mirrors how MIGRATE routes through itsgetkeys_proc.commands.defregenerated.georadiusGetKeyspreviously returnedflags = 0for every key, since it was only used by cluster routing where read/write direction is irrelevant. Now that ACL uses it, setCMD_KEY_RO | CMD_KEY_ACCESSon the source andCMD_KEY_OW | CMD_KEY_UPDATEon the store key so%R~/%W~direction is enforced.Testing
Added regression tests:
tests/unit/acl-v2.tcl: a restricted user'sSTORE scratch:ok STORE protected:dstis denied with NOPERM (both the overwrite and the missing-source delete variant), checked viaACL DRYRUNand end-to-end; a legitimate single destination still works.tests/unit/geo.tcl:COMMAND GETKEYS ... STORE a STORE breturns the last destinationbfor both commands.