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:
Jo-Philipp Wich 2018-12-21 13:16:16 +01:00
parent 5ae6f06014
commit 21db93576a

View file

@ -27,6 +27,12 @@ limitations under the License.
#define LUCI_JSONC "luci.jsonc"
#define LUCI_JSONC_PARSER "luci.jsonc.parser"
struct seen {
size_t size;
size_t len;
const void *ptrs[];
};
struct json_state {
struct json_object *obj;
struct json_tokener *tok;
@ -35,6 +41,7 @@ struct json_state {
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_rec(lua_State *L, int index, struct seen **seen);
static int json_new(lua_State *L)
{
@ -199,6 +206,9 @@ static int _lua_test_array(lua_State *L, int index)
int max = 0;
lua_Number idx;
if (!lua_checkstack(L, 2))
return -1;
lua_pushnil(L);
/* check for non-integer keys */
@ -243,16 +253,54 @@ out:
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;
struct json_object *obj;
const char *key;
int i, max;
if (index < 0)
index = lua_gettop(L) + index + 1;
switch (lua_type(L, index))
{
case LUA_TTABLE:
if (visited(seen, lua_topointer(L, index)))
return NULL;
max = _lua_test_array(L, index);
if (max >= 0)
@ -262,12 +310,15 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (!obj)
return NULL;
if (!lua_checkstack(L, 1))
return NULL;
for (i = 1; i <= max; i++)
{
lua_rawgeti(L, index, i);
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);
}
@ -280,6 +331,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (!obj)
return NULL;
if (!lua_checkstack(L, 3))
return NULL;
lua_pushnil(L);
while (lua_next(L, index))
@ -289,7 +343,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (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);
}
@ -318,6 +372,23 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
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)
{
struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);