You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4161768
Browse filesBrowse the repository at this point in the historyBrowse files
fix(mysql): harden protocol decoders against malformed packets from hostile servers (#4458)
Found during a security review of server-controlled parsing paths (threat model: rogue or MITM MySQL/MariaDB server; handshake parsing is reachable pre-authentication).
### Does your PR solve an issue?
No tracking issue — reported here directly. This extends the fix pattern of #4176 (truncated `OK` packet) to the rest of the protocol; #4451 documents the same review on the PostgreSQL side.
### The problem
- `recv_packet`'s continuation loop accumulated an unbounded number of `0xFFFFFF`-sized parts: a hostile server streams endless 16 MiB frames and the client OOMs at near-zero bandwidth cost.
- The result-set column count (a length-encoded u64) fed `HashMap::with_capacity` / `Vec::reserve` directly; a ~10-byte packet claiming 2^40 columns aborts the process.
- Dozens of decode sites call panicking `bytes::Buf` getters / slice indexing / `advance` on untrusted buffers: truncated ERR packets, every field of `HandshakeV10` (including the attacker-controlled auth-plugin-data length), length-encoded strings claiming more than the remaining bytes, `TextRow` field-count mismatch, `BinaryRow` (null bitmap, temporal length byte, fixed-width and lenenc value bounds — plus an `unreachable!()` actually reachable via a NULL-typed column), short EOF packets, and a 1-byte `caching_sha2_password` continue packet. The OkPacket decoder was hardened in #4176; the rest of the protocol was not.
### The change
- Cumulative 1 GiB cap on packet reassembly (`MySql`'s own `max_allowed_packet` hard ceiling); protocol error beyond it.
- Result sets claiming more than 4096 columns (the MySQL server hard limit) are protocol errors before any allocation.
- All listed sites check remaining length up front and return `Error::Protocol` describing expectation vs. reality; the `unreachable!()` is now an error.
### Is this a breaking change?
No: every changed path converts a panic or abort into a returned `Err`, which callers already handle (the pool discards the connection). Newly-observable edges: aggregate packets over 1 GiB and result sets over 4096 columns are now errors rather than allocation attempts.
### Regression tests
15 new unit tests, including a sweep asserting that every strict prefix of captured MySQL 8.0.18 and MariaDB 10.4.7 handshake packets now errors instead of panicking. Each test fails (panics) without the fix. `cargo test -p sqlx-mysql --lib` passes.
0 commit comments