Package: libjson-c2
Version: 0.11-4
Severity: normal
Tags: upstream patch

Dear Maintainer,

inputs or values beginning with a numeral could get partly parsed,
resulting in truncated output instead of raising an error.

Examples:
 '1.2.3'      -> (double)1.2
 '2015-03-09' -> (int)2015

This problem is quite severe for the php5-json package which
is the default JSON extension in Debian for licence reasons.
vanilla PHP:
 var_dump(json_decode('2015-01-01')); // Null
Debian php5-json:
 var_dump(json_decode('2015-01-01')); // (int)2015

This issue has been reported and a patch has been accepted upstream :
https://github.com/json-c/json-c/commit/99d8fc975e059a5e1749d4dc6c07a02e9a629921

Please find attached an attempt to port the patch to the version
available in Jessie (core code untouched but tests simplified).

Thanks !


-- System Information:
Debian Release: 8.0
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.32 (SMP w/4 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: sysvinit (via /sbin/init)

Versions of packages libjson-c2 depends on:
ii  libc6              2.19-15
ii  multiarch-support  2.19-15

libjson-c2 recommends no packages.

libjson-c2 suggests no packages.

-- no debconf information
Description: fix integer-starting input truncation. Ex: '2015-01-01' -> (int)2015
 Some badly formated "numbers" could get partly parsed,
 resulting in truncated results instead of raising an
 error.

 Examples :
  '1.2.3'      -> (double)1.2
  '2015-01-15' -> (int)2015

 This patch is not perfect (ex: input can still end with a 'E', which
 is forbidden by json.org doc) but should avoid non-sensically
 formated input.

Origin: upstream, https://github.com/json-c/json-c/commit/99d8fc975e059a5e1749d4dc6c07a02e9a629921
Last-Update: 2015-03-06

--- json-c-0.11.orig/json_tokener.c
+++ json-c-0.11/json_tokener.c
@@ -611,10 +611,45 @@ struct json_object* json_tokener_parse_e
 	/* Advance until we change state */
 	const char *case_start = str;
 	int case_len=0;
+	int is_exponent=0;
+	int negativesign_next_possible_location=1;
 	while(c && strchr(json_number_chars, c)) {
 	  ++case_len;
-	  if(c == '.' || c == 'e' || c == 'E')
+
+	  /* non-digit characters checks */
+	  /* note: since the main loop condition to get here was
+	           an input starting with 0-9 or '-', we are
+	           protected from input starting with '.' or
+	           e/E. */
+	  if (c == '.') {
+	    if (tok->is_double != 0) {
+	      /* '.' can only be found once, and out of the exponent part.
+	         Thus, if the input is already flagged as double, it
+	         is invalid. */
+	      tok->err = json_tokener_error_parse_number;
+	      goto out;
+	    }
 	    tok->is_double = 1;
+	  }
+	  if (c == 'e' || c == 'E') {
+	    if (is_exponent != 0) {
+	      /* only one exponent possible */
+	      tok->err = json_tokener_error_parse_number;
+	      goto out;
+	    }
+	    is_exponent = 1;
+	    tok->is_double = 1;
+	    /* the exponent part can begin with a negative sign */
+	    negativesign_next_possible_location = case_len + 1;
+	  }
+	  if (c == '-' && case_len != negativesign_next_possible_location) {
+	    /* If the negative sign is not where expected (ie
+	       start of input or start of exponent part), the
+	       input is invalid. */
+	    tok->err = json_tokener_error_parse_number;
+	    goto out;
+	  }
+
 	  if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) {
 	    printbuf_memappend_fast(tok->pb, case_start, case_len);
 	    goto out;
--- json-c-0.11.orig/tests/test_parse.c
+++ json-c-0.11/tests/test_parse.c
@@ -59,6 +59,19 @@ static void test_basic_parse()
 	printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
 	json_object_put(new_obj);
 
+	new_obj = json_tokener_parse("12.3.4"); /* non-sensical, returns null */
+	printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
+	json_object_put(new_obj);
+
+	/* was returning (int)2015 before patch, should return null */
+	new_obj = json_tokener_parse("2015-01-15");
+	printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
+	json_object_put(new_obj);
+
+	new_obj = json_tokener_parse("{\"FoO\"  :   -12.3E51.2}"); /* non-sensical, returns null */
+	printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
+	json_object_put(new_obj);
+
 	new_obj = json_tokener_parse("[\"\\n\"]");
 	printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
 	json_object_put(new_obj);
@@ -163,6 +180,9 @@ struct incremental_step {
 	{ "1",                 1, 1, json_tokener_continue, 0 },
 	{ "2",                 2, 1, json_tokener_success, 0 },
 
+	/* Some bad formatting. Check we get the correct error status */
+	{ "2015-01-15",       10, 4, json_tokener_error_parse_number, 1 },
+
 	/* Strings have a well defined end point, so we can stop at the quote */
 	{ "\"blue\"",         -1, -1, json_tokener_success, 0 },
 
--- json-c-0.11.orig/tests/test_parse.expected
+++ json-c-0.11/tests/test_parse.expected
@@ -14,6 +14,9 @@ new_obj.to_string()=-Infinity
 new_obj.to_string()=true
 new_obj.to_string()=12
 new_obj.to_string()=12.300000
+new_obj.to_string()=null
+new_obj.to_string()=null
+new_obj.to_string()=null
 new_obj.to_string()=[ "\n" ]
 new_obj.to_string()=[ "\nabc\n" ]
 new_obj.to_string()=[ null ]
@@ -40,6 +40,7 @@ json_tokener_parse_ex(tok, {"x": 123 }"X
 json_tokener_parse_ex(tok, "Y"         ,   3) ... OK: got object of type [string]: "Y"
 json_tokener_parse_ex(tok, 1           ,   1) ... OK: got correct error: continue
 json_tokener_parse_ex(tok, 2           ,   2) ... OK: got object of type [int]: 12
+json_tokener_parse_ex(tok, 2015-01-15  ,  10) ... OK: got correct error: number expected
 json_tokener_parse_ex(tok, "blue"      ,   6) ... OK: got object of type [string]: "blue"
 json_tokener_parse_ex(tok, "\""        ,   4) ... OK: got object of type [string]: "\""
 json_tokener_parse_ex(tok, "\\"        ,   4) ... OK: got object of type [string]: "\\"
@@ -53,5 +54,5 @@ json_tokener_parse_ex(tok, [1,2,3,]    ,
 json_tokener_parse_ex(tok, [1,2,,3,]   ,   9) ... OK: got correct error: unexpected character
 json_tokener_parse_ex(tok, [1,2,3,]    ,   8) ... OK: got correct error: unexpected character
 json_tokener_parse_ex(tok, {"a":1,}    ,   8) ... OK: got correct error: unexpected character
-End Incremental Tests OK=29 ERROR=0
+End Incremental Tests OK=30 ERROR=0
 ==================================

Reply via email to