Protect against local flooder of /var/run/log. Do not loop forever in
syslog(3) if we are a priveleged program (sshd, su, etc.). - Make syslogd open an additional socket /var/run/logpriv, with 0600 permissions. - In libc, try to use this socket. - Do not loop forever if we are using this socket (partial backout of 1.31) Reviewed by: dwmalone, Andrea Campi <andrea webcom it> Approved by: julian (mentor) MFC after: 1 month
This commit is contained in:
parent
247444670e
commit
240d5a9b1c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=137233
@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "libc_private.h"
|
||||
|
||||
static int LogFile = -1; /* fd for log */
|
||||
static int connected; /* have done connect */
|
||||
static int status; /* connection status */
|
||||
static int opened; /* have done openlog() */
|
||||
static int LogStat = 0; /* status bits, set by openlog() */
|
||||
static const char *LogTag = NULL; /* string to tag the entry with */
|
||||
@ -70,6 +70,12 @@ static int LogMask = 0xff; /* mask of priorities to be logged */
|
||||
static void disconnectlog(void); /* disconnect from syslogd */
|
||||
static void connectlog(void); /* (re)connect to syslogd */
|
||||
|
||||
enum {
|
||||
NOCONN = 0,
|
||||
CONNDEF,
|
||||
CONNPRIV,
|
||||
};
|
||||
|
||||
/*
|
||||
* Format of the magic cookie passed through the stdio hook
|
||||
*/
|
||||
@ -247,10 +253,16 @@ vsyslog(pri, fmt, ap)
|
||||
/*
|
||||
* If the send() failed, there are two likely scenarios:
|
||||
* 1) syslogd was restarted
|
||||
* 2) /var/run/log is out of socket buffer space
|
||||
* 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 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 we are working with a priveleged socket, then take
|
||||
* only one attempt, because we don't want to freeze a
|
||||
* critical application like su(1) or sshd(8).
|
||||
*
|
||||
*/
|
||||
|
||||
if (send(LogFile, tbuf, cnt, 0) < 0) {
|
||||
@ -262,6 +274,8 @@ vsyslog(pri, fmt, ap)
|
||||
usleep(1);
|
||||
if (send(LogFile, tbuf, cnt, 0) >= 0)
|
||||
break;
|
||||
if (status == CONNPRIV)
|
||||
break;
|
||||
} while (errno == ENOBUFS);
|
||||
}
|
||||
|
||||
@ -297,7 +311,7 @@ disconnectlog()
|
||||
_close(LogFile);
|
||||
LogFile = -1;
|
||||
}
|
||||
connected = 0; /* retry connect */
|
||||
status = NOCONN; /* retry connect */
|
||||
}
|
||||
|
||||
static void
|
||||
@ -310,27 +324,41 @@ connectlog()
|
||||
return;
|
||||
(void)_fcntl(LogFile, F_SETFD, 1);
|
||||
}
|
||||
if (LogFile != -1 && !connected) {
|
||||
if (LogFile != -1 && status == NOCONN) {
|
||||
SyslogAddr.sun_len = sizeof(SyslogAddr);
|
||||
SyslogAddr.sun_family = AF_UNIX;
|
||||
(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
|
||||
sizeof SyslogAddr.sun_path);
|
||||
connected = _connect(LogFile, (struct sockaddr *)&SyslogAddr,
|
||||
sizeof(SyslogAddr)) != -1;
|
||||
|
||||
if (!connected) {
|
||||
/*
|
||||
* First try priveleged socket. If no success,
|
||||
* then try default socket.
|
||||
*/
|
||||
(void)strncpy(SyslogAddr.sun_path, _PATH_LOG_PRIV,
|
||||
sizeof SyslogAddr.sun_path);
|
||||
if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
|
||||
sizeof(SyslogAddr)) != -1)
|
||||
status = CONNPRIV;
|
||||
|
||||
if (status == NOCONN) {
|
||||
(void)strncpy(SyslogAddr.sun_path, _PATH_LOG,
|
||||
sizeof SyslogAddr.sun_path);
|
||||
if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
|
||||
sizeof(SyslogAddr)) != -1)
|
||||
status = CONNDEF;
|
||||
}
|
||||
|
||||
if (status == NOCONN) {
|
||||
/*
|
||||
* Try the old "/dev/log" path, for backward
|
||||
* compatibility.
|
||||
*/
|
||||
(void)strncpy(SyslogAddr.sun_path, _PATH_OLDLOG,
|
||||
sizeof SyslogAddr.sun_path);
|
||||
connected = _connect(LogFile,
|
||||
(struct sockaddr *)&SyslogAddr,
|
||||
sizeof(SyslogAddr)) != -1;
|
||||
if (_connect(LogFile, (struct sockaddr *)&SyslogAddr,
|
||||
sizeof(SyslogAddr)) != -1)
|
||||
status = CONNDEF;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
if (status == NOCONN) {
|
||||
(void)_close(LogFile);
|
||||
LogFile = -1;
|
||||
}
|
||||
@ -360,7 +388,7 @@ closelog()
|
||||
(void)_close(LogFile);
|
||||
LogFile = -1;
|
||||
LogTag = NULL;
|
||||
connected = 0;
|
||||
status = NOCONN;
|
||||
}
|
||||
|
||||
/* setlogmask -- set the log mask level */
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define _SYS_SYSLOG_H_
|
||||
|
||||
#define _PATH_LOG "/var/run/log"
|
||||
#define _PATH_LOG_PRIV "/var/run/logpriv"
|
||||
#define _PATH_OLDLOG "/dev/log" /* backward compatibility */
|
||||
|
||||
/*
|
||||
|
@ -250,8 +250,10 @@ The
|
||||
.Nm
|
||||
utility reads messages from the
|
||||
.Ux
|
||||
domain socket
|
||||
.Pa /var/run/log ,
|
||||
domain sockets
|
||||
.Pa /var/run/log
|
||||
and
|
||||
.Pa /var/run/logpriv ,
|
||||
from an Internet domain socket specified in
|
||||
.Pa /etc/services ,
|
||||
and from the special device
|
||||
@ -293,6 +295,9 @@ default process ID file
|
||||
name of the
|
||||
.Ux
|
||||
domain datagram log socket
|
||||
.It Pa /var/run/logpriv
|
||||
.Ux
|
||||
socket for priveleged applications
|
||||
.It Pa /dev/klog
|
||||
kernel log device
|
||||
.El
|
||||
|
@ -129,6 +129,8 @@ const char ctty[] = _PATH_CONSOLE;
|
||||
|
||||
/*
|
||||
* Unix sockets.
|
||||
* We have two default sockets, one with 666 permissions,
|
||||
* and one for priveleged programs
|
||||
*/
|
||||
struct funix {
|
||||
int s;
|
||||
@ -136,11 +138,13 @@ struct funix {
|
||||
mode_t mode;
|
||||
STAILQ_ENTRY(funix) next;
|
||||
};
|
||||
struct funix funix_default = { -1, _PATH_LOG, DEFFILEMODE,
|
||||
struct funix funix_secure = { -1, _PATH_LOG_PRIV, S_IRUSR | S_IWUSR,
|
||||
{ NULL } };
|
||||
struct funix funix_default = { -1, _PATH_LOG, DEFFILEMODE,
|
||||
{ &funix_secure } };
|
||||
|
||||
STAILQ_HEAD(, funix) funixes = { &funix_default,
|
||||
&(funix_default.next.stqe_next) };
|
||||
&(funix_secure.next.stqe_next) };
|
||||
|
||||
/*
|
||||
* Flags to logmsg().
|
||||
@ -504,7 +508,7 @@ main(int argc, char *argv[])
|
||||
"cannot create %s", fx->name);
|
||||
logerror(line);
|
||||
dprintf("cannot create %s (%d)\n", fx->name, errno);
|
||||
if (fx == &funix_default)
|
||||
if (fx == &funix_default || fx == &funix_secure)
|
||||
die(0);
|
||||
else
|
||||
STAILQ_REMOVE(&funixes, fx, funix, next);
|
||||
|
Loading…
Reference in New Issue
Block a user