mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 21:11:52 +00:00
M12: an XFA template parsed directly is held to the packet size limit
parse() refuses a template larger than the 64 MiB a document's packets may hold (read_packets' limit), before any of it is parsed, so what parsing keeps of it, item lists held by the field and its properties among them, stays within a few times that whoever calls it (review). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv
This commit is contained in:
1 parent
17ad260d71
commit
0481b98cda
3 files changed
+26
-2
No files matched your search
@@ -5,8 +5,9 @@ use pdfcraft_cos::{Document, Object};
|
||||
|
||||
use crate::XfaError;
|
||||
|
||||
/// Most decoded packet bytes read in total.
|
||||
const MAX_XDP: usize = 64 << 20;
|
||||
/// Most decoded packet bytes read in total; a template handed to [`crate::parse`] directly is held
|
||||
/// to the same.
|
||||
pub(crate) const MAX_XDP: usize = 64 << 20;
|
||||
|
||||
/// What was found in the XFA entry.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
|
||||
@@ -969,6 +969,16 @@ fn collect_page_roles(nodes: &[Node], out: &mut Vec<(String, PageRole)>, depth:
|
||||
|
||||
/// Parse a template packet. Returns the template and the warnings met on the way.
|
||||
pub fn parse(xml: &str) -> Result<(Template, Vec<String>), XfaError> {
|
||||
// As read from a document ([`crate::read_packets`]): a template parsed directly is no bigger,
|
||||
// so what parsing keeps of it (item lists are held by the field and its properties) stays
|
||||
// within a few times that.
|
||||
if xml.len() > crate::packets::MAX_XDP {
|
||||
return Err(XfaError::TooLarge(format!(
|
||||
"the template is {} MiB, past the {} MiB the reader accepts",
|
||||
xml.len() >> 20,
|
||||
crate::packets::MAX_XDP >> 20
|
||||
)));
|
||||
}
|
||||
let depth = crate::xml_nesting_depth(xml);
|
||||
if depth > crate::MAX_XML_DEPTH {
|
||||
return Err(XfaError::Malformed(format!(
|
||||
|
||||
@@ -221,3 +221,16 @@ fn a_caption_s_rich_text_and_a_list_s_items_are_kept() {
|
||||
assert_eq!(f.common.props.elements[2].attrs, [("save".to_string(), "1".to_string())]);
|
||||
assert_eq!(f.items.len(), 400, "the list shows the same entries");
|
||||
}
|
||||
|
||||
/// A template handed to `parse` directly is held to the bytes a document's packets may hold: one
|
||||
/// past them is refused before any of it is parsed, so the item lists a field and its properties
|
||||
/// keep of it can't grow past a few times that.
|
||||
#[test]
|
||||
fn a_template_past_the_packet_limit_is_refused_before_parsing() {
|
||||
let limit = crate::packets::MAX_XDP;
|
||||
let head = r#"<template xmlns="http://www.xfa.org/schema/xfa-template/3.3/"><subform name="form"><field name="f"><items><text>"#;
|
||||
let tail = "</text></items></field></subform></template>";
|
||||
let xml = format!("{head}{}{tail}", "a".repeat(limit + 1 - head.len() - tail.len()));
|
||||
assert_eq!(xml.len(), limit + 1);
|
||||
assert!(matches!(crate::parse(&xml), Err(crate::XfaError::TooLarge(_))));
|
||||
}
|
||||
Reference in new issue
Block a user