Check PDU formats

This commit is contained in:
dasha_uwu
2025-12-18 01:34:02 +05:00
committed by Jason Volk
parent c5508bba58
commit 7b2079f714
8 changed files with 35 additions and 19 deletions

View File

@@ -6,6 +6,7 @@ use ruma::{
use crate::{ use crate::{
Result, extract_variant, is_equal_to, Result, extract_variant, is_equal_to,
matrix::{PduEvent, room_version}, matrix::{PduEvent, room_version},
state_res::{self},
}; };
pub fn into_outgoing_federation( pub fn into_outgoing_federation(
@@ -95,6 +96,8 @@ pub fn from_incoming_federation(
pdu_json.insert("event_id".into(), CanonicalJsonValue::String(event_id.into())); pdu_json.insert("event_id".into(), CanonicalJsonValue::String(event_id.into()));
} }
state_res::check_pdu_format(pdu_json, &room_rules.event_format)?;
PduEvent::from_val(pdu_json) PduEvent::from_val(pdu_json)
} }

View File

@@ -37,9 +37,7 @@ pub fn check_pdu_format(pdu: &CanonicalJsonObject, rules: &EventFormatRules) ->
.map_err(|e| err!(Request(BadJson("Failed to serialize canonical JSON: {e}"))))?; .map_err(|e| err!(Request(BadJson("Failed to serialize canonical JSON: {e}"))))?;
if json.len() > MAX_PDU_BYTES { if json.len() > MAX_PDU_BYTES {
return Err!(Request(InvalidParam( return Err!(Request(TooLarge("PDU is larger than maximum of {MAX_PDU_BYTES} bytes")));
"PDU is larger than maximum of {MAX_PDU_BYTES} bytes"
)));
} }
// Check the presence, type and length of the `type` field. // Check the presence, type and length of the `type` field.
@@ -133,7 +131,7 @@ fn extract_optional_string_field<'a>(
match object.get(field) { match object.get(field) {
| Some(CanonicalJsonValue::String(value)) => | Some(CanonicalJsonValue::String(value)) =>
if value.len() > ID_MAX_BYTES { if value.len() > ID_MAX_BYTES {
Err!(Request(InvalidParam( Err!(Request(TooLarge(
"invalid `{field}` field in PDU: string length is larger than maximum of \ "invalid `{field}` field in PDU: string length is larger than maximum of \
{ID_MAX_BYTES} bytes" {ID_MAX_BYTES} bytes"
))) )))
@@ -177,7 +175,7 @@ fn extract_required_array_field<'a>(
match object.get(field) { match object.get(field) {
| Some(CanonicalJsonValue::Array(value)) => | Some(CanonicalJsonValue::Array(value)) =>
if value.len() > max_len { if value.len() > max_len {
Err!(Request(InvalidParam( Err!(Request(TooLarge(
"invalid `{field}` field in PDU: array length is larger than maximum of \ "invalid `{field}` field in PDU: array length is larger than maximum of \
{max_len}" {max_len}"
))) )))

View File

@@ -225,6 +225,8 @@ pub async fn join_remote(
.server_keys .server_keys
.gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?; .gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
state_res::check_pdu_format(&join_event_stub, &room_version_rules.event_format)?;
// It has enough fields to be called a proper event now // It has enough fields to be called a proper event now
let mut join_event = join_event_stub; let mut join_event = join_event_stub;
@@ -634,6 +636,8 @@ pub async fn join_local(
)); ));
} }
let room_version_rules = room_version::rules(&room_version_id)?;
let mut join_event_stub: CanonicalJsonObject = let mut join_event_stub: CanonicalJsonObject =
serde_json::from_str(make_join_response.event.get()).map_err(|e| { serde_json::from_str(make_join_response.event.get()).map_err(|e| {
err!(BadServerResponse("Invalid make_join event json received from server: {e:?}")) err!(BadServerResponse("Invalid make_join event json received from server: {e:?}"))
@@ -699,6 +703,8 @@ pub async fn join_local(
.server_keys .server_keys
.gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?; .gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
state_res::check_pdu_format(&join_event_stub, &room_version_rules.event_format)?;
// It has enough fields to be called a proper event now // It has enough fields to be called a proper event now
let join_event = join_event_stub; let join_event = join_event_stub;

View File

@@ -11,8 +11,9 @@ use ruma::{
}; };
use tuwunel_core::{ use tuwunel_core::{
Err, Result, debug_info, debug_warn, err, implement, Err, Result, debug_info, debug_warn, err, implement,
matrix::PduCount, matrix::{PduCount, room_version},
pdu::PduBuilder, pdu::PduBuilder,
state_res,
utils::{self, FutureBoolExt, future::ReadyBoolExt}, utils::{self, FutureBoolExt, future::ReadyBoolExt},
warn, warn,
}; };
@@ -278,6 +279,8 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
))); )));
} }
let room_version_rules = room_version::rules(&room_version_id)?;
let mut leave_event_stub = serde_json::from_str::<CanonicalJsonObject>( let mut leave_event_stub = serde_json::from_str::<CanonicalJsonObject>(
make_leave_response.event.get(), make_leave_response.event.get(),
) )
@@ -312,6 +315,8 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
.server_keys .server_keys
.gen_id_hash_and_sign_event(&mut leave_event_stub, &room_version_id)?; .gen_id_hash_and_sign_event(&mut leave_event_stub, &room_version_id)?;
state_res::check_pdu_format(&leave_event_stub, &room_version_rules.event_format)?;
// It has enough fields to be called a proper event now // It has enough fields to be called a proper event now
let leave_event = leave_event_stub; let leave_event = leave_event_stub;

View File

@@ -68,6 +68,8 @@ pub(super) async fn handle_outlier_pdu(
let room_rules = room_version::rules(room_version)?; let room_rules = room_version::rules(room_version)?;
state_res::check_pdu_format(&pdu_json, &room_rules.event_format)?;
// Now that we have checked the signature and hashes we can make mutations and // Now that we have checked the signature and hashes we can make mutations and
// convert to our PduEvent type. // convert to our PduEvent type.
let event = from_incoming_federation(room_id, event_id, &mut pdu_json, &room_rules)?; let event = from_incoming_federation(room_id, event_id, &mut pdu_json, &room_rules)?;

View File

@@ -52,6 +52,8 @@ pub(super) async fn upgrade_outlier_to_timeline_pdu(
let timer = Instant::now(); let timer = Instant::now();
let room_rules = room_version::rules(room_version)?; let room_rules = room_version::rules(room_version)?;
state_res::check_pdu_format(&val, &room_rules.event_format)?;
// 10. Fetch missing state and auth chain events by calling /state_ids at // 10. Fetch missing state and auth chain events by calling /state_ids at
// backwards extremities doing all the checks in this list starting at 1. // backwards extremities doing all the checks in this list starting at 1.
// These are not timeline events. // These are not timeline events.

View File

@@ -187,17 +187,7 @@ pub async fn create_hash_and_sign_event(
pdu.event_id = self pdu.event_id = self
.services .services
.server_keys .server_keys
.gen_id_hash_and_sign_event(&mut pdu_json, &room_version) .gen_id_hash_and_sign_event(&mut pdu_json, &room_version)?;
.map_err(|e| {
use Error::Signatures;
use ruma::signatures::Error::PduSize;
match e {
| Signatures(PduSize) => {
err!(Request(TooLarge("PDU exceeds 65535 bytes")))
},
| _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))),
}
})?;
// Room id is event id for V12+ // Room id is event id for V12+
if matches!(version_rules.room_id_format, RoomIdFormatVersion::V2) if matches!(version_rules.room_id_format, RoomIdFormatVersion::V2)
@@ -207,6 +197,8 @@ pub async fn create_hash_and_sign_event(
pdu_json.insert("room_id".into(), CanonicalJsonValue::String(pdu.room_id.clone().into())); pdu_json.insert("room_id".into(), CanonicalJsonValue::String(pdu.room_id.clone().into()));
} }
state_res::check_pdu_format(&pdu_json, &version_rules.event_format)?;
// Generate short event id // Generate short event id
let _shorteventid = self let _shorteventid = self
.services .services

View File

@@ -1,6 +1,6 @@
use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId}; use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId};
use tuwunel_core::{ use tuwunel_core::{
Result, implement, Result, err, implement,
matrix::{event::gen_event_id, room_version}, matrix::{event::gen_event_id, room_version},
}; };
@@ -73,7 +73,15 @@ pub fn hash_and_sign_event(
object, object,
&room_version_rules.redaction, &room_version_rules.redaction,
) )
.map_err(Into::into) .map_err(|e| {
use ruma::signatures::Error::PduSize;
match e {
| PduSize => {
err!(Request(TooLarge("PDU exceeds 65535 bytes")))
},
| _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))),
}
})
} }
#[implement(super::Service)] #[implement(super::Service)]