From: Keith Derrick Date: Tue, 1 Oct 2013 16:18:51 +0000 (-0700) Subject: Avoid potential overflow in json_object_get_double X-Git-Tag: json-c-0.12-20140410~18^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F109%2Fhead;p=thirdparty%2Fjson-c.git Avoid potential overflow in json_object_get_double sscanf is always a potential problem when converting numeric values as it does not correctly handle over- and underflow (or at least gives no indication that it has done so). This change converts json_object_get_double() to use strtod() according to CERT guidelines. --- diff --git a/json_object.c b/json_object.c index faf61930..377ab596 100644 --- a/json_object.c +++ b/json_object.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "debug.h" #include "printbuf.h" @@ -636,6 +637,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(struct json_object *jso) { double cdouble; + char *errPtr = NULL; if(!jso) return 0.0; switch(jso->o_type) { @@ -646,7 +648,36 @@ double json_object_get_double(struct json_object *jso) case json_type_boolean: return jso->o.c_boolean; case json_type_string: - if(sscanf(jso->o.c_string.str, "%lf", &cdouble) == 1) return cdouble; + errno = 0; + cdouble = strtod(jso->o.c_string.str,&errPtr); + + /* if conversion stopped at the first character, return 0.0 */ + if (errPtr == jso->o.c_string.str) + return 0.0; + + /* + * Check that the conversion terminated on something sensible + * + * For example, { "pay" : 123AB } would parse as 123. + */ + if (*errPtr != '\0') + return 0.0; + + /* + * If strtod encounters a string which would exceed the + * capacity of a double, it returns +/- HUGE_VAL and sets + * errno to ERANGE. But +/- HUGE_VAL is also a valid result + * from a conversion, so we need to check errno. + * + * Underflow also sets errno to ERANGE, but it returns 0 in + * that case, which is what we will return anyway. + * + * See CERT guideline ERR30-C + */ + if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && + (ERANGE == errno)) + cdouble = 0.0; + return cdouble; default: return 0.0; }