innd DOS attack reported

Katsuhiro Kondou kondou at nec.co.jp
Wed Jul 26 16:47:28 UTC 2000



In article <20000726194840U.kondou at inn.do.mms.mt.nec.co.jp>,
	Katsuhiro Kondou <kondou at nec.co.jp> wrote;

} } A Debian GNU/Linux user has pointed out that innd can be made to consume lots
} } of RAM by opening a connection to it and feeding it lots of bytes without any
} } commands.  Testing for and handling this case explicitly might be worthwhile? 
} 
} Hm, innd seems to grow space for fetching nntp command.
} I'll try to fix.

I think I've fixed it.  Try attached.
-- 
Katsuhiro Kondou

--- innd/innd.h.orig	Tue Jun  6 07:42:07 2000
+++ innd/innd.h	Wed Jul 26 23:00:04 2000
@@ -134,7 +134,7 @@
     CSpaused,
     CSgetarticle,
     CSeatarticle,
-    CSgetrep,
+    CSeatcommand,
     CSgetxbatch
 } CHANNELSTATE;
 
@@ -201,6 +201,7 @@
     int                 PrecommitiCachenext;
     int                 XBatchSize;
     int                 LargeArtSize;
+    int                 LargeCmdSize;
     int			Lastch;
     int			Rest;
     int			SaveUsed;
--- innd/nc.c.orig	Fri Jun  9 10:52:52 2000
+++ innd/nc.c	Wed Jul 26 22:59:56 2000
@@ -260,7 +260,6 @@
     case CSgetcmd:
     case CSgetauth:
     case CSgetarticle:
-    case CSgetrep:
     case CSgetxbatch:
 	RCHANadd(cp);
 	break;
@@ -768,6 +767,15 @@
 	    if (i < bp->Used) cp->Rest = bp->Used = ++i;
 	    else {
 		cp->Rest = 0;
+		/* Check for too long command. */
+		if (bp->Used > NNTP_STRLEN) {
+		    /* Make some room, saving only the last few bytes. */
+		    for (p = bp->Data, i = 0; i < SAVE_AMT; p++, i++)
+			p[0] = p[bp->Used - SAVE_AMT];
+		    cp->LargeCmdSize += bp->Used - SAVE_AMT;
+		    bp->Used = cp->Lastch = SAVE_AMT;
+		    cp->State = CSeatcommand;
+		}
 		break;	/* come back later for rest of line */
 	    }
 	    if (cp->Rest < 2) break;
@@ -858,7 +866,6 @@
 	    break;
 
 	case CSgetarticle:
-	case CSgetrep:
 	    /* Check for the null article. */
 	    if ((bp->Used >= 3) && (bp->Data[0] == '.')
 	     && (bp->Data[1] == '\r') && (bp->Data[2] == '\n')) {
@@ -1000,6 +1007,61 @@
 		for (p = bp->Data, i = 0; i < SAVE_AMT; p++, i++)
 		    p[0] = p[bp->Used - SAVE_AMT + 0];
 		cp->LargeArtSize += bp->Used - SAVE_AMT;
+		bp->Used = cp->Lastch = SAVE_AMT;
+		cp->Rest = 0;
+	    }
+	    break;
+	case CSeatcommand:
+	    /* Eat the command line and then complain that it was too large */
+	    /* Reading a line; look for "\r\n" terminator. */
+	    if (cp->Lastch > 5) i = cp->Lastch; /* only look at new data */
+	    else		i = 5;
+	    for ( ; i <= bp->Used; i++) {
+		if ((bp->Data[i - 2] == '\r') && (bp->Data[i - 1] == '\n')) {
+		    cp->Rest = bp->Used = i;
+		    p = &bp->Data[i];
+		    break;
+		}
+	    }
+	    if (i <= bp->Used) {	/* did find terminator */
+		/* Reached the end of the command line. */
+		SCHANremove(cp);
+		if (cp->Argument != NULL) {
+		    DISPOSE(cp->Argument);
+		    cp->Argument = NULL;
+		}
+		i = cp->LargeCmdSize + bp->Used;
+		syslog(L_NOTICE, "%s internal rejecting too long command line (%d > %d)",
+		    CHANname(cp), i, NNTP_STRLEN);
+		cp->LargeCmdSize = 0;
+		(void)sprintf(buff, "%d command exceeds local limit of %ld bytes",
+			NNTP_BAD_COMMAND_VAL, NNTP_STRLEN);
+		cp->State = CSgetcmd;
+		NCwritereply(cp, buff);
+
+		/*
+		 * only free and allocate the buffer back to
+		 * START_BUFF_SIZE if there's nothing in the buffer we
+		 * need to save (i.e., following commands.
+		 * if there is, then we're probably in streaming mode,
+		 * so probably not much point in trying to keep the
+		 * buffers minimal anyway...
+		 */
+		if (bp->Used == cp->SaveUsed) {
+		    /* Reset input buffer to the default size; don't let realloc
+		     * be lazy. */
+		    DISPOSE(bp->Data);
+		    bp->Size = START_BUFF_SIZE;
+		    bp->Used = 0;
+		    bp->Data = NEW(char, bp->Size);
+		    cp->SaveUsed = cp->Rest = cp->Lastch = 0;
+		}
+	    }
+	    else if (bp->Used > 8 * 1024) {
+		/* Make some room; save the last few bytes of the article */
+		for (p = bp->Data, i = 0; i < SAVE_AMT; p++, i++)
+		    p[0] = p[bp->Used - SAVE_AMT + 0];
+		cp->LargeCmdSize += bp->Used - SAVE_AMT;
 		bp->Used = cp->Lastch = SAVE_AMT;
 		cp->Rest = 0;
 	    }



More information about the inn-bugs mailing list