]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
json: add flags parameter to json_parse_file(), for parsing "sensitive" data
authorLennart Poettering <lennart@poettering.net>
Tue, 8 Jan 2019 17:48:48 +0000 (18:48 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 2 Dec 2019 08:47:00 +0000 (09:47 +0100)
This will call json_variant_sensitive() internally while parsing for
each allocated sub-variant. This is better than calling it a posteriori
at the end, because partially parsed variants will always be properly
erased from memory this way.

src/fuzz/fuzz-json.c
src/nspawn/nspawn-oci.c
src/shared/json.c
src/shared/json.h
src/shared/varlink.c
src/test/test-json.c

index ce7b69dbb99f639600b625d3b359e3290503ea8a..c01e2a570c50a6189d2b1f2c9cb2c34d11be6ac0 100644 (file)
@@ -18,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         f = fmemopen_unlocked((char*) data, size, "re");
         assert_se(f);
 
-        if (json_parse_file(f, NULL, &v, NULL, NULL) < 0)
+        if (json_parse_file(f, NULL, 0, &v, NULL, NULL) < 0)
                 return 0;
 
         g = open_memstream_unlocked(&out, &out_size);
index 4519c74b95b3582778f4bfd53ecfaa9e46d8c424..ba8b142c99ec3bc160f297194a9d93df687f317b 100644 (file)
@@ -2214,7 +2214,7 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
 
         path = strjoina(bundle, "/config.json");
 
-        r = json_parse_file(f, path, &oci, &line, &column);
+        r = json_parse_file(f, path, 0, &oci, &line, &column);
         if (r < 0) {
                 if (line != 0 && column != 0)
                         return log_error_errno(r, "Failed to parse '%s' at %u:%u: %m", path, line, column);
index 377a2c455a2e9886da8527708ba1db78892207d9..98fa067ef4db5ceffb367fc9cd53f893fcadf399 100644 (file)
@@ -2479,6 +2479,7 @@ static void json_stack_release(JsonStack *s) {
 static int json_parse_internal(
                 const char **input,
                 JsonSource *source,
+                JsonParseFlags flags,
                 JsonVariant **ret,
                 unsigned *line,
                 unsigned *column,
@@ -2797,6 +2798,12 @@ static int json_parse_internal(
                 }
 
                 if (add) {
+                        /* If we are asked to make this parsed object sensitive, then let's apply this
+                         * immediately after allocating each variant, so that when we abort half-way
+                         * everything we already allocated that is then freed is correctly marked. */
+                        if (FLAGS_SET(flags, JSON_PARSE_SENSITIVE))
+                                json_variant_sensitive(add);
+
                         (void) json_variant_set_source(&add, source, line_token, column_token);
 
                         if (!GREEDY_REALLOC(current->elements, current->n_elements_allocated, current->n_elements + 1)) {
@@ -2825,15 +2832,15 @@ finish:
         return r;
 }
 
-int json_parse(const char *input, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
-        return json_parse_internal(&input, NULL, ret, ret_line, ret_column, false);
+int json_parse(const char *input, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
+        return json_parse_internal(&input, NULL, flags, ret, ret_line, ret_column, false);
 }
 
-int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
-        return json_parse_internal(p, NULL, ret, ret_line, ret_column, true);
+int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
+        return json_parse_internal(p, NULL, flags, ret, ret_line, ret_column, true);
 }
 
-int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
+int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
         _cleanup_(json_source_unrefp) JsonSource *source = NULL;
         _cleanup_free_ char *text = NULL;
         const char *p;
@@ -2855,7 +2862,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonVariant **ret,
         }
 
         p = text;
-        return json_parse_internal(&p, source, ret, ret_line, ret_column, false);
+        return json_parse_internal(&p, source, flags, ret, ret_line, ret_column, false);
 }
 
 int json_buildv(JsonVariant **ret, va_list ap) {
@@ -3093,7 +3100,7 @@ int json_buildv(JsonVariant **ret, va_list ap) {
                                 /* Note that we don't care for current->n_suppress here, we should generate parsing
                                  * errors even in suppressed object properties */
 
-                                r = json_parse(l, &add, NULL, NULL);
+                                r = json_parse(l, 0, &add, NULL, NULL);
                                 if (r < 0)
                                         goto finish;
                         } else
index dd1aff450ab60b5aca89fa25d027b1bcdc3a7901..d3e44d1b0436c4bd0a69c1d591b455db6d58d05d 100644 (file)
@@ -174,12 +174,16 @@ int json_variant_filter(JsonVariant **v, char **to_remove);
 
 int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *value);
 
-int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
-int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
-int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
+typedef enum JsonParseFlags {
+        JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */
+} JsonParseFlags;
 
-static inline int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
-        return json_parse_file_at(f, AT_FDCWD, path, ret, ret_line, ret_column);
+int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
+int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
+int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
+
+static inline int json_parse_file(FILE *f, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
+        return json_parse_file_at(f, AT_FDCWD, path, flags, ret, ret_line, ret_column);
 }
 
 enum {
index ee4fb9e843961105ec478fc4fe133cc8f7a3f451..e1d956e6490a9ef49d3b1ca595bfa554235f89d5 100644 (file)
@@ -577,7 +577,7 @@ static int varlink_parse_message(Varlink *v) {
 
         varlink_log(v, "New incoming message: %s", begin);
 
-        r = json_parse(begin, &v->current, NULL, NULL);
+        r = json_parse(begin, 0, &v->current, NULL, NULL);
         if (r < 0)
                 return r;
 
index a6613043b92408c9368df89e4f6e05dfe1a1d9a9..90b91f6310c80dc9e92913cfc672f7274c367bf7 100644 (file)
@@ -82,7 +82,7 @@ static void test_variant(const char *data, Test test) {
         _cleanup_free_ char *s = NULL;
         int r;
 
-        r = json_parse(data, &v, NULL, NULL);
+        r = json_parse(data, 0, &v, NULL, NULL);
         assert_se(r == 0);
         assert_se(v);
 
@@ -93,7 +93,7 @@ static void test_variant(const char *data, Test test) {
 
         log_info("formatted normally: %s\n", s);
 
-        r = json_parse(data, &w, NULL, NULL);
+        r = json_parse(data, JSON_PARSE_SENSITIVE, &w, NULL, NULL);
         assert_se(r == 0);
         assert_se(w);
         assert_se(json_variant_has_type(v, json_variant_type(w)));
@@ -110,7 +110,7 @@ static void test_variant(const char *data, Test test) {
 
         log_info("formatted prettily:\n%s", s);
 
-        r = json_parse(data, &w, NULL, NULL);
+        r = json_parse(data, 0, &w, NULL, NULL);
         assert_se(r == 0);
         assert_se(w);
 
@@ -302,7 +302,7 @@ static void test_build(void) {
 
         assert_se(json_variant_format(a, 0, &s) >= 0);
         log_info("GOT: %s\n", s);
-        assert_se(json_parse(s, &b, NULL, NULL) >= 0);
+        assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0);
         assert_se(json_variant_equal(a, b));
 
         a = json_variant_unref(a);
@@ -313,7 +313,7 @@ static void test_build(void) {
         s = mfree(s);
         assert_se(json_variant_format(a, 0, &s) >= 0);
         log_info("GOT: %s\n", s);
-        assert_se(json_parse(s, &b, NULL, NULL) >= 0);
+        assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0);
         assert_se(json_variant_format(b, 0, &t) >= 0);
         log_info("GOT: %s\n", t);
 
@@ -365,7 +365,7 @@ static void test_source(void) {
 
         assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r"));
 
-        assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0);
+        assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) >= 0);
 
         printf("--- non-pretty begin ---\n");
         json_variant_dump(v, 0, stdout, NULL);