]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
logger: bugfix: missing sanity checks with --prio-prefix option
authorRainer Gerhards <rgerhards@adiscon.com>
Sat, 7 Mar 2015 10:49:00 +0000 (11:49 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 12 Mar 2015 09:20:44 +0000 (10:20 +0100)
There were no apparent sanity checks other than applying the logmask
when reading PRI values from files. As such, invalid PRIs (tested with
values 192, 210, and 2100) are accepted. This in turn can trigger
problems in various receivers, especially older versions. See here
for details:

http://www.rsyslog.com/remote-syslog-pri-vulnerability-cve-2014-3683/

Note that 2100 was changed to 52 as described in above link.

This patch refactors PRI processing. Invalid PRIs are detected and in
this case the message is sent with the default priority, with the
invalid pri being part of the message to be sent. This is along the
line of what 2.26 did when it detected the PRI was invalid.

The refactoring now also enables pricese tracking of syslog header
length in all cases, so --size is now strictly obeyed.

[kzak@redhat.com: - fix compiler warning [-Wunused-variable]]

Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/logger.c

index 3a4d58efeee51dbe9d4a6cbadd247e8909aab6e6..575d111e684a2d15f97f92ce56714a7100116c81 100644 (file)
@@ -114,25 +114,6 @@ struct logger_ctl {
                        rfc5424_host:1;         /* include hostname */
 };
 
-static char *get_prio_prefix(char *msg, int *prio)
-{
-       int p;
-       char *end = NULL;
-       int facility = *prio & LOG_FACMASK;
-
-       errno = 0;
-       p = strtoul(msg + 1, &end, 10);
-
-       if (errno || !end || end == msg + 1 || end[0] != '>')
-               return msg;
-
-       if (p & LOG_FACMASK)
-               facility = p & LOG_FACMASK;
-
-       *prio = facility | (p & LOG_PRIMASK);
-       return end + 1;
-}
-
 static int decode(const char *name, CODE *codetab)
 {
        register CODE *c;
@@ -548,25 +529,55 @@ static void logger_command_line(const struct logger_ctl *ctl, char **argv)
 
 static void logger_stdin(struct logger_ctl *ctl)
 {
-       char *msg;
        int default_priority = ctl->pri;
-       const size_t max_usrmsg_size = ctl->max_message_size - strlen(ctl->hdr);
-       char *const buf = xmalloc(max_usrmsg_size + 2);
-
-       while (fgets(buf, max_usrmsg_size+2, stdin) != NULL) {
-               int len = strlen(buf);
-
-               /* some glibc versions are buggy, they add an additional
-                * newline which is removed here.  */
-               if (0 < len && buf[len - 1] == '\n')
-                       buf[len - 1] = '\0';
-               msg = buf;
-               ctl->pri = default_priority;
-               if (ctl->prio_prefix && msg[0] == '<')
-                       msg = get_prio_prefix(msg, &ctl->pri);
-               /* this potentially runs long, date may have changed (and also PRI) */
-               generate_syslog_header(ctl);
-               write_output(ctl, msg);
+       int last_pri = default_priority;
+       size_t max_usrmsg_size = ctl->max_message_size - strlen(ctl->hdr);
+       char *const buf = xmalloc(max_usrmsg_size + 2 + 2);
+       int pri;
+       int c;
+       size_t i;
+
+       c = getchar();
+       while (c != EOF) {
+               i = 0;
+               if (ctl->prio_prefix) {
+                       if (c == '<') {
+                               pri = 0;
+                               buf[i++] = c;
+                               while(isdigit(c = getchar()) && pri <= 191) {
+                                               buf[i++] = c;
+                                               pri = pri * 10 + c - '0';
+                               }
+                               if (c != EOF && c != '\n')
+                                       buf[i++] = c;
+                               if (c == '>' && 0 <= pri && pri <= 191) { /* valid RFC PRI values */
+                                       i = 0;
+                                       if (pri < 8)
+                                               pri |= 8; /* kern facility is forbidden */
+                                       ctl->pri = pri;
+                               } else
+                                       ctl->pri = default_priority;
+
+                               if (ctl->pri != last_pri) {
+                                       generate_syslog_header(ctl);
+                                       max_usrmsg_size = ctl->max_message_size - strlen(ctl->hdr);
+                                       last_pri = ctl->pri;
+                               }
+                               if (c != EOF && c != '\n')
+                                       c = getchar();
+                       }
+               }
+
+               while (c != EOF && c != '\n' && i < max_usrmsg_size) {
+                       buf[i++] = c;
+                       c = getchar();
+               }
+               buf[i] = '\0';
+
+               write_output(ctl, buf);
+
+               if (c == '\n') /* discard line terminator */
+                       c = getchar();
        }
 }