I found an integer overflow in syslogd which can be triggered by
compiling and running:

#include <err.h>
#include <string.h>
#include <sys/types.h>

int main( int argc, char ** argv ) {
        const char * msg = "<999999999999> hello";
        return sendsyslog( msg, strlen( msg ) );
}


The problematic code is a hand-rolled int parser in printline/printsys:

pri = 0;
while (isdigit((unsigned char)*++p))
        pri = 10 * pri + (*p - '0');
if (*p == '>')
        ++p;


I've attached a patch which converts the loop to strtonum, but doesn't
exactly mirror the behaviour of the old code in funny cases, like
sendsyslog("<1no closing angle bracket").

Mike
Index: syslogd.c
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.177
diff -u -p -r1.177 syslogd.c
--- syslogd.c   20 Jul 2015 19:49:33 -0000      1.177
+++ syslogd.c   11 Feb 2016 20:31:55 -0000
@@ -1331,18 +1331,23 @@ usage(void)
 void
 printline(char *hname, char *msg)
 {
-       int pri;
-       char *p, *q, line[MAXLINE + 4 + 1];  /* message, encoding, NUL */
+       int pri, possiblepri;
+       char *p, *q, line[MAXLINE + 4 + 1], *gt;  /* message, encoding, NUL */
+       const char *errstr;
 
        /* test for special codes */
        pri = DEFUPRI;
        p = msg;
        if (*p == '<') {
-               pri = 0;
-               while (isdigit((unsigned char)*++p))
-                       pri = 10 * pri + (*p - '0');
-               if (*p == '>')
-                       ++p;
+               gt = strchr(p, '>');
+               if (gt) {
+                       *gt = '\0';
+                       possiblepri = strtonum(p + 1, 0, INT_MAX, &errstr);
+                       if (!errstr)
+                               pri = possiblepri;
+                       *gt = '>';
+                       p = gt + 1;
+               }
        }
        if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
                pri = DEFUPRI;
@@ -1372,8 +1377,9 @@ printline(char *hname, char *msg)
 void
 printsys(char *msg)
 {
-       int c, pri, flags;
-       char *lp, *p, *q, line[MAXLINE + 1];
+       int c, pri, flags, possiblepri;
+       char *lp, *p, *q, line[MAXLINE + 1], *gt;
+       const char *errstr;
 
        (void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX);
        lp = line + strlen(line);
@@ -1381,11 +1387,15 @@ printsys(char *msg)
                flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
                pri = DEFSPRI;
                if (*p == '<') {
-                       pri = 0;
-                       while (isdigit((unsigned char)*++p))
-                               pri = 10 * pri + (*p - '0');
-                       if (*p == '>')
-                               ++p;
+                       gt = strchr(p, '>');
+                       if (gt) {
+                               *gt = '\0';
+                               possiblepri = strtonum(p + 1, 0, INT_MAX, 
&errstr);
+                               if (!errstr)
+                                       pri = possiblepri;
+                               *gt = '>';
+                               p = gt + 1;
+                       }
                } else {
                        /* kernel printf's come out on console */
                        flags |= IGN_CONS;

Reply via email to