reject a malformed mutable put instead of storing it as immutable - #8698
reject a malformed mutable put instead of storing it as immutable#8698dangowrt wants to merge 1 commit into
Conversation
|
this should have a unit test, at least covering all the cases where a PUT is treated as an invalid PUT rather than an immutable PUT. Another important consideration is that the response (error message) should be significantly smaller than the request. So if the incoming message is very short, we should probably not respond at all. That would open up for magnification attacks, since the source IP address can be spoofed. |
cc29a75 to
477dc75
Compare
|
Thanks — addressed both. Unit test. Added Amplification. Good catch — narrowed it so the reply can't be a magnifier:
Force-pushed with the narrowed predicate and the test. |
There was a problem hiding this comment.
🟡 Not ready to approve
The new malformed-mutable guard and test coverage don’t fully align with the PR description’s stated rejection criteria for malformed puts (notably around seq-only / missing-seq scenarios).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR tightens BEP 44 DHT put handling so that requests that appear to be mutable puts (by including mutable fields) but are not well-formed are rejected with protocol error 203, instead of being accepted and stored as immutable items.
Changes:
- Add a DHT-node-side guard to reject malformed “mutable”
putrequests early with error 203 and a specific message. - Add a unit test ensuring malformed mutable puts are rejected while a valid signed mutable put is still accepted.
File summaries
| File | Description |
|---|---|
src/kademlia/node.cpp |
Adds a validation gate rejecting malformed mutable puts instead of falling back to immutable storage. |
test/test_dht.cpp |
Adds a regression test for malformed mutable puts and validates correct mutable puts still work. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| // a put that carries a public key or signature claims to be a mutable | ||
| // put; if it isn't well-formed (seq, k and sig all present) reject it | ||
| // rather than silently storing the value as an immutable item under | ||
| // sha1(v). keying on k/sig keeps such a request larger than the error | ||
| // reply (a 32-byte key or 64-byte signature), so the reply can't be | ||
| // used to amplify traffic; it also sits after the write-token check | ||
| if ((msg_keys[3] || msg_keys[4]) && !mutable_put) |
There was a problem hiding this comment.
I prefer the previous version of this. My comment about magnification was a bit hasty. This is already after we check the write_token, so you can't abuse this part in a magnification attack.
And, in either case, such protection should probably be implemented at a higher level anyway, looking at packet sizes.
| // each of these carries the public key (so it targets the mutable id and | ||
| // reuses the token above) but is missing at least one of seq/sig | ||
| msg_args const malformed[] = | ||
| { | ||
| msg_args().token(token).value(value).key(pk).seq(seq), // no sig | ||
| msg_args().token(token).value(value).key(pk), // no sig, no seq | ||
| }; |
The DHT put handler treats a put as mutable only when seq, k and sig are all present and valid, and otherwise stores the value as an immutable item at sha1(v). A put carrying a public key or signature but missing (or mistyping) one of the other mutable fields was therefore stored as immutable rather than rejected: the signature was never checked and the item was not at sha1(pk+salt) where a reader looks for it. Reject a put that carries a k or sig but is not a well-formed mutable put; genuine immutable puts (neither field present) are unaffected. Keying on k/sig keeps the error reply smaller than the request so it cannot be used to amplify traffic, and the check runs after the write-token verification. Adds a unit test covering the rejected cases and a correctly signed put that still stores.
477dc75 to
2641b45
Compare
|
Re the automated review:
|
Not necessarily, it can be > 1kiB. I prefer to protect against reflection/magnification attacks separately |
The DHT put handler treats a put as mutable only when
seq,kandsigareall present and valid, and otherwise stores the value as an immutable item at
sha1(v). A put that carries a public key or signature but is missing (ormistypes) one of the other mutable fields — a wrong-length or absent
sig, amissing or mistyped
seq— is therefore stored as an immutable item rather thanrejected: the signature is never checked, and the item is not at
sha1(pk+salt)where a reader looks for it.
This rejects a put that carries a
korsigbut is not a well-formed mutableput, with protocol error 203; genuine immutable puts (neither field present) are
unaffected.
Keying the rejection on
k/sigrather than onseqas well is deliberate: aput claiming to be mutable always carries a 32-byte key or 64-byte signature, so
the error reply is always much smaller than the request and can't be used to
amplify traffic (the check also runs after the write-token verification). A put
carrying only a
seqand no key or signature is small, so rather than answer itwith an error it is left as a plain immutable put.
Found with a black-box BEP 44 conformance suite; verified by rebuilding
libtorrent and running
test/test_dht— the newput_malformed_mutabletest(k+seq without sig, k alone, and k+sig without seq all rejected with 203; a
correctly signed put still stored) and the full DHT suite pass.