summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2014-11-25 20:59:22 +0000
committerdelphij <delphij@FreeBSD.org>2014-11-25 20:59:22 +0000
commit4e7f1924945cfb59b6d7b938f83aff58e281d512 (patch)
treea3598651b251bc8803e26d2dc6d047c1b36863d2
parentdb759d1bdf8558e7648f20f29cf2c8e60b41ba13 (diff)
downloadFreeBSD-src-4e7f1924945cfb59b6d7b938f83aff58e281d512.zip
FreeBSD-src-4e7f1924945cfb59b6d7b938f83aff58e281d512.tar.gz
Reinstitate send() after syslogd restarts.
In r228193 the test of CONNPRIV have been moved to before the _usleep and send in vsyslog(). When syslogd restarts, this would prevent the message being logged after the disconnect/connect dance for scenario #1. PR: 194751 Submitted by: Peter Creath <pjcreath+freebsd gmail com> Reviewed By: glebius MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D1227
-rw-r--r--lib/libc/gen/syslog.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c
index 3a5cafe..003f24d 100644
--- a/lib/libc/gen/syslog.c
+++ b/lib/libc/gen/syslog.c
@@ -261,26 +261,45 @@ vsyslog(int pri, const char *fmt, va_list ap)
connectlog();
/*
- * If the send() failed, there are two likely scenarios:
+ * If the send() fails, there are two likely scenarios:
* 1) syslogd was restarted
* 2) /var/run/log is out of socket buffer space, which
* in most cases means local DoS.
- * We attempt to reconnect to /var/run/log[priv] to take care of
- * case #1 and keep send()ing data to cover case #2
- * to give syslogd a chance to empty its socket buffer.
+ * If the error does not indicate a full buffer, we address
+ * case #1 by attempting to reconnect to /var/run/log[priv]
+ * and resending the message once.
*
- * If we are working with a priveleged socket, then take
- * only one attempt, because we don't want to freeze a
+ * If we are working with a privileged socket, the retry
+ * attempts end there, because we don't want to freeze a
* critical application like su(1) or sshd(8).
*
+ * Otherwise, we address case #2 by repeatedly retrying the
+ * send() to give syslogd a chance to empty its socket buffer.
*/
if (send(LogFile, tbuf, cnt, 0) < 0) {
if (errno != ENOBUFS) {
+ /*
+ * Scenario 1: syslogd was restarted
+ * reconnect and resend once
+ */
disconnectlog();
connectlog();
+ if (send(LogFile, tbuf, cnt, 0) >= 0) {
+ THREAD_UNLOCK();
+ return;
+ }
+ /*
+ * if the resend failed, fall through to
+ * possible scenario 2
+ */
}
- do {
+ while (errno == ENOBUFS) {
+ /*
+ * Scenario 2: out of socket buffer space
+ * possible DoS, fail fast on a privileged
+ * socket
+ */
if (status == CONNPRIV)
break;
_usleep(1);
@@ -288,7 +307,7 @@ vsyslog(int pri, const char *fmt, va_list ap)
THREAD_UNLOCK();
return;
}
- } while (errno == ENOBUFS);
+ }
} else {
THREAD_UNLOCK();
return;
@@ -350,7 +369,7 @@ connectlog(void)
SyslogAddr.sun_family = AF_UNIX;
/*
- * First try priveleged socket. If no success,
+ * First try privileged socket. If no success,
* then try default socket.
*/
(void)strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
OpenPOWER on IntegriCloud