Repository navigation
fix: native safety fixes [todo:S6,S5,B3] - #9
Merged
Merged
Conversation
The protocol parser sliced server bytes with no bounds check. Release builds abort on a panic, so a short or broken message killed the whole Dart process. Now every read is checked and gives an error. Negative lengths from Dart are also refused, not cast to a huge usize.
dpg_connect turned any verify value other than 1 or 2 into no check, so the verifier took any certificate. Now only 0 (require, prefer) skips the check. Any other value is the full check.
Member
Author
Bot reviewVerdict: OK No blocking problems. The small points below are optional. They can go in this PR or a later one.
What I checked
Results
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Safety fixes in the Rust part. One commit per item. B3 was already fixed on main, so it has no commit (see below).
S6: a short server message kills the Dart process
Problem. The backend message parser in
native/src/conn.rsread server bytes with plain indexing:be16,be32,columns()(RowDescription),row()(DataRow) and the auth message inlogin()(&body[4..],data[..4]). There was no bounds check. Alsodpg_connectanddpg_submitdidlen as usizeon lengths from Dart.What it causes. Release builds use
panic = "abort". So a short or broken message from the server (or a proxy, or a man in the middle) aborts the whole Dart process, not just the query. A negative length becomes a hugeusize, which is undefined behavior infrom_raw_parts.Fix.
take()readsnbytes atpwith.get()and gives an error when they are not there.be16andbe32use it and returnResult.columns()androw()returnResult, and a column name with no end byte is an error.login()uses.get()too. The error isdox_postgres_native: bad message from the server. It fails the connection, like other read errors.bytes(ptr, len)inlib.rs: a negative length or a null pointer is an empty slice.dpg_connectreturns -1 for a negativelenorroot_len.dpg_submitusesbytes().Tests:
short_or_broken_messages_are_errors_not_panicsandnegative_ffi_lengths_are_refused.S5 (Rust part): the verifier takes any certificate
Problem.
dpg_connectmappedverify1 to the full check and 2 to the chain check. Any other value meant no check. With no check,Verifiertakes any certificate.What it causes. A wrong or new
verifyvalue turns the check off without a sign. A man in the middle can then read the traffic.Fix. New
Check::of(verify): only 0 skips the check (require,prefer, like libpq). 2 is the chain check. Any other value is the full check (verify-full). So a bad value fails closed.The main part of S5 is in dox-orm (dartondox/dox-orm#23): there
useSSL: truenow givesverify-full, notrequire. The Dart side of this package already sends 1 forverify-fulland 2 forverify-ca. An explicitsslMode: 'require'still skips the check on purpose, like libpq (eg. Heroku).Test:
an_unknown_verify_value_is_the_full_check.B3: the native link is never freed (already fixed)
I checked this and it is not a problem on main any more.
gone()innative/src/link.rsends withArc::decrement_strong_count(self as *const Link). That gives back the reference fromArc::into_rawindpg_open. It came in with #5.gone()runs once, from the helper thread, and then the helper returns and drops its own clone. So the link is freed when the isolate exits. No change is made for B3.Checks
cargo fmt --check,cargo clippy --release --all-targets -- -D warnings,cargo test --release: pass (11 tests).dart format,dart analyze --fatal-infos: no issues.DRIVER=postgres dart test --concurrency=1with a local release build: all pass on Postgres 16 (TLS off, like CI).