DF-5675 / fix.diff
--- a/sys/libprop/prop_object_impl.h +++ b/sys/libprop/prop_object_impl.h @@ -45,6 +45,16 @@ unsigned int poec_depth; /* nesting depth */ }; +/* + * Maximum container nesting the (recursive) externalize walk will emit. + * Internalize, release and equals are iterative (prop_stack) and accept + * any depth; externalize recurses one stack frame per nesting level, so + * an attacker-supplied plist with deep <array>/<dict> nesting would + * otherwise exhaust the 16KB kernel thread stack (DF-5675: double fault + * at depth ~192, 64B/frame). Real-world plists nest < 10 levels. + */ +#define _PROP_EXTERNALIZE_MAX_DEPTH 64 + bool _prop_object_externalize_start_tag( struct _prop_object_externalize_context *, const char *); --- a/sys/libprop/prop_array.c +++ b/sys/libprop/prop_array.c @@ -155,6 +155,9 @@ unsigned int i; bool rv = false; + if (ctx->poec_depth >= _PROP_EXTERNALIZE_MAX_DEPTH) + return (false); + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); if (pa->pa_count == 0) { --- a/sys/libprop/prop_dictionary.c +++ b/sys/libprop/prop_dictionary.c @@ -433,6 +433,9 @@ unsigned int i; bool rv = false; + if (ctx->poec_depth >= _PROP_EXTERNALIZE_MAX_DEPTH) + return (false); + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); if (pd->pd_count == 0) { |