From fffd63a3bd3a5475379b7c074820a5463b7663b3 Mon Sep 17 00:00:00 2001 From: Mark Emlyn David Thomas Date: Tue, 18 Mar 2014 10:27:31 +0000 Subject: [PATCH] Fix possible overflow when parsing long values from a byte array. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1578812 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/tomcat/util/buf/Ascii.java | 18 ++--- .../org/apache/tomcat/util/buf/TestAscii.java | 65 +++++++++++++++++++ webapps/docs/changelog.xml | 4 ++ 3 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 test/org/apache/tomcat/util/buf/TestAscii.java diff --git a/java/org/apache/tomcat/util/buf/Ascii.java b/java/org/apache/tomcat/util/buf/Ascii.java index fbae9313f822..cc3135c855ee 100644 --- a/java/org/apache/tomcat/util/buf/Ascii.java +++ b/java/org/apache/tomcat/util/buf/Ascii.java @@ -33,10 +33,11 @@ public final class Ascii { */ private static final boolean[] isDigit = new boolean[256]; + private static final long OVERFLOW_LIMIT = Long.MAX_VALUE / 10; + /* * Initialize character translation and type tables. */ - static { for (int i = 0; i < 256; i++) { toLower[i] = (byte)i; @@ -85,19 +86,12 @@ public static long parseLong(byte[] b, int off, int len) } long n = c - '0'; - long m; - while (--len > 0) { - if (!isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - m = n * 10 + c - '0'; - - if (m < n) { - // Overflow - throw new NumberFormatException(); + if (isDigit(c = b[off++]) && + (n < OVERFLOW_LIMIT || (n == OVERFLOW_LIMIT && (c - '0') < 8))) { + n = n * 10 + c - '0'; } else { - n = m; + throw new NumberFormatException(); } } diff --git a/test/org/apache/tomcat/util/buf/TestAscii.java b/test/org/apache/tomcat/util/buf/TestAscii.java new file mode 100644 index 000000000000..25cc260eb141 --- /dev/null +++ b/test/org/apache/tomcat/util/buf/TestAscii.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.buf; + +import java.math.BigInteger; + +import org.junit.Assert; +import org.junit.Test; + +public class TestAscii { + + @Test + public void testParseLong1() { + String value = "9223372036854775807"; // Long.MAX_VALUE + byte[] bytes = value.getBytes(); + long result = Ascii.parseLong(bytes, 0, bytes.length); + Assert.assertEquals(value, String.valueOf(result)); + } + + @Test(expected = NumberFormatException.class) + public void testParseLong2() { + byte[] bytes = "9223372036854775808".getBytes(); // Long.MAX_VALUE + 1 + long result = Ascii.parseLong(bytes, 0, bytes.length); + Assert.fail("NumberFormatException expected, got: " + result); + } + + @Test(expected = NumberFormatException.class) + public void testParseLong3() { + byte[] bytes = "9223372036854775810".getBytes(); // Long.MAX_VALUE + 3 + long result = Ascii.parseLong(bytes, 0, bytes.length); + Assert.fail("NumberFormatException expected, got: " + result); + } + + @Test(expected = NumberFormatException.class) + public void testParseLong4() { + BigInteger x = BigInteger.valueOf(5000000000L).shiftLeft(32); + byte[] bytes = String.valueOf(x).getBytes(); + long result = Ascii.parseLong(bytes, 0, bytes.length); + Assert.fail("NumberFormatException expected, got: " + result); + } + + @Test + public void testParseLong5() { + String value = "9223372036854775806"; // Long.MAX_VALUE - 1 + byte[] bytes = value.getBytes(); + long result = Ascii.parseLong(bytes, 0, bytes.length); + Assert.assertEquals(value, String.valueOf(result)); + } + + +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index e4ec3b9dc420..59a1f64cfb17 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -165,6 +165,10 @@ non-blocking IO support that broke handling of requests with an explicit content length of zero. (markt/kkolinko) + + Fix possible overflow when parsing long values from a byte array. + (markt) +