Skip to content
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

Fix a potential null pointer deref in the Sqlite backend #4224

Merged
merged 1 commit into from
Sep 3, 2024

Conversation

weiznich
Copy link
Member

@weiznich weiznich commented Sep 2, 2024

The documentation of sqlite3_prepare_v3 states that:

*ppStmt is left pointing to a compiled prepared statement that can be
executed using sqlite3_step(). If there is an error, *ppStmt is set to NULL. If the input text contains no SQL (if the input is an empty string or a comment) then *ppStmt is set to NULL. The calling procedure is responsible for deleting the compiled SQL statement using sqlite3_finalize() after it has finished with it. ppStmt may not be NULL.

We already guard against the error case there before constructing the NonNull pointer, we do not guard against empty statements yet. This commit fixes that particular issue + adds a test to check if the fix works as expected.

This fixes #4223

@weiznich weiznich added the maybe backport Maybe backport this pr to the latest diesel release label Sep 2, 2024
@weiznich
Copy link
Member Author

weiznich commented Sep 2, 2024

cc @diesel-rs/core I would like to release that as patch release somewhen this week.

crate::result::EmptyQuery,
)));
}

Copy link
Contributor

@stormshield-kg stormshield-kg Sep 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a check after the call to sqlite3_prepare_v3() to ensure that stmt is not null before calling NonNull::new_unchecked() ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the documentation of sqlite3_prepare_v3 that shouldn't be necessary as we already cover both variants that are documented to return null. That written: It might still be worth to add that additional check to be sure.

Copy link
Contributor

@stormshield-kg stormshield-kg Sep 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above check is not enough, since the pointer will be null if the query string is not empty but contains only whitespaces or comments. We should also add a test for this.

@Ten0
Copy link
Member

Ten0 commented Sep 2, 2024

It looks like that doesn't guard against strings that are considered empty by sqlite, e.g. whitespace and comments-only.
It looks like it would be safer to replace the initial check on the Diesel side by a match on NonNull::new(stmt) after making the sqlite C call, returning EmptyQuery if at that point it's still a null pointer, instead of using new_unchecked.

@stormshield-kg
Copy link
Contributor

It looks like that doesn't guard against strings that are considered empty by sqlite, e.g. whitespace and comments-only. It looks like it would be safer to replace the initial check on the Diesel side by a match on NonNull::new(stmt) after making the sqlite C call, returning EmptyQuery if at that point it's still a null pointer, instead of using new_unchecked.

Yes, but it should be done only if the call returned ffi::SQLITE_OK.

Verified

This commit was signed with the committer’s verified signature.
sidharthv96 Sidharth Vinod
The documentation of `sqlite3_prepare_v3` states that:

> *ppStmt is left pointing to a compiled prepared statement that can be
executed using sqlite3_step(). If there is an error, *ppStmt is set to
NULL. If the input text contains no SQL (if the input is an empty string
or a comment) then *ppStmt is set to NULL. The calling procedure is
responsible for deleting the compiled SQL statement using
sqlite3_finalize() after it has finished with it. ppStmt may not be
NULL.

We already guard against the error case there before constructing the
`NonNull` pointer, we do not guard against empty statements yet. This
commit fixes that particular issue + adds a test to check if the fix
works as expected.

This fixes diesel-rs#4223
@weiznich
Copy link
Member Author

weiznich commented Sep 2, 2024

You are both correct, I misread that statment as literal empty string. Note to myself: Don't fix this kind of issues just before needing to leave.

I've now pushed a fixed version by using NonNull::new instead of the new_unchecked variant. I also also added tests for the other variants.

@weiznich weiznich added this pull request to the merge queue Sep 3, 2024
Merged via the queue into diesel-rs:master with commit de01971 Sep 3, 2024
48 checks passed
weiznich added a commit to weiznich/diesel that referenced this pull request Sep 3, 2024

Verified

This commit was signed with the committer’s verified signature.
sidharthv96 Sidharth Vinod
Fix a potential null pointer deref in the Sqlite backend
@weiznich weiznich mentioned this pull request Sep 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maybe backport Maybe backport this pr to the latest diesel release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Undefined behavior when using diesel::sql_query with an empty string for Sqlite
4 participants