-
Notifications
You must be signed in to change notification settings - Fork 455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add explicit protocol validation when reading RESP messages #332
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only got about half-way through so far, but looks promising and much safer; some notes included
On the magic numbers vs readability topic vs performance topic; the
benchmark shows that on net8+ the inline read looks fine for perf, but if
you wanted to generalize without compromising, a
suggestion:
static readonly uint MeaningfulNameHere = Utils.CpuEndianUInt32("$1\r\n"u8);
(etc for different widths)
where the method would assert the length, do a coerced read, and reverse
endianness if needed, without using random numbers in the code.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM A lot of general goodness done here and I'm glad that people are contributing their BDN benchmarks to the repo!
Overview
This PR adds explicit syntax checks to ensure RESP packages follow the correct RESP syntax, safeguarding against vulnerabilities that result from malicious RESP packages.
Why is this important?
Not validating the complete RESP package syntax can expose vulnerabilities that allow attackers to divert Garnet's control flow and execute malicious actions. It also makes debugging of unintentionally malformed RESP messages much harder.
Take the following invalid RESP message as an example:
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$\r\n1\r\nPING\r\n
Without validation, this message will cause Tsavorite to crash and terminates the client connection without an explicit error message. With the changes in this PR Garnet will return a proper error message back to the client:
-ERR Protocol Error: Unexpected character '\x0d'
Please note that a parsing error will still close the affected RESP session, because it is impossible to safely recover from a malformed package without discarding the remaining read buffer.
Implementation Details
The PR makes the following changes:
RespParsingException
exception type that is used to indicate parsing errors and terminate the active RESP session. Note thatRespParsingExceptions
should only be used when the error is expected to be forwarded to the client.'$'
,'*'
,':'
and'\r\n'
Known limitations:
$-1\r\n
) requires specific opt-in by the caller ofReadLengthHeader()
to reduce the risk of unhandled null values.Performance Impact
Considering the requirement for additional checks in the RESP parsing logic — specifically bounds checking for digits and overflow validation for integers — we observed a noticeable impact on parsing performance. In certain scenarios, this impact extends to overall end-to-end performance as well. However, I believe this trade-off is justifiable given the significant improvements for security and stability.
Below I am listing the performance degradation I have measured for the different RESP parsing functions:
Please note that NA indicates a parsing error being thrown (i.e., length headers must not be negative).
Complete performance before PR
Complete performance after PR