mirror of
https://github.com/systemd/systemd.git
synced 2025-01-05 13:18:06 +03:00
varlink: limit the maximum nesting depth
Let's limit the maximum nesting depth for structure definitions to 64 to avoid stack overflows with very deep definitions. Resolves: #29589
This commit is contained in:
parent
d2e99d288e
commit
69d17e23db
@ -6,6 +6,8 @@
|
|||||||
#include "varlink-idl.h"
|
#include "varlink-idl.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
|
|
||||||
|
#define DEPTH_MAX 64U
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
COLOR_SYMBOL_TYPE, /* interface, method, type, error */
|
COLOR_SYMBOL_TYPE, /* interface, method, type, error */
|
||||||
COLOR_FIELD_TYPE, /* string, bool, … */
|
COLOR_FIELD_TYPE, /* string, bool, … */
|
||||||
@ -562,13 +564,14 @@ static int varlink_idl_subparse_whitespace(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int varlink_idl_subparse_struct_or_enum(const char **p, unsigned *line, unsigned *column, VarlinkSymbol **symbol, size_t *n_fields, VarlinkFieldDirection direction);
|
static int varlink_idl_subparse_struct_or_enum(const char **p, unsigned *line, unsigned *column, VarlinkSymbol **symbol, size_t *n_fields, VarlinkFieldDirection direction, unsigned depth);
|
||||||
|
|
||||||
static int varlink_idl_subparse_field_type(
|
static int varlink_idl_subparse_field_type(
|
||||||
const char **p,
|
const char **p,
|
||||||
unsigned *line,
|
unsigned *line,
|
||||||
unsigned *column,
|
unsigned *column,
|
||||||
VarlinkField *field) {
|
VarlinkField *field,
|
||||||
|
unsigned depth) {
|
||||||
|
|
||||||
size_t l;
|
size_t l;
|
||||||
int r;
|
int r;
|
||||||
@ -638,7 +641,8 @@ static int varlink_idl_subparse_field_type(
|
|||||||
column,
|
column,
|
||||||
&symbol,
|
&symbol,
|
||||||
&n_fields,
|
&n_fields,
|
||||||
VARLINK_REGULAR);
|
VARLINK_REGULAR,
|
||||||
|
depth + 1);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -677,7 +681,8 @@ static int varlink_idl_subparse_struct_or_enum(
|
|||||||
unsigned *column,
|
unsigned *column,
|
||||||
VarlinkSymbol **symbol,
|
VarlinkSymbol **symbol,
|
||||||
size_t *n_fields,
|
size_t *n_fields,
|
||||||
VarlinkFieldDirection direction) {
|
VarlinkFieldDirection direction,
|
||||||
|
unsigned depth) {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
STATE_OPEN,
|
STATE_OPEN,
|
||||||
@ -698,6 +703,9 @@ static int varlink_idl_subparse_struct_or_enum(
|
|||||||
assert(*symbol);
|
assert(*symbol);
|
||||||
assert(n_fields);
|
assert(n_fields);
|
||||||
|
|
||||||
|
if (depth > DEPTH_MAX)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Maximum nesting depth reached (%u).", *line, *column, DEPTH_MAX);
|
||||||
|
|
||||||
while (state != STATE_DONE) {
|
while (state != STATE_DONE) {
|
||||||
_cleanup_free_ char *token = NULL;
|
_cleanup_free_ char *token = NULL;
|
||||||
|
|
||||||
@ -765,7 +773,7 @@ static int varlink_idl_subparse_struct_or_enum(
|
|||||||
.field_direction = direction,
|
.field_direction = direction,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = varlink_idl_subparse_field_type(p, line, column, field);
|
r = varlink_idl_subparse_field_type(p, line, column, field, depth);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -992,7 +1000,7 @@ int varlink_idl_parse(
|
|||||||
symbol->symbol_type = VARLINK_METHOD;
|
symbol->symbol_type = VARLINK_METHOD;
|
||||||
symbol->name = TAKE_PTR(token);
|
symbol->name = TAKE_PTR(token);
|
||||||
|
|
||||||
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_INPUT);
|
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_INPUT, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1009,7 +1017,7 @@ int varlink_idl_parse(
|
|||||||
if (!streq(token, "->"))
|
if (!streq(token, "->"))
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Unexpected token '%s'.", *line, *column, token);
|
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "%u:%u: Unexpected token '%s'.", *line, *column, token);
|
||||||
|
|
||||||
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_OUTPUT);
|
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_OUTPUT, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1037,7 +1045,7 @@ int varlink_idl_parse(
|
|||||||
symbol->symbol_type = _VARLINK_SYMBOL_TYPE_INVALID; /* don't know yet if enum or struct, will be field in by varlink_idl_subparse_struct_or_enum() */
|
symbol->symbol_type = _VARLINK_SYMBOL_TYPE_INVALID; /* don't know yet if enum or struct, will be field in by varlink_idl_subparse_struct_or_enum() */
|
||||||
symbol->name = TAKE_PTR(token);
|
symbol->name = TAKE_PTR(token);
|
||||||
|
|
||||||
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_REGULAR);
|
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_REGULAR, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1065,7 +1073,7 @@ int varlink_idl_parse(
|
|||||||
symbol->symbol_type = VARLINK_ERROR;
|
symbol->symbol_type = VARLINK_ERROR;
|
||||||
symbol->name = TAKE_PTR(token);
|
symbol->name = TAKE_PTR(token);
|
||||||
|
|
||||||
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_REGULAR);
|
r = varlink_idl_subparse_struct_or_enum(&text, line, column, &symbol, &n_fields, VARLINK_REGULAR, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -249,6 +249,35 @@ TEST(validate_json) {
|
|||||||
assert_se(varlink_idl_validate_method_call(symbol, v, NULL) >= 0);
|
assert_se(varlink_idl_validate_method_call(symbol, v, NULL) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_recursive_one(unsigned depth) {
|
||||||
|
_cleanup_(varlink_interface_freep) VarlinkInterface *parsed = NULL;
|
||||||
|
_cleanup_free_ char *pre = NULL, *post = NULL, *text = NULL;
|
||||||
|
static const char header[] =
|
||||||
|
"interface recursive.test\n"
|
||||||
|
"type Foo (\n";
|
||||||
|
|
||||||
|
/* Generate a chain of nested structures, i.e. a: (a: (... (int))...) */
|
||||||
|
pre = strrep("a:(", depth);
|
||||||
|
post = strrep(")", depth);
|
||||||
|
if (!pre || !post)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
text = strjoin(header, pre, "int", post, ")");
|
||||||
|
if (!text)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
return varlink_idl_parse(text, NULL, NULL, &parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(recursive) {
|
||||||
|
assert_se(test_recursive_one(32) >= 0);
|
||||||
|
assert_se(test_recursive_one(64) >= 0);
|
||||||
|
|
||||||
|
/* We should handle this gracefully without a stack overflow */
|
||||||
|
assert_se(test_recursive_one(65) < 0);
|
||||||
|
assert_se(test_recursive_one(20000) < 0 );
|
||||||
|
}
|
||||||
|
|
||||||
static int test_method(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
static int test_method(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||||
JsonVariant *foo = json_variant_by_key(parameters, "foo"), *bar = json_variant_by_key(parameters, "bar");
|
JsonVariant *foo = json_variant_by_key(parameters, "foo"), *bar = json_variant_by_key(parameters, "bar");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user