improve media key decoding logs

On my HS I observed 5 instances of keys with the following format:

* MXC bytes.
* A 0xFF byte.
* 4 bytes where the width and height are supposed to be, which are
  supposed to be 8 bytes in length.
* 3 consecutive 0xFF bytes. This means that the `content-type` and
  `content-disposition` sections both parse as the empty string, and
  there's an extra separator at the end too.
* Extra bytes, all of which were `image/png`.

The 4 bytes where the width and height are supposed to be were one of:

* 003ED000
* 003EE000
* 003EF001

Which seems to have some kind of pattern to it...

After much digging, we have absolutely no idea what could've caused
this. Cursed.
This commit is contained in:
Charles Hall 2024-09-17 21:16:22 -07:00
parent d848e787d3
commit cb3e0c620a
No known key found for this signature in database
GPG key ID: 7B8E0645816E07CF
2 changed files with 23 additions and 7 deletions

View file

@ -19,24 +19,28 @@ struct MediaFileKeyParts {
impl TryFrom<&MediaFileKey> for MediaFileKeyParts {
type Error = Error;
#[tracing::instrument(
err,
fields(key = utils::u8_slice_to_hex(key.as_bytes())),
)]
fn try_from(key: &MediaFileKey) -> Result<MediaFileKeyParts> {
let mut parts = key.as_bytes().split(|&b| b == 0xFF);
let mxc_bytes = parts
.next()
.ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?;
.ok_or_else(|| Error::BadDatabase("Media ID in db is invalid."))?;
let mxc = utils::string_from_bytes(mxc_bytes)
.map_err(|_| {
Error::bad_database("Media MXC URI in db is invalid unicode.")
Error::BadDatabase("Media MXC URI in db is invalid unicode.")
})?
.into();
let thumbnail_size_bytes = parts
.next()
.ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?;
.ok_or_else(|| Error::BadDatabase("Media ID in db is invalid."))?;
let thumbnail_size_bytes: &[u8; 8] =
thumbnail_size_bytes.try_into().map_err(|_| {
Error::bad_database("Media ID thumbnail size in db is invalid")
Error::BadDatabase("Media ID thumbnail size in db is invalid")
})?;
let width = u32::from_be_bytes(
thumbnail_size_bytes[..4].try_into().expect("should be 4 bytes"),
@ -49,7 +53,7 @@ impl TryFrom<&MediaFileKey> for MediaFileKeyParts {
.next()
.map(|bytes| {
utils::string_from_bytes(bytes).map_err(|_| {
Error::bad_database(
Error::BadDatabase(
"Content type in mediaid_file is invalid unicode.",
)
})
@ -58,14 +62,14 @@ impl TryFrom<&MediaFileKey> for MediaFileKeyParts {
let content_disposition_bytes = parts
.next()
.ok_or_else(|| Error::bad_database("Media ID in db is invalid."))?;
.ok_or_else(|| Error::BadDatabase("Media ID in db is invalid."))?;
let content_disposition = if content_disposition_bytes.is_empty() {
None
} else {
Some(utils::string_from_bytes(content_disposition_bytes).map_err(
|_| {
Error::bad_database(
Error::BadDatabase(
"Content Disposition in mediaid_file is invalid \
unicode.",
)

View file

@ -4,6 +4,7 @@ pub(crate) mod on_demand_hashmap;
use std::{
borrow::Cow,
cmp, fmt,
fmt::Write,
str::FromStr,
time::{SystemTime, UNIX_EPOCH},
};
@ -366,6 +367,17 @@ pub(crate) fn curlify<T>(req: &http::Request<T>) -> Option<String> {
)
}
/// Format a u8 slice as an uppercase hex string
///
/// The output does not contain a leading `0x` nor any non-hex characters (e.g.
/// whitespace or commas do not appear in the output).
pub(crate) fn u8_slice_to_hex(slice: &[u8]) -> String {
slice.iter().fold(String::new(), |mut acc, x| {
write!(acc, "{x:X}").expect("in-memory write should succeed");
acc
})
}
#[cfg(test)]
mod tests {
use crate::utils::dbg_truncate_str;