summaryrefslogtreecommitdiffstats
path: root/src/plist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-11-05 09:35:33 +0100
committerGravatar Nikias Bassen2026-11-05 09:35:33 +0100
commit3e9c034c93fa6f59584ec179d3df1333f250c694 (patch)
tree96444ba52f58f002229d1b6724082e7c27d3e426 /src/plist.c
parentfe3dc34dc3484006e12b403f7ceb06f0ad40b6f4 (diff)
downloadlibplist-3e9c034c93fa6f59584ec179d3df1333f250c694.tar.gz
libplist-3e9c034c93fa6f59584ec179d3df1333f250c694.tar.bz2
plist: fix use-after-free in plist_copy_node() on stack realloc
plist_copy_node() kept a pointer `f` to the top frame of its traversal stack and dereferenced it after the stack was grown with realloc(), which may move the buffer. Plists nested deeper than 64 levels hit this path, causing a heap-use-after-free when reading f->depth. Read the child depth before the realloc and use it when building the new frame. Thanks to @sdnuhfiu for reporting! Fixes #328
Diffstat (limited to 'src/plist.c')
-rw-r--r--src/plist.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/src/plist.c b/src/plist.c
index bcd212c..66fe1ab 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -921,6 +921,8 @@ static plist_t plist_copy_node(node_t root)
f->node_index++;
// push child frame to process its children
+ // (read depth before realloc, which may invalidate f)
+ int child_depth = f->depth + 1;
if (sp == cap) {
cap += 64;
copy_frame_t *tmp = (copy_frame_t*)realloc(st, cap * sizeof(*st));
@@ -940,7 +942,7 @@ static plist_t plist_copy_node(node_t root)
nf.type = newch_type;
nf.next_child = node_first_child(ch);
nf.node_index = 0;
- nf.depth = f->depth + 1;
+ nf.depth = child_depth;
st[sp++] = nf;
}