json: add JSON_FORMAT_REFUSE_SENSITIVE to json_variant_format()
Returns -EPERM if any node in the variant is marked as sensitive, useful to avoid leaking data to log messages and so on
This commit is contained in:
@@ -1771,6 +1771,28 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool json_variant_is_sensitive_recursive(JsonVariant *v) {
|
||||
if (!v)
|
||||
return false;
|
||||
if (json_variant_is_sensitive(v))
|
||||
return true;
|
||||
if (v == JSON_VARIANT_MAGIC_EMPTY_ARRAY ||
|
||||
v == JSON_VARIANT_MAGIC_EMPTY_OBJECT)
|
||||
return false;
|
||||
if (!json_variant_is_regular(v))
|
||||
return false;
|
||||
if (!IN_SET(v->type, JSON_VARIANT_ARRAY, JSON_VARIANT_OBJECT))
|
||||
return false;
|
||||
if (v->is_reference)
|
||||
return json_variant_is_sensitive_recursive(v->reference);
|
||||
|
||||
for (size_t i = 0; i < json_variant_elements(v); i++)
|
||||
if (json_variant_is_sensitive_recursive(json_variant_by_index(v, i)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
|
||||
_cleanup_(memstream_done) MemStream m = {};
|
||||
size_t sz;
|
||||
@@ -1786,6 +1808,10 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) {
|
||||
if (flags & JSON_FORMAT_OFF)
|
||||
return -ENOEXEC;
|
||||
|
||||
if ((flags & JSON_FORMAT_REFUSE_SENSITIVE))
|
||||
if (json_variant_is_sensitive_recursive(v))
|
||||
return -EPERM;
|
||||
|
||||
f = memstream_init(&m);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
+12
-11
@@ -185,17 +185,18 @@ struct json_variant_foreach_state {
|
||||
int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
typedef enum JsonFormatFlags {
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_PRETTY_AUTO = 1 << 2, /* same, but only if connected to a tty (and JSON_FORMAT_NEWLINE otherwise) */
|
||||
JSON_FORMAT_COLOR = 1 << 3, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_COLOR_AUTO = 1 << 4, /* insert ANSI color sequences if colors_enabled() says so */
|
||||
JSON_FORMAT_SOURCE = 1 << 5, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 6, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 7, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
JSON_FORMAT_FLUSH = 1 << 8, /* call fflush() after dumping JSON */
|
||||
JSON_FORMAT_EMPTY_ARRAY = 1 << 9, /* output "[]" for empty input */
|
||||
JSON_FORMAT_OFF = 1 << 10, /* make json_variant_format() fail with -ENOEXEC */
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_PRETTY_AUTO = 1 << 2, /* same, but only if connected to a tty (and JSON_FORMAT_NEWLINE otherwise) */
|
||||
JSON_FORMAT_COLOR = 1 << 3, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_COLOR_AUTO = 1 << 4, /* insert ANSI color sequences if colors_enabled() says so */
|
||||
JSON_FORMAT_SOURCE = 1 << 5, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 6, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 7, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
JSON_FORMAT_FLUSH = 1 << 8, /* call fflush() after dumping JSON */
|
||||
JSON_FORMAT_EMPTY_ARRAY = 1 << 9, /* output "[]" for empty input */
|
||||
JSON_FORMAT_OFF = 1 << 10, /* make json_variant_format() fail with -ENOEXEC */
|
||||
JSON_FORMAT_REFUSE_SENSITIVE = 1 << 11, /* return EPERM if any node in the tree is marked as senstitive */
|
||||
} JsonFormatFlags;
|
||||
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
|
||||
|
||||
@@ -104,6 +104,17 @@ static void test_variant_one(const char *data, Test test) {
|
||||
assert_se(json_variant_has_type(w, json_variant_type(v)));
|
||||
assert_se(json_variant_equal(v, w));
|
||||
|
||||
s = mfree(s);
|
||||
r = json_variant_format(w, JSON_FORMAT_REFUSE_SENSITIVE, &s);
|
||||
assert_se(r == -EPERM);
|
||||
assert_se(!s);
|
||||
|
||||
s = mfree(s);
|
||||
r = json_variant_format(w, JSON_FORMAT_PRETTY, &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(s);
|
||||
assert_se((size_t) r == strlen(s));
|
||||
|
||||
s = mfree(s);
|
||||
w = json_variant_unref(w);
|
||||
|
||||
@@ -813,4 +824,98 @@ TEST(json_dispatch) {
|
||||
assert_se(foobar.l == INT16_MIN);
|
||||
}
|
||||
|
||||
TEST(json_sensitive) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL, *v = NULL;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_se(json_build(&a, JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "bar", "baz", "foo", "qux", "baz"))) >= 0);
|
||||
assert_se(json_build(&b, JSON_BUILD_STRV(STRV_MAKE("foo", "bar", "baz", "qux"))) >= 0);
|
||||
|
||||
json_variant_sensitive(a);
|
||||
|
||||
assert_se(json_variant_format(a, JSON_FORMAT_REFUSE_SENSITIVE, &s) == -EPERM);
|
||||
assert_se(!s);
|
||||
|
||||
r = json_variant_format(b, JSON_FORMAT_REFUSE_SENSITIVE, &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(s);
|
||||
assert_se((size_t) r == strlen(s));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
r = json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(s);
|
||||
assert_se((size_t) r == strlen(s));
|
||||
s = mfree(s);
|
||||
v = json_variant_unref(v);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_VARIANT("b", b),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
r = json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s);
|
||||
assert_se(r >= 0);
|
||||
assert_se(s);
|
||||
assert_se((size_t) r == strlen(s));
|
||||
s = mfree(s);
|
||||
v = json_variant_unref(v);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_VARIANT("b", b),
|
||||
JSON_BUILD_PAIR_VARIANT("a", a),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
assert_se(json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s) == -EPERM);
|
||||
assert_se(!s);
|
||||
v = json_variant_unref(v);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_VARIANT("b", b),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR_VARIANT("a", a),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
assert_se(json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s) == -EPERM);
|
||||
assert_se(!s);
|
||||
v = json_variant_unref(v);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_VARIANT("b", b),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR_VARIANT("a", a),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
assert_se(json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s) == -EPERM);
|
||||
assert_se(!s);
|
||||
v = json_variant_unref(v);
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_VARIANT("b", b),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_INTEGER(INT64_MIN)),
|
||||
JSON_BUILD_PAIR("d", JSON_BUILD_STRING("-9223372036854775808")),
|
||||
JSON_BUILD_PAIR("e", JSON_BUILD_EMPTY_OBJECT),
|
||||
JSON_BUILD_PAIR_VARIANT("a", a))) >= 0);
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
assert_se(json_variant_format(v, JSON_FORMAT_REFUSE_SENSITIVE, &s) == -EPERM);
|
||||
assert_se(!s);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
Reference in New Issue
Block a user