Skip to content

Potential vulnerability: overflowing and truncating casts #3440

@abonander

Description

@abonander

Context

User "Sytten" on Discord brought to our attention the following presentation from this year's DEFCON: https://media.defcon.org/DEF%20CON%2032/DEF%20CON%2032%20presentations/DEF%20CON%2032%20-%20Paul%20Gerste%20-%20SQL%20Injection%20Isn't%20Dead%20Smuggling%20Queries%20at%20the%20Protocol%20Level.pdf

(Note: if there's a public page or blog post for this, or one is posted in the future, please let me know so I can include it for posterity.)

Essentially, encoding a value larger than 4GiB can cause the length prefix in the protocol to overflow, causing the server to interpret the rest of the string as binary protocol commands (or other data? it's not clear):

image
image

It appears SQLx does perform truncating casts in a way that could be problematic, for example:

(self.len() - offset - 4) as i32

This code has existed essentially since the beginning, so it is reasonable to assume that all published versions are affected.

It's hard to glean just from the slides exactly how this may be exploited, and in any case it requires a malicious input at least 4 GiB long.

Mitigation

As always, you should make sure your application is validating untrustworthy user input. Reject any input over 4 GiB, or any input that could encode to a string longer than 4 GiB. Dynamically built queries are also potentially problematic if it pushes the message size over this 4 GiB bound.

Encode::size_hint() can be used for sanity checks, but do not assume that the size returned is accurate. For example, the Json<T> and Text<T> adapters have no reasonable way to predict or estimate the final encoded size, so they just return size_of::<T>() instead.

For web application backends, consider adding some middleware that limits the size of request bodies by default.

Resolution

I have started work on a branch that adds #[deny] directives for the following Clippy lints:

and I'm auditing the code that they flag. This is the same approach being used by Diesel: diesel-rs/diesel#4170

In the process I realized that our CI wasn't running a lot of our unit tests, so I'm fixing that as well.

After the fix, attempting to encode a value larger than is allowed in a given binary protocol will return an error instead of silently truncating it.

I will also be filing a RUSTSEC advisory.

Metadata

Metadata

Assignees

No one assigned

    Labels

    advisoryIssues that may represent a vulnerabilitybug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions