Author: tomwhite
Date: Tue Sep 11 11:48:44 2012
New Revision: 1383365
URL: http://svn.apache.org/viewvc?rev=1383365&view=rev
Log:
AVRO-1111. Malformed data can cause OutOfMemoryError in Avro IPC. Contributed
by Mike Percy.
Modified:
avro/trunk/CHANGES.txt
avro/trunk/lang/java/ipc/src/main/java/org/apache/avro/ipc/NettyTransportCodec.java
avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/ipc/TestNettyServer.java
Modified: avro/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1383365&r1=1383364&r2=1383365&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Tue Sep 11 11:48:44 2012
@@ -37,6 +37,9 @@ Avro 1.7.2 (unreleased)
AVRO-1152. Java: Fix TestTraceSingletons for Java 7. (cutting)
+ AVRO-1111. Malformed data can cause OutOfMemoryError in Avro IPC.
+ (Mike Percy via tomwhite)
+
Avro 1.7.1 (16 July 2012)
NEW FEATURES
Modified:
avro/trunk/lang/java/ipc/src/main/java/org/apache/avro/ipc/NettyTransportCodec.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/ipc/src/main/java/org/apache/avro/ipc/NettyTransportCodec.java?rev=1383365&r1=1383364&r2=1383365&view=diff
==============================================================================
---
avro/trunk/lang/java/ipc/src/main/java/org/apache/avro/ipc/NettyTransportCodec.java
(original)
+++
avro/trunk/lang/java/ipc/src/main/java/org/apache/avro/ipc/NettyTransportCodec.java
Tue Sep 11 11:48:44 2012
@@ -21,6 +21,7 @@ package org.apache.avro.ipc;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import org.apache.avro.AvroRuntimeException;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
@@ -119,6 +120,13 @@ public class NettyTransportCodec {
private boolean packHeaderRead = false;
private int listSize;
private NettyDataPack dataPack;
+ private final long maxMem;
+ private static final long SIZEOF_REF = 8L; // mem usage of 64-bit pointer
+
+
+ public NettyFrameDecoder() {
+ maxMem = Runtime.getRuntime().maxMemory();
+ }
/**
* decode buffer to NettyDataPack
@@ -150,8 +158,19 @@ public class NettyTransportCodec {
}
int serial = buffer.readInt();
- listSize = buffer.readInt();
+ int listSize = buffer.readInt();
+
+ // Sanity check to reduce likelihood of invalid requests being honored.
+ // Only allow 10% of available memory to go towards this list (too much!)
+ if (listSize * SIZEOF_REF > 0.1 * maxMem) {
+ channel.close().await();
+ throw new AvroRuntimeException("Excessively large list allocation " +
+ "request detected: " + listSize + " items! Connection closed.");
+ }
+
+ this.listSize = listSize;
dataPack = new NettyDataPack(serial, new
ArrayList<ByteBuffer>(listSize));
+
return true;
}
Modified:
avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/ipc/TestNettyServer.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/ipc/TestNettyServer.java?rev=1383365&r1=1383364&r2=1383365&view=diff
==============================================================================
---
avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/ipc/TestNettyServer.java
(original)
+++
avro/trunk/lang/java/ipc/src/test/java/org/apache/avro/ipc/TestNettyServer.java
Tue Sep 11 11:48:44 2012
@@ -18,9 +18,14 @@
package org.apache.avro.ipc;
+import java.io.IOException;
+import java.io.OutputStream;
import static org.junit.Assert.assertEquals;
import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -148,4 +153,20 @@ public class TestNettyServer {
return msg;
}
+ // send a malformed request (HTTP) to the NettyServer port
+ @Test
+ public void testBadRequest() throws IOException {
+ int port = server.getPort();
+ String msg = "GET /status HTTP/1.1\n\n";
+ InetSocketAddress sockAddr = new InetSocketAddress("127.0.0.1", port);
+ Socket sock = new Socket();
+ sock.connect(sockAddr);
+ OutputStream out = sock.getOutputStream();
+ out.write(msg.getBytes(Charset.forName("UTF-8")));
+ out.flush();
+ byte[] buf = new byte[2048];
+ int bytesRead = sock.getInputStream().read(buf);
+ Assert.assertTrue("Connection should have been closed", bytesRead == -1);
+ }
+
}