1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +02:00

additional hardening against mallformed demos

This commit is contained in:
Robin Appelman 2022-12-13 22:06:07 +01:00
commit a7a46384ce
4 changed files with 45 additions and 9 deletions

View file

@ -297,6 +297,9 @@ impl Parse<'_> for PacketEntitiesMessage {
for _ in 0..updated_entries {
let diff: u32 = read_bit_var(&mut data)?;
last_index = last_index.saturating_add(diff as i32).saturating_add(1);
if last_index >= 2048 {
return Err(ParseError::InvalidDemo("invalid entity index"));
}
let entity_index = EntityId::from(last_index as u32);
let update_type = data.read()?;

View file

@ -414,7 +414,7 @@ pub fn parse_string_table_update<'a>(
for _ in 0..entry_count {
let index = if stream.read()? {
(last_entry + 1) as u16
last_entry.saturating_add(1) as u16
} else {
stream.read_sized(entry_bits as usize)?
};

View file

@ -54,7 +54,7 @@ impl Parse<'_> for TempEntitiesMessage {
let class_id = if stream.read()? {
let bits = log_base2(state.server_classes.len()) + 1;
(stream.read_sized::<u16>(bits as usize)? - 1).into()
(stream.read_sized::<u16>(bits as usize)?.saturating_sub(1)).into()
} else {
let last = events.last().ok_or(ParseError::InvalidDemo(
"temp entity update without previous",

View file

@ -319,7 +319,12 @@ fn test_parse_send_table_roundtrip() {
impl ParseSendTable {
pub fn flatten_props(&self, tables: &[ParseSendTable]) -> Result<Vec<SendPropDefinition>> {
let mut flat = Vec::with_capacity(32);
self.get_all_props(tables, &self.get_excludes(tables), &mut flat)?;
self.get_all_props(
tables,
&self.get_excludes(tables, &mut Vec::with_capacity(8)),
&mut flat,
Vec::with_capacity(8),
)?;
// sort often changed props before the others
let mut start = 0;
@ -335,7 +340,12 @@ impl ParseSendTable {
Ok(flat)
}
fn get_excludes<'a>(&'a self, tables: &'a [ParseSendTable]) -> Vec<SendPropIdentifier> {
fn get_excludes<'a>(
&'a self,
tables: &'a [ParseSendTable],
processed_tables: &mut Vec<SendTableName>,
) -> Vec<SendPropIdentifier> {
processed_tables.push(self.name.clone());
let mut excludes = Vec::with_capacity(8);
for prop in self.props.iter() {
@ -345,7 +355,9 @@ impl ParseSendTable {
prop.name.as_str(),
))
} else if let Some(table) = prop.get_data_table(tables) {
excludes.extend_from_slice(&table.get_excludes(tables));
if !processed_tables.contains(&table.name) {
excludes.extend_from_slice(&table.get_excludes(tables, processed_tables));
}
}
}
@ -358,10 +370,17 @@ impl ParseSendTable {
tables: &[ParseSendTable],
excludes: &[SendPropIdentifier],
props: &mut Vec<SendPropDefinition>,
processed_tables: Vec<SendTableName>,
) -> Result<()> {
let mut local_props = Vec::new();
self.get_all_props_iterator_props(tables, excludes, &mut local_props, props)?;
self.get_all_props_iterator_props(
tables,
excludes,
&mut local_props,
props,
processed_tables,
)?;
props.extend_from_slice(&local_props);
Ok(())
}
@ -372,17 +391,31 @@ impl ParseSendTable {
excludes: &[SendPropIdentifier],
local_props: &mut Vec<SendPropDefinition>,
props: &mut Vec<SendPropDefinition>,
processed_tables: Vec<SendTableName>,
) -> Result<()> {
let processed_tables = &processed_tables;
self.props
.iter()
.filter(|prop| !prop.is_exclude())
.filter(|prop| !excludes.iter().any(|exclude| *exclude == prop.identifier()))
.try_for_each(|prop| {
let mut child_processed_tables = processed_tables.clone();
child_processed_tables.push(self.name.clone());
if let Some(table) = prop.get_data_table(tables) {
if prop.flags.contains(SendPropFlag::Collapsible) {
table.get_all_props_iterator_props(tables, excludes, local_props, props)?;
if !processed_tables.contains(&table.name) {
if prop.flags.contains(SendPropFlag::Collapsible) {
table.get_all_props_iterator_props(
tables,
excludes,
local_props,
props,
child_processed_tables,
)?;
} else {
table.get_all_props(tables, excludes, props, child_processed_tables)?;
}
} else {
table.get_all_props(tables, excludes, props)?;
dbg!(table.name.as_str());
}
} else {
local_props.push(SendPropDefinition::try_from(prop)?);