luci-lib-jsonc: prevent infinite recursion in stringify
Also increase the stack size as needed to prevent crashes when serializing deeply nested tables. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
5ae6f06014
commit
21db93576a
1 changed files with 74 additions and 3 deletions
|
@ -27,6 +27,12 @@ limitations under the License.
|
||||||
#define LUCI_JSONC "luci.jsonc"
|
#define LUCI_JSONC "luci.jsonc"
|
||||||
#define LUCI_JSONC_PARSER "luci.jsonc.parser"
|
#define LUCI_JSONC_PARSER "luci.jsonc.parser"
|
||||||
|
|
||||||
|
struct seen {
|
||||||
|
size_t size;
|
||||||
|
size_t len;
|
||||||
|
const void *ptrs[];
|
||||||
|
};
|
||||||
|
|
||||||
struct json_state {
|
struct json_state {
|
||||||
struct json_object *obj;
|
struct json_object *obj;
|
||||||
struct json_tokener *tok;
|
struct json_tokener *tok;
|
||||||
|
@ -35,6 +41,7 @@ struct json_state {
|
||||||
|
|
||||||
static void _json_to_lua(lua_State *L, struct json_object *obj);
|
static void _json_to_lua(lua_State *L, struct json_object *obj);
|
||||||
static struct json_object * _lua_to_json(lua_State *L, int index);
|
static struct json_object * _lua_to_json(lua_State *L, int index);
|
||||||
|
static struct json_object * _lua_to_json_rec(lua_State *L, int index, struct seen **seen);
|
||||||
|
|
||||||
static int json_new(lua_State *L)
|
static int json_new(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -199,6 +206,9 @@ static int _lua_test_array(lua_State *L, int index)
|
||||||
int max = 0;
|
int max = 0;
|
||||||
lua_Number idx;
|
lua_Number idx;
|
||||||
|
|
||||||
|
if (!lua_checkstack(L, 2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
|
|
||||||
/* check for non-integer keys */
|
/* check for non-integer keys */
|
||||||
|
@ -243,16 +253,54 @@ out:
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_object * _lua_to_json(lua_State *L, int index)
|
|
||||||
|
static bool visited(struct seen **sp, const void *ptr) {
|
||||||
|
struct seen *s = *sp;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (s->len >= s->size)
|
||||||
|
{
|
||||||
|
i = s->size + 10;
|
||||||
|
s = realloc(*sp, sizeof(struct seen) + sizeof(void *) * i);
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
{
|
||||||
|
if (*sp)
|
||||||
|
free(*sp);
|
||||||
|
|
||||||
|
*sp = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->size = i;
|
||||||
|
*sp = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < s->len; i++)
|
||||||
|
if (s->ptrs[i] == ptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
s->ptrs[s->len++] = ptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct json_object * _lua_to_json_rec(lua_State *L, int index,
|
||||||
|
struct seen **seen)
|
||||||
{
|
{
|
||||||
lua_Number nd, ni;
|
lua_Number nd, ni;
|
||||||
struct json_object *obj;
|
struct json_object *obj;
|
||||||
const char *key;
|
const char *key;
|
||||||
int i, max;
|
int i, max;
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
|
index = lua_gettop(L) + index + 1;
|
||||||
|
|
||||||
switch (lua_type(L, index))
|
switch (lua_type(L, index))
|
||||||
{
|
{
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
|
if (visited(seen, lua_topointer(L, index)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
max = _lua_test_array(L, index);
|
max = _lua_test_array(L, index);
|
||||||
|
|
||||||
if (max >= 0)
|
if (max >= 0)
|
||||||
|
@ -262,12 +310,15 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!lua_checkstack(L, 1))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (i = 1; i <= max; i++)
|
for (i = 1; i <= max; i++)
|
||||||
{
|
{
|
||||||
lua_rawgeti(L, index, i);
|
lua_rawgeti(L, index, i);
|
||||||
|
|
||||||
json_object_array_put_idx(obj, i - 1,
|
json_object_array_put_idx(obj, i - 1,
|
||||||
_lua_to_json(L, lua_gettop(L)));
|
_lua_to_json_rec(L, -1, seen));
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
@ -280,6 +331,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!lua_checkstack(L, 3))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
|
|
||||||
while (lua_next(L, index))
|
while (lua_next(L, index))
|
||||||
|
@ -289,7 +343,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
|
||||||
|
|
||||||
if (key)
|
if (key)
|
||||||
json_object_object_add(obj, key,
|
json_object_object_add(obj, key,
|
||||||
_lua_to_json(L, lua_gettop(L) - 1));
|
_lua_to_json_rec(L, -2, seen));
|
||||||
|
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
|
@ -318,6 +372,23 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct json_object * _lua_to_json(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
struct seen *s = calloc(sizeof(struct seen) + sizeof(void *) * 10, 1);
|
||||||
|
struct json_object *rv;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
s->size = 10;
|
||||||
|
|
||||||
|
rv = _lua_to_json_rec(L, index, &s);
|
||||||
|
|
||||||
|
free(s);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
static int json_parse_set(lua_State *L)
|
static int json_parse_set(lua_State *L)
|
||||||
{
|
{
|
||||||
struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
|
struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
|
||||||
|
|
Loading…
Reference in a new issue