Skip to content

Commit

Permalink
Fix an overflow issue in 4 byte to unsigned integer conversion (neede…
Browse files Browse the repository at this point in the history
…d to be a long).

Fix a related TODO in ConnectionSettings

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1682984 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Jun 1, 2015
1 parent dbc805e commit 50cb94a
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 25 deletions.
4 changes: 2 additions & 2 deletions java/org/apache/coyote/http2/ByteUtil.java
Expand Up @@ -68,8 +68,8 @@ public static void setThreeBytes(byte[] output, int firstByte, int value) {
} }




public static int getFourBytes(byte[] input, int firstByte) { public static long getFourBytes(byte[] input, int firstByte) {
return ((input[firstByte] & 0xFF) << 24) + ((input[firstByte + 1] & 0xFF) << 16) + return ((long)(input[firstByte] & 0xFF) << 24) + ((input[firstByte + 1] & 0xFF) << 16) +
((input[firstByte + 2] & 0xFF) << 8) + (input[firstByte + 3] & 0xFF); ((input[firstByte + 2] & 0xFF) << 8) + (input[firstByte + 3] & 0xFF);
} }
} }
46 changes: 25 additions & 21 deletions java/org/apache/coyote/http2/ConnectionSettings.java
Expand Up @@ -28,20 +28,19 @@ public class ConnectionSettings {
private final StringManager sm = StringManager.getManager(ConnectionSettings.class); private final StringManager sm = StringManager.getManager(ConnectionSettings.class);


public static final int DEFAULT_WINDOW_SIZE = (1 << 16) - 1; public static final int DEFAULT_WINDOW_SIZE = (1 << 16) - 1;
// TODO: The maximum allowed in a settings frame as 2^32 (unsigned) private static final long UNLIMITED = ((long)1 << 32); // Use the maximum possible
private static final int UNLIMITED = (1 << 31) -1; // Use the maximum possible
private static final int MAX_WINDOW_SIZE = (1 << 31) - 1; private static final int MAX_WINDOW_SIZE = (1 << 31) - 1;
private static final int MIN_MAX_FRAME_SIZE = 1 << 14; private static final int MIN_MAX_FRAME_SIZE = 1 << 14;
private static final int MAX_MAX_FRAME_SIZE = (1 << 24) - 1; private static final int MAX_MAX_FRAME_SIZE = (1 << 24) - 1;


private volatile int headerTableSize = 4096; private volatile int headerTableSize = 4096;
private volatile int enablePush = 1; private volatile boolean enablePush = true;
private volatile int maxConcurrentStreams = UNLIMITED; private volatile long maxConcurrentStreams = UNLIMITED;
private volatile int initialWindowSize = DEFAULT_WINDOW_SIZE; private volatile int initialWindowSize = DEFAULT_WINDOW_SIZE;
private volatile int maxFrameSize = MIN_MAX_FRAME_SIZE; private volatile int maxFrameSize = MIN_MAX_FRAME_SIZE;
private volatile int maxHeaderListSize = UNLIMITED; private volatile long maxHeaderListSize = UNLIMITED;


public void set(int parameterId, int value) throws IOException { public void set(int parameterId, long value) throws IOException {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug(sm.getString("connectionSettings.debug", log.debug(sm.getString("connectionSettings.debug",
Integer.toString(parameterId), Long.toString(value))); Integer.toString(parameterId), Long.toString(value)));
Expand Down Expand Up @@ -77,63 +76,68 @@ public void set(int parameterId, int value) throws IOException {
public int getHeaderTableSize() { public int getHeaderTableSize() {
return headerTableSize; return headerTableSize;
} }
public void setHeaderTableSize(int headerTableSize) { public void setHeaderTableSize(long headerTableSize) throws IOException {
this.headerTableSize = headerTableSize; // Need to put a sensible limit on this. Start with 16k (default is 4k)
if (headerTableSize > (16 * 1024)) {
throw new Http2Exception(sm.getString("connectionSettings.headerTableSizeLimit",
Long.toString(headerTableSize)), 0, Http2Exception.PROTOCOL_ERROR);
}
this.headerTableSize = (int) headerTableSize;
} }




public int getEnablePush() { public boolean getEnablePush() {
return enablePush; return enablePush;
} }
public void setEnablePush(int enablePush) throws IOException { public void setEnablePush(long enablePush) throws IOException {
// Can't be less than zero since the result of the byte->long conversion // Can't be less than zero since the result of the byte->long conversion
// will never be negative // will never be negative
if (enablePush > 1) { if (enablePush > 1) {
throw new Http2Exception(sm.getString("connectionSettings.enablePushInvalid", throw new Http2Exception(sm.getString("connectionSettings.enablePushInvalid",
Long.toString(enablePush)), 0, Http2Exception.PROTOCOL_ERROR); Long.toString(enablePush)), 0, Http2Exception.PROTOCOL_ERROR);
} }
this.enablePush = enablePush; this.enablePush = (enablePush == 1);
} }




public int getMaxConcurrentStreams() { public long getMaxConcurrentStreams() {
return maxConcurrentStreams; return maxConcurrentStreams;
} }
public void setMaxConcurrentStreams(int maxConcurrentStreams) { public void setMaxConcurrentStreams(long maxConcurrentStreams) {
this.maxConcurrentStreams = maxConcurrentStreams; this.maxConcurrentStreams = maxConcurrentStreams;
} }




public int getInitialWindowSize() { public int getInitialWindowSize() {
return initialWindowSize; return initialWindowSize;
} }
public void setInitialWindowSize(int initialWindowSize) throws IOException { public void setInitialWindowSize(long initialWindowSize) throws IOException {
if (initialWindowSize > MAX_WINDOW_SIZE) { if (initialWindowSize > MAX_WINDOW_SIZE) {
throw new Http2Exception(sm.getString("connectionSettings.windowSizeTooBig", throw new Http2Exception(sm.getString("connectionSettings.windowSizeTooBig",
Long.toString(initialWindowSize), Long.toString(MAX_WINDOW_SIZE)), Long.toString(initialWindowSize), Long.toString(MAX_WINDOW_SIZE)),
0, Http2Exception.PROTOCOL_ERROR); 0, Http2Exception.PROTOCOL_ERROR);
} }
this.initialWindowSize = initialWindowSize; this.initialWindowSize = (int) initialWindowSize;
} }




public int getMaxFrameSize() { public int getMaxFrameSize() {
return maxFrameSize; return maxFrameSize;
} }
public void setMaxFrameSize(int maxFrameSize) throws IOException { public void setMaxFrameSize(long maxFrameSize) throws IOException {
if (maxFrameSize < MIN_MAX_FRAME_SIZE || maxFrameSize > MAX_MAX_FRAME_SIZE) { if (maxFrameSize < MIN_MAX_FRAME_SIZE || maxFrameSize > MAX_MAX_FRAME_SIZE) {
throw new Http2Exception(sm.getString("connectionSettings.maxFrameSizeInvalid", throw new Http2Exception(sm.getString("connectionSettings.maxFrameSizeInvalid",
Long.toString(maxFrameSize), Long.toString(MIN_MAX_FRAME_SIZE), Long.toString(maxFrameSize), Integer.toString(MIN_MAX_FRAME_SIZE),
Long.toString(MAX_MAX_FRAME_SIZE)), 0, Http2Exception.PROTOCOL_ERROR); Integer.toString(MAX_MAX_FRAME_SIZE)), 0, Http2Exception.PROTOCOL_ERROR);
} }
this.maxFrameSize = maxFrameSize; this.maxFrameSize = (int) maxFrameSize;
} }




public int getMaxHeaderListSize() { public long getMaxHeaderListSize() {
return maxHeaderListSize; return maxHeaderListSize;
} }
public void setMaxHeaderListSize(int maxHeaderListSize) { public void setMaxHeaderListSize(long maxHeaderListSize) {
this.maxHeaderListSize = maxHeaderListSize; this.maxHeaderListSize = maxHeaderListSize;
} }
} }
4 changes: 2 additions & 2 deletions java/org/apache/coyote/http2/Http2UpgradeHandler.java
Expand Up @@ -184,7 +184,7 @@ public void init(WebConnection webConnection) {


for (int i = 0; i < settings.length % 6; i++) { for (int i = 0; i < settings.length % 6; i++) {
int id = ByteUtil.getTwoBytes(settings, i * 6); int id = ByteUtil.getTwoBytes(settings, i * 6);
int value = ByteUtil.getFourBytes(settings, (i * 6) + 2); long value = ByteUtil.getFourBytes(settings, (i * 6) + 2);
remoteSettings.set(id, value); remoteSettings.set(id, value);
} }


Expand Down Expand Up @@ -568,7 +568,7 @@ private void processFrameSettings(int flags, int streamId, int payloadSize) thro
for (int i = 0; i < payloadSize / 6; i++) { for (int i = 0; i < payloadSize / 6; i++) {
readFully(setting); readFully(setting);
int id = ByteUtil.getTwoBytes(setting, 0); int id = ByteUtil.getTwoBytes(setting, 0);
int value = ByteUtil.getFourBytes(setting, 2); long value = ByteUtil.getFourBytes(setting, 2);
remoteSettings.set(id, value); remoteSettings.set(id, value);
} }
} }
Expand Down
1 change: 1 addition & 0 deletions java/org/apache/coyote/http2/LocalStrings.properties
Expand Up @@ -21,6 +21,7 @@ connectionPrefaceParser.mismatch=An unexpected byte sequence was received at the


connectionSettings.debug=Parameter type [{0}] set to [{1}] connectionSettings.debug=Parameter type [{0}] set to [{1}]
connectionSettings.enablePushInvalid=The requested value for enable push [{0}] is not one of the permitted values (zero or one) connectionSettings.enablePushInvalid=The requested value for enable push [{0}] is not one of the permitted values (zero or one)
connectionSettings.headerTableSizeLimit=Attempted to set a header table size of [{0}] but the limit is 16k
connectionSettings.maxFrameSizeInvalid=The requested maximum frame size of [{0}] is ouside the permitted range of [{1}] to [{2}] connectionSettings.maxFrameSizeInvalid=The requested maximum frame size of [{0}] is ouside the permitted range of [{1}] to [{2}]
connectionSettings.unknown=An unknown setting with identifier [{0}] and value [{1}] was ignored connectionSettings.unknown=An unknown setting with identifier [{0}] and value [{1}] was ignored
connectionSettings.windowSizeTooBig=The requested window size of [{0}] is bigger than the maximum permitted value of [{1}] connectionSettings.windowSizeTooBig=The requested window size of [{0}] is bigger than the maximum permitted value of [{1}]
Expand Down
39 changes: 39 additions & 0 deletions test/org/apache/coyote/http2/TestByteUtil.java
@@ -0,0 +1,39 @@
/*
* 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.coyote.http2;

import org.junit.Assert;
import org.junit.Test;

public class TestByteUtil {

@Test
public void testGet31Bits() {
byte[] input = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
int result = ByteUtil.get31Bits(input, 0);
Assert.assertEquals(0x7fffffff, result);
}


@Test
public void testGetFourBytes() {
byte[] input = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
long result = ByteUtil.getFourBytes(input, 0);
Assert.assertEquals(0xffffffffL, result);
}

}

0 comments on commit 50cb94a

Please sign in to comment.