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:
Gleb Smirnoff 2004-11-04 23:09:57 +00:00
parent 247444670e
commit 240d5a9b1c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=137233
4 changed files with 57 additions and 19 deletions

View File

@ -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 */

View File

@ -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 */
/*

View File

@ -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

View File

@ -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);