Enforce integer limits of the Postgres wire protocol #1161
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem
The Postgres wire protocol has certain fields that contain fixed-size integers, such as the 32-bit message length (see here). This library does not check if values fit into these fixed-size fields before writing them to the buffer. This can lead to the truncation of the values being written, causing corrupted messages.
Example: If the message to be sent is$4^{32} + 4$ bytes long, the length cannot fit into the 4-byte length field. The value written to the buffer will be $4$ by the Postgres database when it receives such a message. Therefore, the Postgres database will think the message has a length of 4 and will try to read the next message after those 4 bytes.
\x00\x00\x00\x04
, which gets decoded toAfter such a malformed message, the client and the database have different understandings of where messages start and end. In the best case, this causes a connection abort due to a parsing error. In the worst case, this leads to the execution of malicious SQL statements that an attacker has injected into a large payload that ends up in an SQL query.
Solution
I added size checks that error if the value being written is too large for its field. Since the functions that I changed don't return errors, I had to
panic()
in the error case. I opted for this route because I noticed that other functions do the same (example 1, example 2). Please let me know if there's a different error-handling mechanism I should use; then I'll amend the PR.