2424#include "terminal-util.h"
2525#include "utf8.h"
2626
27+ /* Refuse putting together variants with a larger depth than 16K by default (as a protection against overflowing stacks
28+ * if code processes JSON objects recursively. Note that we store the depth in an uint16_t, hence make sure this
29+ * remains under 2^16. */
30+ #define DEPTH_MAX (16U*1024U)
31+ assert_cc (DEPTH_MAX <= UINT16_MAX );
32+
2733typedef struct JsonSource {
2834 /* When we parse from a file or similar, encodes the filename, to indicate the source of a json variant */
2935 size_t n_ref ;
@@ -63,6 +69,9 @@ struct JsonVariant {
6369 /* While comparing two arrays, we use this for marking what we already have seen */
6470 bool is_marked :1 ;
6571
72+ /* The current 'depth' of the JsonVariant, i.e. how many levels of member variants this has */
73+ uint16_t depth ;
74+
6675 union {
6776 /* For simple types we store the value in-line. */
6877 JsonValue value ;
@@ -158,6 +167,18 @@ static JsonVariant *json_variant_dereference(JsonVariant *v) {
158167 return json_variant_dereference (v -> reference );
159168}
160169
170+ static uint16_t json_variant_depth (JsonVariant * v ) {
171+
172+ v = json_variant_dereference (v );
173+ if (!v )
174+ return 0 ;
175+
176+ if (json_variant_is_magic (v ))
177+ return 0 ;
178+
179+ return v -> depth ;
180+ }
181+
161182static JsonVariant * json_variant_normalize (JsonVariant * v ) {
162183
163184 /* Converts json variants to their normalized form, i.e. fully dereferenced and wherever possible converted to
@@ -413,8 +434,7 @@ static void json_variant_copy_source(JsonVariant *v, JsonVariant *from) {
413434}
414435
415436int json_variant_new_array (JsonVariant * * ret , JsonVariant * * array , size_t n ) {
416- JsonVariant * v ;
417- size_t i ;
437+ _cleanup_ (json_variant_unrefp ) JsonVariant * v = NULL ;
418438
419439 assert_return (ret , - EINVAL );
420440 if (n == 0 ) {
@@ -430,22 +450,29 @@ int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n) {
430450 * v = (JsonVariant ) {
431451 .n_ref = 1 ,
432452 .type = JSON_VARIANT_ARRAY ,
433- .n_elements = n ,
434453 };
435454
436- for (i = 0 ; i < n ; i ++ ) {
437- JsonVariant * w = v + 1 + i ;
455+ for (v -> n_elements = 0 ; v -> n_elements < n ; v -> n_elements ++ ) {
456+ JsonVariant * w = v + 1 + v -> n_elements ,
457+ * c = array [v -> n_elements ];
458+ uint16_t d ;
459+
460+ d = json_variant_depth (c );
461+ if (d >= DEPTH_MAX ) /* Refuse too deep nesting */
462+ return - ELNRNG ;
463+ if (d >= v -> depth )
464+ v -> depth = d + 1 ;
438465
439466 * w = (JsonVariant ) {
440467 .is_embedded = true,
441468 .parent = v ,
442469 };
443470
444- json_variant_set (w , array [ i ] );
445- json_variant_copy_source (w , array [ i ] );
471+ json_variant_set (w , c );
472+ json_variant_copy_source (w , c );
446473 }
447474
448- * ret = v ;
475+ * ret = TAKE_PTR ( v ) ;
449476 return 0 ;
450477}
451478
@@ -468,6 +495,7 @@ int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n) {
468495 .n_ref = 1 ,
469496 .type = JSON_VARIANT_ARRAY ,
470497 .n_elements = n ,
498+ .depth = 1 ,
471499 };
472500
473501 for (i = 0 ; i < n ; i ++ ) {
@@ -505,6 +533,7 @@ int json_variant_new_array_strv(JsonVariant **ret, char **l) {
505533 * v = (JsonVariant ) {
506534 .n_ref = 1 ,
507535 .type = JSON_VARIANT_ARRAY ,
536+ .depth = 1 ,
508537 };
509538
510539 for (v -> n_elements = 0 ; v -> n_elements < n ; v -> n_elements ++ ) {
@@ -536,8 +565,7 @@ int json_variant_new_array_strv(JsonVariant **ret, char **l) {
536565}
537566
538567int json_variant_new_object (JsonVariant * * ret , JsonVariant * * array , size_t n ) {
539- JsonVariant * v ;
540- size_t i ;
568+ _cleanup_ (json_variant_unrefp ) JsonVariant * v = NULL ;
541569
542570 assert_return (ret , - EINVAL );
543571 if (n == 0 ) {
@@ -554,22 +582,29 @@ int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n) {
554582 * v = (JsonVariant ) {
555583 .n_ref = 1 ,
556584 .type = JSON_VARIANT_OBJECT ,
557- .n_elements = n ,
558585 };
559586
560- for (i = 0 ; i < n ; i ++ ) {
561- JsonVariant * w = v + 1 + i ;
587+ for (v -> n_elements = 0 ; v -> n_elements < n ; v -> n_elements ++ ) {
588+ JsonVariant * w = v + 1 + v -> n_elements ,
589+ * c = array [v -> n_elements ];
590+ uint16_t d ;
591+
592+ d = json_variant_depth (c );
593+ if (d >= DEPTH_MAX ) /* Refuse too deep nesting */
594+ return - ELNRNG ;
595+ if (d >= v -> depth )
596+ v -> depth = d + 1 ;
562597
563598 * w = (JsonVariant ) {
564599 .is_embedded = true,
565600 .parent = v ,
566601 };
567602
568- json_variant_set (w , array [ i ] );
569- json_variant_copy_source (w , array [ i ] );
603+ json_variant_set (w , c );
604+ json_variant_copy_source (w , c );
570605 }
571606
572- * ret = v ;
607+ * ret = TAKE_PTR ( v ) ;
573608 return 0 ;
574609}
575610
0 commit comments