diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 07dda2cdd..45f9c3b1d 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -185,6 +185,8 @@ public class DatabaseStoreMessage extends FastI2NPMessageImpl { // If we do delay it, getEntry() will have to check if _dbEntry is null and _byteCache // is non-null, and then decompress. byte decompressed[] = DataHelper.decompress(data, curIndex, compressedSize); + if (decompressed.length > RouterInfo.MAX_UNCOMPRESSED_SIZE) + throw new I2NPMessageException("RI too big: " + decompressed.length); _dbEntry.readBytes(new ByteArrayInputStream(decompressed)); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error reading the routerInfo", dfe); diff --git a/router/java/src/net/i2p/data/router/RouterInfo.java b/router/java/src/net/i2p/data/router/RouterInfo.java index b2fd039fa..d8dae8d64 100644 --- a/router/java/src/net/i2p/data/router/RouterInfo.java +++ b/router/java/src/net/i2p/data/router/RouterInfo.java @@ -87,6 +87,15 @@ public class RouterInfo extends DatabaseEntry { public static final char CAPABILITY_HIDDEN = 'H'; private static final int MAX_ADDRESSES = 16; + /** + * All legit RIs are currently under 2KB. + * May need to be adjusted if we add a huge new enctype or sigtype. + * Enforced in DatabaseStoreMessage, the transports, and reseed. + * + * @since 0.9.62 + */ + public static final int MAX_UNCOMPRESSED_SIZE = 4*1024; + /** Public string of chars which serve as bandwidth capacity markers * NOTE: individual chars defined in Router.java */ diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java index 6a9655cf5..014fd6af7 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java @@ -541,6 +541,12 @@ public class PersistentDataStore extends TransientDataStore { * @since 0.9.58 */ public boolean read() { + if (_routerFile.length() > RouterInfo.MAX_UNCOMPRESSED_SIZE) { + if (_log.shouldWarn()) + _log.warn("RI file too big " + _routerFile.length() + ": " + _routerFile); + _routerFile.delete(); + return false; + } if (!shouldRead()) return false; if (_log.shouldLog(Log.DEBUG)) _log.debug("Reading " + _routerFile); diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index 73f431e94..46beb2371 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -24,6 +24,7 @@ import net.i2p.crypto.SU3File; import net.i2p.data.Base64; import net.i2p.data.DataHelper; import net.i2p.data.Hash; +import net.i2p.data.router.RouterInfo; import net.i2p.router.RouterClock; import net.i2p.router.RouterContext; import net.i2p.router.util.EventLog; @@ -911,7 +912,7 @@ public class Reseeder { String name = f.getName(); if (name.length() != ROUTERINFO_PREFIX.length() + 44 + ROUTERINFO_SUFFIX.length() || name.equals(ourB64) || - f.length() > 10*1024 || + f.length() > RouterInfo.MAX_UNCOMPRESSED_SIZE || f.lastModified() < minTime || !name.startsWith(ROUTERINFO_PREFIX) || !name.endsWith(ROUTERINFO_SUFFIX) || diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCP2Payload.java b/router/java/src/net/i2p/router/transport/ntcp/NTCP2Payload.java index d771006e4..e1fda3180 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCP2Payload.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCP2Payload.java @@ -117,10 +117,12 @@ class NTCP2Payload { case BLOCK_ROUTERINFO: int flag = payload[i] & 0xff; + if (len - 1 > RouterInfo.MAX_UNCOMPRESSED_SIZE) + throw new DataFormatException("RI too big: " + (len - 1)); RouterInfo alice = new RouterInfo(); ByteArrayInputStream bais = new ByteArrayInputStream(payload, i + 1, len - 1); alice.readBytes(bais, true); - cb.gotRI(alice, isHandshake, (flag & 0x01) != 0 && len < 4*1024); + cb.gotRI(alice, isHandshake, (flag & 0x01) != 0 && len < 3*1024); break; case BLOCK_I2NP: diff --git a/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java b/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java index f85670de8..cfe0d8416 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java @@ -197,16 +197,20 @@ class SSU2Payload { if (ftot == 0) throw new IOException("Bad fragment count for ROUTERINFO: " + ftot); if (fnum == 0 && ftot == 1) { - RouterInfo alice = new RouterInfo(); ByteArrayInputStream bais; if (gz) { byte decompressed[] = DataHelper.decompress(payload, i + 2, len - 2); + if (decompressed.length > RouterInfo.MAX_UNCOMPRESSED_SIZE) + throw new DataFormatException("RI too big: " + decompressed.length); bais = new ByteArrayInputStream(decompressed); } else { + if (len - 2 > RouterInfo.MAX_UNCOMPRESSED_SIZE) + throw new DataFormatException("RI too big: " + (len - 2)); bais = new ByteArrayInputStream(payload, i + 2, len - 2); } - if (bais.available() >= 4*1024) + if (bais.available() >= 3*1024) flood = false; + RouterInfo alice = new RouterInfo(); alice.readBytes(bais, true); cb.gotRI(alice, isHandshake, flood); } else {