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_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);
|
||||
|
|
Loading…
Reference in a new issue