For every (first) IPv4 fragment received, a buffer of size
IPV4_FRAG_IOB_SIZE (currently 1500 bytes) is allocated. Limiting the
number of fragment buffers prevents memory exhaustion if too many
fragments are received without being assembled (e.g. because of wrongly
configured firewall).
Signed-off-by: Michal Kubecek <mku...@su...>
---
src/include/gpxe/ip.h | 1 +
src/net/ipv4.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/src/include/gpxe/ip.h b/src/include/gpxe/ip.h
index 29def10..55854ca 100644
--- a/src/include/gpxe/ip.h
+++ b/src/include/gpxe/ip.h
@@ -34,6 +34,7 @@ struct net_protocol;
#define IP_FRAG_IOB_SIZE 1500
#define IP_FRAG_TIMEOUT 50
+#define IP_FRAG_MAXBUFS 128
#define IP_FRAG_EXPIRED 0x0001
/** An IPv4 packet header */
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index f20762f..53048b8 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -34,6 +34,9 @@ struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
/** List of fragment reassembly buffers */
static LIST_HEAD ( frag_buffers );
+/** Current number of fragment reassembly buffers */
+static int frag_buffer_count = 0;
+
/**
* Add IPv4 minirouting table entry
*
@@ -157,6 +160,7 @@ static void ipv4_frag_expired ( struct retry_timer *timer,
*/
static void free_fragbuf ( struct frag_buffer *fragbuf ) {
list_del ( &fragbuf->list );
+ frag_buffer_count--;
stop_timer ( &fragbuf->frag_timer );
if ( fragbuf->frag_iob )
free_iob ( fragbuf->frag_iob );
@@ -179,6 +183,27 @@ static void ipv4_frag_cleanup ()
}
/**
+ * Remove oldest fragment buffer
+ *
+ */
+static void ipv4_frag_remove_oldest ()
+{
+ struct frag_buffer *fragbuf;
+ struct frag_buffer *oldest = NULL;
+ unsigned long oldest_start = 0;
+
+ list_for_each_entry ( fragbuf, &frag_buffers, list ) {
+ if ( !oldest || (fragbuf->frag_timer.start < oldest_start) ) {
+ oldest = fragbuf;
+ oldest_start = fragbuf->frag_timer.start;
+ }
+ }
+
+ if ( oldest )
+ free_fragbuf ( oldest );
+}
+
+/**
* Fragment reassembler
*
* @v iobuf I/O buffer, fragment of the datagram
@@ -246,6 +271,10 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
/** Check if the fragment is the first in the fragment series */
if ( ( pkt_frags & IP_MASK_MOREFRAGS ) &&
( ( pkt_frags & IP_MASK_OFFSET ) == 0 ) ) {
+
+ /* If there are too many buffers, remove the oldest */
+ if ( frag_buffer_count >= IP_FRAG_MAXBUFS )
+ ipv4_frag_remove_oldest();
/** Create a new fragment buffer */
fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
@@ -266,6 +295,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
/* Add the fragment buffer to the list of fragment buffers */
list_add ( &fragbuf->list, &frag_buffers );
+ frag_buffer_count++;
} else {
/* Doesn't match anything but it's not first fragment */
free_iob ( iobuf );
--
1.7.7
|