mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-31 23:32:16 +00:00
Catch out-of-bound reads and rethrow as ProtocolExceptions.
This commit is contained in:
parent
dbf7728b4f
commit
a7987585b8
@ -148,7 +148,7 @@ public class Block extends Message {
|
|||||||
hash = null;
|
hash = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseHeader() {
|
private void parseHeader() throws ProtocolException {
|
||||||
if (headerParsed)
|
if (headerParsed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ public class Block extends Message {
|
|||||||
/*
|
/*
|
||||||
* Block uses some special handling for lazy parsing and retention of cached bytes. Parsing and serializing the
|
* Block uses some special handling for lazy parsing and retention of cached bytes. Parsing and serializing the
|
||||||
* block header and the transaction list are both non-trivial so there are good efficiency gains to be had by
|
* block header and the transaction list are both non-trivial so there are good efficiency gains to be had by
|
||||||
* separating them. There are many cases where a user may need access to access or change one or the other but not both.
|
* separating them. There are many cases where a user may need to access or change one or the other but not both.
|
||||||
*
|
*
|
||||||
* With this in mind we ignore the inherited checkParse() and unCache() methods and implement a separate version
|
* With this in mind we ignore the inherited checkParse() and unCache() methods and implement a separate version
|
||||||
* of them for both header and transactions.
|
* of them for both header and transactions.
|
||||||
@ -242,9 +242,15 @@ public class Block extends Message {
|
|||||||
private void maybeParseHeader() {
|
private void maybeParseHeader() {
|
||||||
if (headerParsed || bytes == null)
|
if (headerParsed || bytes == null)
|
||||||
return;
|
return;
|
||||||
parseHeader();
|
try {
|
||||||
if (!(headerBytesValid || transactionBytesValid))
|
parseHeader();
|
||||||
bytes = null;
|
if (!(headerBytesValid || transactionBytesValid))
|
||||||
|
bytes = null;
|
||||||
|
} catch (ProtocolException e) {
|
||||||
|
throw new LazyParseException(
|
||||||
|
"ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access",
|
||||||
|
e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeParseTransactions() {
|
private void maybeParseTransactions() {
|
||||||
|
@ -402,74 +402,104 @@ public abstract class Message implements Serializable {
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
long readUint32() {
|
long readUint32() throws ProtocolException {
|
||||||
long u = Utils.readUint32(bytes, cursor);
|
try {
|
||||||
cursor += 4;
|
long u = Utils.readUint32(bytes, cursor);
|
||||||
return u;
|
cursor += 4;
|
||||||
|
return u;
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sha256Hash readHash() {
|
Sha256Hash readHash() throws ProtocolException {
|
||||||
byte[] hash = new byte[32];
|
try {
|
||||||
System.arraycopy(bytes, cursor, hash, 0, 32);
|
byte[] hash = new byte[32];
|
||||||
// We have to flip it around, as it's been read off the wire in little endian.
|
System.arraycopy(bytes, cursor, hash, 0, 32);
|
||||||
// Not the most efficient way to do this but the clearest.
|
// We have to flip it around, as it's been read off the wire in little endian.
|
||||||
hash = Utils.reverseBytes(hash);
|
// Not the most efficient way to do this but the clearest.
|
||||||
cursor += 32;
|
hash = Utils.reverseBytes(hash);
|
||||||
return new Sha256Hash(hash);
|
cursor += 32;
|
||||||
|
return new Sha256Hash(hash);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long readInt64() {
|
long readInt64() throws ProtocolException {
|
||||||
long u = Utils.readInt64(bytes, cursor);
|
try {
|
||||||
cursor += 8;
|
long u = Utils.readInt64(bytes, cursor);
|
||||||
return u;
|
cursor += 8;
|
||||||
|
return u;
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger readUint64() {
|
BigInteger readUint64() throws ProtocolException {
|
||||||
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
|
try {
|
||||||
byte[] valbytes = new byte[8];
|
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
|
||||||
System.arraycopy(bytes, cursor, valbytes, 0, 8);
|
byte[] valbytes = new byte[8];
|
||||||
valbytes = Utils.reverseBytes(valbytes);
|
System.arraycopy(bytes, cursor, valbytes, 0, 8);
|
||||||
cursor += valbytes.length;
|
valbytes = Utils.reverseBytes(valbytes);
|
||||||
return new BigInteger(valbytes);
|
cursor += valbytes.length;
|
||||||
|
return new BigInteger(valbytes);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long readVarInt() {
|
long readVarInt() throws ProtocolException {
|
||||||
return readVarInt(0);
|
return readVarInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
long readVarInt(int offset) {
|
long readVarInt(int offset) throws ProtocolException {
|
||||||
VarInt varint = new VarInt(bytes, cursor + offset);
|
try {
|
||||||
cursor += offset + varint.getOriginalSizeInBytes();
|
VarInt varint = new VarInt(bytes, cursor + offset);
|
||||||
return varint.value;
|
cursor += offset + varint.getOriginalSizeInBytes();
|
||||||
|
return varint.value;
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte[] readBytes(int length) {
|
byte[] readBytes(int length) throws ProtocolException {
|
||||||
byte[] b = new byte[length];
|
try {
|
||||||
System.arraycopy(bytes, cursor, b, 0, length);
|
byte[] b = new byte[length];
|
||||||
cursor += length;
|
System.arraycopy(bytes, cursor, b, 0, length);
|
||||||
return b;
|
cursor += length;
|
||||||
|
return b;
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] readByteArray() {
|
byte[] readByteArray() throws ProtocolException {
|
||||||
long len = readVarInt();
|
long len = readVarInt();
|
||||||
return readBytes((int)len);
|
return readBytes((int)len);
|
||||||
}
|
}
|
||||||
|
|
||||||
String readStr() {
|
String readStr() throws ProtocolException {
|
||||||
VarInt varInt = new VarInt(bytes, cursor);
|
|
||||||
if (varInt.value == 0) {
|
|
||||||
cursor += 1;
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
cursor += varInt.getOriginalSizeInBytes();
|
|
||||||
byte[] characters = new byte[(int) varInt.value];
|
|
||||||
System.arraycopy(bytes, cursor, characters, 0, characters.length);
|
|
||||||
cursor += characters.length;
|
|
||||||
try {
|
try {
|
||||||
return new String(characters, "UTF-8");
|
VarInt varInt = new VarInt(bytes, cursor);
|
||||||
} catch (UnsupportedEncodingException e) {
|
if (varInt.value == 0) {
|
||||||
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
|
cursor += 1;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
cursor += varInt.getOriginalSizeInBytes();
|
||||||
|
byte[] characters = new byte[(int) varInt.value];
|
||||||
|
System.arraycopy(bytes, cursor, characters, 0, characters.length);
|
||||||
|
cursor += characters.length;
|
||||||
|
try {
|
||||||
|
return new String(characters, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
|
||||||
|
}
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new ProtocolException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public class PeerAddress extends ChildMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parse() {
|
protected void parse() throws ProtocolException {
|
||||||
// Format of a serialized address:
|
// Format of a serialized address:
|
||||||
// uint32 timestamp
|
// uint32 timestamp
|
||||||
// uint64 services (flags determining what the node can do)
|
// uint64 services (flags determining what the node can do)
|
||||||
|
@ -54,7 +54,7 @@ public class Ping extends Message {
|
|||||||
try {
|
try {
|
||||||
nonce = readInt64();
|
nonce = readInt64();
|
||||||
hasNonce = true;
|
hasNonce = true;
|
||||||
} catch(ArrayIndexOutOfBoundsException e) {
|
} catch(ProtocolException e) {
|
||||||
hasNonce = false;
|
hasNonce = false;
|
||||||
}
|
}
|
||||||
length = hasNonce ? 8 : 0;
|
length = hasNonce ? 8 : 0;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.core;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class ProtocolException extends Exception {
|
public class ProtocolException extends VerificationException {
|
||||||
|
|
||||||
public ProtocolException(String msg) {
|
public ProtocolException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
|
@ -121,7 +121,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
|
|||||||
this.parentTransaction = parentTransaction;
|
this.parentTransaction = parentTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void parseLite() {
|
protected void parseLite() throws ProtocolException {
|
||||||
int curs = cursor;
|
int curs = cursor;
|
||||||
int scriptLen = (int) readVarInt(36);
|
int scriptLen = (int) readVarInt(36);
|
||||||
length = cursor - offset + scriptLen + 4;
|
length = cursor - offset + scriptLen + 4;
|
||||||
|
@ -121,7 +121,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
|
|||||||
return scriptPubKey;
|
return scriptPubKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void parseLite() {
|
protected void parseLite() throws ProtocolException {
|
||||||
// TODO: There is no reason to use BigInteger for values, they are always smaller than 21 million * COIN
|
// TODO: There is no reason to use BigInteger for values, they are always smaller than 21 million * COIN
|
||||||
// The only reason to use BigInteger would be to properly read values from the reference implementation, however
|
// The only reason to use BigInteger would be to properly read values from the reference implementation, however
|
||||||
// the reference implementation uses signed 64-bit integers for its values as well (though it probably shouldn't)
|
// the reference implementation uses signed 64-bit integers for its values as well (though it probably shouldn't)
|
||||||
|
@ -22,6 +22,10 @@ public class VerificationException extends Exception {
|
|||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VerificationException(Exception e) {
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
public VerificationException(String msg, Throwable t) {
|
public VerificationException(String msg, Throwable t) {
|
||||||
super(msg, t);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user