From 6c2d4029f1fecb51e0b002e652fd18e18d059fe0 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 20 Jul 2009 01:45:48 -0500 Subject: Time.parse3339 range checking and proper 'sec-frac' skip The parse3339 JNI code doesn't properly do bounds checking on the input String. These changes do some bounds checking to prevent a buffer underflow condition. parse3339 should allow the fractional seconds to be optional and an arbitrary length as specified in RFC 3339. This will scan through arbitrary precision until it finds the timezone indicators. Change-Id: Ie9d01d0b24163d893c58c747d37873c83b74e6c7 --- core/jni/android_text_format_Time.cpp | 46 ++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'core/jni') diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp index fde6ca6..d89a7e6 100644 --- a/core/jni/android_text_format_Time.cpp +++ b/core/jni/android_text_format_Time.cpp @@ -382,7 +382,7 @@ static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected) jchar c = s[spos]; if (c != expected) { char msg[100]; - sprintf(msg, "Unexpected %c at pos=%d. Expected %c.", c, spos, + sprintf(msg, "Unexpected character 0x%02x at pos=%d. Expected %c.", c, spos, expected); jniThrowException(env, "android/util/TimeFormatException", msg); return false; @@ -483,6 +483,12 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, int n; jboolean inUtc = false; + if (len < 10) { + jniThrowException(env, "android/util/TimeFormatException", + "Time input is too short; must be at least 10 characters"); + return false; + } + // year n = get_char(env, s, 0, 1000, &thrown); n += get_char(env, s, 1, 100, &thrown); @@ -510,7 +516,7 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, if (thrown) return false; env->SetIntField(This, g_mdayField, n); - if (len >= 17) { + if (len >= 19) { // T if (!check_char(env, s, 10, 'T')) return false; @@ -541,10 +547,19 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, if (thrown) return false; env->SetIntField(This, g_secField, n); - // skip the '.XYZ' -- we don't care about subsecond precision. + // skip the '.XYZ' -- we don't care about subsecond precision. + int tz_index = 19; + if (tz_index < len && s[tz_index] == '.') { + do { + tz_index++; + } while (tz_index < len + && s[tz_index] >= '0' + && s[tz_index] <= '9'); + } + int offset = 0; - if (len >= 23) { - char c = s[23]; + if (len > tz_index) { + char c = s[tz_index]; // NOTE: the offset is meant to be subtracted to get from local time // to UTC. we therefore use 1 for '-' and -1 for '+'. @@ -561,27 +576,34 @@ static jboolean android_text_format_Time_parse3339(JNIEnv* env, break; default: char msg[100]; - sprintf(msg, "Unexpected %c at position 19. Expected + or -", - c); + sprintf(msg, "Unexpected character 0x%02x at position %d. Expected + or -", + c, tz_index); jniThrowException(env, "android/util/TimeFormatException", msg); return false; } inUtc = true; if (offset != 0) { + if (len < tz_index + 5) { + char msg[100]; + sprintf(msg, "Unexpected length; should be %d characters", tz_index + 5); + jniThrowException(env, "android/util/TimeFormatException", msg); + return false; + } + // hour - n = get_char(env, s, 24, 10, &thrown); - n += get_char(env, s, 25, 1, &thrown); + n = get_char(env, s, tz_index + 1, 10, &thrown); + n += get_char(env, s, tz_index + 2, 1, &thrown); if (thrown) return false; n *= offset; hour += n; // : - if (!check_char(env, s, 26, ':')) return false; + if (!check_char(env, s, tz_index + 3, ':')) return false; // minute - n = get_char(env, s, 27, 10, &thrown); - n += get_char(env, s, 28, 1, &thrown); + n = get_char(env, s, tz_index + 4, 10, &thrown); + n += get_char(env, s, tz_index + 5, 1, &thrown); if (thrown) return false; n *= offset; minute += n; -- cgit v1.1