Fix panic in Postgres Bytes decode (#1948)

This function can panic due to slicing out of bounds when the server
responds without the `\x` prefix. With this commit we instead error and
also ensure that the prefix is what we expect instead of blindly
removing it.

Not directly related to the panic, we replace as_str() with as_bytes()
because there is no reason to perform a utf8 validity check when
hex::decode already checks that the content is valid.
This commit is contained in:
Valentin 2022-07-07 03:23:29 +02:00 committed by GitHub
parent 79ebd3005a
commit b3bbdab705
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 1 deletions

View file

@ -55,7 +55,11 @@ impl Decode<'_, Postgres> for Vec<u8> {
PgValueFormat::Binary => value.as_bytes()?.to_owned(),
PgValueFormat::Text => {
// BYTEA is formatted as \x followed by hex characters
hex::decode(&value.as_str()?[2..])?
let text = value
.as_bytes()?
.strip_prefix(b"\\x")
.ok_or("text does not start with \\x")?;
hex::decode(text)?
}
})
}

View file

@ -1713,3 +1713,16 @@ async fn test_advisory_locks() -> anyhow::Result<()> {
Ok(())
}
#[sqlx_macros::test]
async fn test_postgres_bytea_hex_deserialization_errors() -> anyhow::Result<()> {
let mut conn = new::<Postgres>().await?;
conn.execute("SET bytea_output = 'escape';").await?;
for value in ["", "DEADBEEF"] {
let query = format!("SELECT '\\x{}'::bytea", value);
let res: sqlx::Result<Vec<u8>> = conn.fetch_one(query.as_str()).await?.try_get(0usize);
// Deserialization only supports hex format so this should error and definitely not panic.
res.unwrap_err();
}
Ok(())
}