diff --git a/core/src/main/java/com/google/bitcoin/core/Message.java b/core/src/main/java/com/google/bitcoin/core/Message.java index c1a37ec6..0076e52c 100644 --- a/core/src/main/java/com/google/bitcoin/core/Message.java +++ b/core/src/main/java/com/google/bitcoin/core/Message.java @@ -458,8 +458,10 @@ public abstract class Message implements Serializable { } } - byte[] readBytes(int length) throws ProtocolException { + if (length > MAX_SIZE) { + throw new ProtocolException("Claimed byte array length too large: " + length); + } try { byte[] b = new byte[length]; System.arraycopy(payload, cursor, b, 0, length); @@ -483,6 +485,9 @@ public abstract class Message implements Serializable { return ""; } cursor += varInt.getOriginalSizeInBytes(); + if (varInt.value > MAX_SIZE) { + throw new ProtocolException("Claimed var_str length too large: " + varInt.value); + } byte[] characters = new byte[(int) varInt.value]; System.arraycopy(payload, cursor, characters, 0, characters.length); cursor += characters.length; diff --git a/core/src/test/java/com/google/bitcoin/core/MessageTest.java b/core/src/test/java/com/google/bitcoin/core/MessageTest.java new file mode 100644 index 00000000..812a4fa7 --- /dev/null +++ b/core/src/test/java/com/google/bitcoin/core/MessageTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 Piotr WĹ‚odarek + * + * Licensed 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 com.google.bitcoin.core; + +import com.google.bitcoin.params.UnitTestParams; +import org.junit.Test; + +public class MessageTest { + + // If readStr() is vulnerable this causes OutOfMemory + @Test(expected = ProtocolException.class) + public void readStrOfExtremeLength() throws Exception { + NetworkParameters params = UnitTestParams.get(); + VarInt length = new VarInt(Integer.MAX_VALUE); + byte[] payload = length.encode(); + new VarStrMessage(params, payload); + } + + static class VarStrMessage extends Message { + public VarStrMessage(NetworkParameters params, byte[] payload) { + super(params, payload, 0); + } + + @Override + void parse() throws ProtocolException { + readStr(); + } + + @Override + protected void parseLite() throws ProtocolException {} + } + + // If readBytes() is vulnerable this causes OutOfMemory + @Test(expected = ProtocolException.class) + public void readByteArrayOfExtremeLength() throws Exception { + NetworkParameters params = UnitTestParams.get(); + VarInt length = new VarInt(Integer.MAX_VALUE); + byte[] payload = length.encode(); + new VarBytesMessage(params, payload); + } + + static class VarBytesMessage extends Message { + public VarBytesMessage(NetworkParameters params, byte[] payload) { + super(params, payload, 0); + } + + @Override + void parse() throws ProtocolException { + readByteArray(); + } + + @Override + protected void parseLite() throws ProtocolException {} + } + +}