logger: use --id as local socket credentials

If you have really paranoid syslog (or systemd who listens on /dev/log)
then it replaces in the message PID with a real PID from socket header
credentials:

 # echo $PPID
 1550

 # logger -p info --stderr --id=$PPID "This is message baby!"
 <14>Oct 29 11:22:13 kzak[1550]: This is message baby!

 # journald -n 1
 Oct 29 11:22:13 ws kzak[22100]: This is message baby!
                         ^^^^^

This patch forces kernel to accept another *valid* PID if logger(1)
executed with root permissions; improved version:

 # logger -p info --stderr --id=$PPID "This is message baby!"
 <14>Oct 29 11:26:00 kzak[1550]: This is message baby!

 # journald -n 1
 Oct 29 11:26:00 ws kzak[1550]: This is message baby!

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2015-10-29 11:18:21 +01:00
parent 17c8aa1dc0
commit 27a9eb5359
2 changed files with 36 additions and 0 deletions

View File

@ -71,6 +71,14 @@ Log the PID of the logger process with each line. When the optional
argument \fIid\fR is specified, then it is used instead of the logger
command's PID. The use of \fB\-\-id=$$\fR
(PPID) is recommended in scripts that send several messages.
Note that system logging infrastructure (for example systemd when listen on
/dev/log) may follow local socket credentials to overwrite in the message
specified PID.
.BR logger(1)
is able to to set the socket credentials to the \fIid\fR if you have
root permissions and process with the specified PID exists, otherwise
the socket credentials are not modified and the problem is silently ignored.
.TP
.BR \-\-journald [ =\fIfile ]
Write a systemd journal entry. The entry is read from the given \fIfile\fR,

View File

@ -51,6 +51,8 @@
#include <netdb.h>
#include <getopt.h>
#include <pwd.h>
#include <sys/types.h>
#include <signal.h>
#include "all-io.h"
#include "c.h"
@ -444,6 +446,12 @@ static void write_output(const struct logger_ctl *ctl, const char *const msg)
if (!ctl->noact) {
struct msghdr msg = { 0 };
struct cmsghdr *cmhp;
struct ucred *cred;
union {
struct cmsghdr cmh;
char control[CMSG_SPACE(sizeof(struct ucred))];
} cbuf;
/* 4) add extra \n to make sure message is terminated */
if ((ctl->socket_type == TYPE_TCP) && !ctl->octet_count)
@ -452,6 +460,26 @@ static void write_output(const struct logger_ctl *ctl, const char *const msg)
msg.msg_iov = iov;
msg.msg_iovlen = iovlen;
/* syslog/journald may follow local socket credentials rather
* than in the message PID. If we use --id as root than we can
* force kernel to accept another valid PID than the real logger(1)
* PID.
*/
if (ctl->pid && !ctl->server && ctl->pid != getpid()
&& geteuid() == 0 && kill(ctl->pid, 0) == 0) {
msg.msg_control = cbuf.control;
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); //sizeof(cbuf);
cmhp = CMSG_FIRSTHDR(&msg);
cmhp->cmsg_len = CMSG_LEN(sizeof(struct ucred));
cmhp->cmsg_level = SOL_SOCKET;
cmhp->cmsg_type = SCM_CREDENTIALS;
cred = (struct ucred *) CMSG_DATA(cmhp);
cred->pid = ctl->pid;
}
if (sendmsg(ctl->fd, &msg, 0) < 0)
warn(_("send message failed"));
}