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