Browse Source

Fix frozen buffer overflow

Resolves https://github.com/cesanta/frozen/issues/14

A better solution would be to allocate buffer from the heap if
necessary, but it's TODO.

PUBLISHED_FROM=3afba5b216dc101b258f677993c464be42c5e717
Dmitry Frank 8 years ago
parent
commit
76c3c442b2
2 changed files with 29 additions and 5 deletions
  1. 7 5
      frozen.c
  2. 22 0
      unit_test.c

+ 7 - 5
frozen.c

@@ -85,14 +85,14 @@ struct frozen {
 
 
   /* For callback API */
   /* For callback API */
   char path[JSON_MAX_PATH_LEN];
   char path[JSON_MAX_PATH_LEN];
-  int path_len;
+  size_t path_len;
   void *callback_data;
   void *callback_data;
   json_walk_callback_t callback;
   json_walk_callback_t callback;
 };
 };
 
 
 struct fstate {
 struct fstate {
   const char *ptr;
   const char *ptr;
-  int path_len;
+  size_t path_len;
 };
 };
 
 
 #define SET_STATE(fr, ptr, str, len)              \
 #define SET_STATE(fr, ptr, str, len)              \
@@ -118,13 +118,15 @@ struct fstate {
 static int append_to_path(struct frozen *f, const char *str, int size) {
 static int append_to_path(struct frozen *f, const char *str, int size) {
   int n = f->path_len;
   int n = f->path_len;
   f->path_len +=
   f->path_len +=
-      snprintf(f->path + f->path_len, sizeof(f->path) - (f->path_len + 1),
-               "%.*s", size, str);
+      snprintf(f->path + f->path_len, sizeof(f->path) - (f->path_len), "%.*s", size, str);
+  if (f->path_len > sizeof(f->path) - 1) {
+    f->path_len = sizeof(f->path) - 1;
+  }
 
 
   return n;
   return n;
 }
 }
 
 
-static void truncate_path(struct frozen *f, int len) {
+static void truncate_path(struct frozen *f, size_t len) {
   f->path_len = len;
   f->path_len = len;
   f->path[len] = '\0';
   f->path[len] = '\0';
 }
 }

+ 22 - 0
unit_test.c

@@ -389,6 +389,27 @@ static const char *test_callback_api(void) {
   return NULL;
   return NULL;
 }
 }
 
 
+/*
+ * Tests with the path which is longer than JSON_MAX_PATH_LEN (at the moment, 60)
+ */
+static const char *test_callback_api_long_path(void) {
+  const char *s =
+    "{\"MyWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZvf\": {}, \"jYP-27917287424p\": {}}";
+
+  const char *result =
+    "name:'<null>', path:'', type:OBJECT_START, val:'<null>'\n"
+    "name:'MyWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZvf', path:'.MyWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', type:OBJECT_START, val:'<null>'\n"
+    "name:'<null>', path:'.MyWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', type:OBJECT_END, val:'{}'\n"
+    "name:'jYP-27917287424p', path:'.jYP-27917287424p', type:OBJECT_START, val:'<null>'\n"
+    "name:'<null>', path:'.jYP-27917287424p', type:OBJECT_END, val:'{}'\n"
+    "name:'<null>', path:'', type:OBJECT_END, val:'{\"MyWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZvf\": {}, \"jYP-27917287424p\": {}}'\n";
+
+  char buf[4096] = "";
+  ASSERT(json_walk(s, strlen(s), cb, buf) == (int) strlen(s));
+  ASSERT(strcmp(buf, result) == 0);
+  return NULL;
+}
+
 static void scan_array(const char *str, int len, void *user_data) {
 static void scan_array(const char *str, int len, void *user_data) {
   struct json_token t;
   struct json_token t;
   int i;
   int i;
@@ -543,6 +564,7 @@ static const char *run_all_tests(void) {
   RUN_TEST(test_json_printf);
   RUN_TEST(test_json_printf);
   RUN_TEST(test_system);
   RUN_TEST(test_system);
   RUN_TEST(test_callback_api);
   RUN_TEST(test_callback_api);
+  RUN_TEST(test_callback_api_long_path);
   RUN_TEST(test_json_unescape);
   RUN_TEST(test_json_unescape);
   return NULL;
   return NULL;
 }
 }