summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-11-05 10:07:22 +0100
committerGravatar Nikias Bassen2026-11-05 10:07:22 +0100
commit2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3 (patch)
tree26648136f289451bddef614b124a168cb6b9669a /src
parent51f471432715f7a1880d38c135ce41182b4dc78e (diff)
downloadlibplist-2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3.tar.gz
libplist-2b3cc554270d34ca1e1fae3eb2cbbc740a65bbf3.tar.bz2
bplist: limit total parsed nodes to prevent memory exhaustionHEADmaster
Binary plist objects may be referenced multiple times, and each reference is parsed into a separate node. A tiny crafted input where arrays reference the same objects repeatedly (without forming a cycle, so the recursion check does not trigger) expands into millions of nodes and exhausts memory. Track the number of nodes parsed and fail with PLIST_ERR_PARSE once it exceeds num_objects * 16 + 65536. Legitimate files create roughly as many nodes as they have objects, so they stay well below this limit. Credit to OSSFuzz
Diffstat (limited to 'src')
-rw-r--r--src/bplist.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/bplist.c b/src/bplist.c
index 8168572..e5ace3a 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -237,6 +237,8 @@ struct bplist_data {
uint8_t offset_size;
const char* offset_table;
uint32_t level;
+ uint64_t nodes_parsed;
+ uint64_t max_nodes;
ptrarray_t* used_indexes;
plist_err_t err;
};
@@ -866,6 +868,14 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
return NULL;
}
+ /* Objects can be referenced multiple times, so limit the total number of
+ nodes created to avoid excessive memory use from reference expansion. */
+ if (++bplist->nodes_parsed > bplist->max_nodes) {
+ PLIST_BIN_ERR("too many nodes created while parsing (reference expansion?)\n");
+ bplist->err = PLIST_ERR_PARSE;
+ return NULL;
+ }
+
/* check nesting depth */
if (bplist->level > PLIST_MAX_NESTING_DEPTH) {
PLIST_BIN_ERR("maximum nesting depth (%u) exceeded\n",(unsigned)PLIST_MAX_NESTING_DEPTH);
@@ -1003,6 +1013,8 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
bplist.offset_size = offset_size;
bplist.offset_table = offset_table;
bplist.level = 0;
+ bplist.nodes_parsed = 0;
+ bplist.max_nodes = num_objects * 16 + 65536;
bplist.used_indexes = ptr_array_new(16);
bplist.err = PLIST_ERR_SUCCESS;