]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: fix possible assert() fail in zlog_fd()
authorDavid Lamparter <equinox@diac24.net>
Sat, 10 Apr 2021 19:02:06 +0000 (21:02 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Wed, 28 Apr 2021 07:34:10 +0000 (09:34 +0200)
If the last message in a batched logging operation isn't printed due to
priority, this skips the code that flushes prepared messages through
writev() and can trigger the assert() at the end of zlog_fd().

Since any logmsg above info priority triggers a buffer flush, running
into this situation requires a log file target configured for info
priority, at least 1 message of info priority buffered, a debug message
buffered after that, and then a buffer flush (explicit or due to buffer
full).

I haven't seen this chain of events happen in the wild, but it needs
fixing anyway.

Signed-off-by: David Lamparter <equinox@diac24.net>
(cherry picked from commit db2baed166581081db692fab0214752dbb121ed3)

lib/zlog_targets.c

index 8f4c2a46a8e432725d3d997a8ed81df86a9d555d..5e12c309c40f6da8335c4442c7873e1b683a8f82 100644 (file)
@@ -78,40 +78,48 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
                struct zlog_msg *msg = msgs[i];
                int prio = zlog_msg_prio(msg);
 
-               if (prio > zt->prio_min)
-                       continue;
-
-               iov[iovpos].iov_base = ts_pos;
-               if (iovpos > 0)
-                       *ts_pos++ = '\n';
-               ts_pos += zlog_msg_ts(msg, ts_pos, sizeof(ts_buf) - 1
-                                     - (ts_pos - ts_buf),
-                                     ZLOG_TS_LEGACY | zte->ts_subsec);
-               *ts_pos++ = ' ';
-               iov[iovpos].iov_len = ts_pos - (char *)iov[iovpos].iov_base;
+               if (prio <= zt->prio_min) {
+                       iov[iovpos].iov_base = ts_pos;
+                       if (iovpos > 0)
+                               *ts_pos++ = '\n';
+                       ts_pos += zlog_msg_ts(msg, ts_pos,
+                                             sizeof(ts_buf) - 1
+                                                     - (ts_pos - ts_buf),
+                                             ZLOG_TS_LEGACY | zte->ts_subsec);
+                       *ts_pos++ = ' ';
+                       iov[iovpos].iov_len =
+                               ts_pos - (char *)iov[iovpos].iov_base;
 
-               iovpos++;
+                       iovpos++;
 
-               if (zte->record_priority) {
-                       iov[iovpos].iov_base = (char *)prionames[prio];
-                       iov[iovpos].iov_len = strlen(iov[iovpos].iov_base);
+                       if (zte->record_priority) {
+                               iov[iovpos].iov_base = (char *)prionames[prio];
+                               iov[iovpos].iov_len =
+                                       strlen(iov[iovpos].iov_base);
 
-                       iovpos++;
-               }
+                               iovpos++;
+                       }
 
-               iov[iovpos].iov_base = zlog_prefix;
-               iov[iovpos].iov_len = zlog_prefixsz;
+                       iov[iovpos].iov_base = zlog_prefix;
+                       iov[iovpos].iov_len = zlog_prefixsz;
 
-               iovpos++;
+                       iovpos++;
 
-               iov[iovpos].iov_base = (char *)zlog_msg_text(msg, &textlen);
-               iov[iovpos].iov_len = textlen;
+                       iov[iovpos].iov_base =
+                               (char *)zlog_msg_text(msg, &textlen);
+                       iov[iovpos].iov_len = textlen;
 
-               iovpos++;
+                       iovpos++;
+               }
 
-               if (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
-                   || i + 1 == nmsgs
-                   || array_size(iov) - iovpos < 5) {
+               /* conditions that trigger writing:
+                *  - out of space for more timestamps/headers
+                *  - this being the last message in the batch
+                *  - not enough remaining iov entries
+                */
+               if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
+                                  || i + 1 == nmsgs
+                                  || array_size(iov) - iovpos < 5)) {
                        iov[iovpos].iov_base = (char *)"\n";
                        iov[iovpos].iov_len = 1;