首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >日记如何知道产生日志数据的进程的PID?

日记如何知道产生日志数据的进程的PID?
EN

Unix & Linux用户
提问于 2018-12-29 05:51:03
回答 2查看 2.2K关注 0票数 2

当我看journalctl时,它会告诉我PID和程序名称(还是服务名称?)一个日志条目。

然后我想知道,日志是由其他进程创建的,systemd-journald如何知道这些进程的PID,当进程只可能将原始字符串写入systemd-journald正在监听的unix域套接字时。另外,sytemd-journald是否总是使用相同的技术来检测一段日志数据的PID,即使进程使用sd_journal_sendv()之类的函数生成日志?

关于这件事,我有什么文件要看吗?

我读过JdeBP的回答,知道systemd-journald监听Unix套接字,但是即使知道发送日志消息的对等套接字地址,它怎么知道PID呢?如果这个发送套接字是由许多非父进程打开的呢?

EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2018-12-29 07:04:09

它通过unix套接字上的SCM_CREDENTIALS辅助数据(参见unix(7) )接收pid。不需要显式发送凭据。

示例:

代码语言:javascript
复制
$ cc -Wall scm_cred.c -o scm_cred
$ ./scm_cred
scm_cred: received from 10114: pid=10114 uid=2000 gid=2000

带有CAP_SYS_ADMIN数据的进程可以通过SCM_CREDENTIALS发送他们想要的任何pid;在systemd-journald的情况下,这意味着它们可以伪造条目,就像被另一个进程记录一样:

代码语言:javascript
复制
# cc -Wall fake.c -o fake
# setcap CAP_SYS_ADMIN+ep fake

$ ./fake `pgrep -f /usr/sbin/sshd`

# journalctl --no-pager -n 1
...
Dec 29 11:04:57 debin sshd[419]: fake log message from 14202
# rm fake
# lsb_release -d
Description:    Debian GNU/Linux 9.6 (stretch)

systemd-journald处理数据报,通过辅助数据发送的凭据位于来自journald-server.cserver_process_datagram()函数中。默认情况下,来自libcD12标准函数和来自libsystemdsd_journal_sendv()将通过SOCK_DGRAM套接字发送数据,而getsockopt(SO_PEERCRED)不工作于数据报(无连接)套接字。systemd-journaldrsyslogd都不接受/dev/log上的SOCK_STREAM连接。

scm_cred.c.c

代码语言:javascript
复制
#define _GNU_SOURCE     1
#include 
#include 
#include 
#include 

int main(void){
        int fd[2]; pid_t pid;
        if(socketpair(AF_LOCAL, SOCK_DGRAM, 0, fd)) err(1, "socketpair");
        if((pid = fork()) == -1) err(1, "fork");
        if(pid){ /* parent */
                int on = 1;
                union {
                        struct cmsghdr h;
                        char data[CMSG_SPACE(sizeof(struct ucred))];
                } buf;
                struct msghdr m = {0};
                struct ucred *uc = (struct ucred*)CMSG_DATA(&buf.h);
                m.msg_control = &buf;
                m.msg_controllen = sizeof buf;
                if(setsockopt(fd[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof on))
                        err(1, "setsockopt");
                if(recvmsg(fd[0], &m, 0) == -1) err(1, "recvmsg");
                warnx("received from %d: pid=%d uid=%d gid=%d", pid,
                        uc->pid, uc->uid, uc->gid);
        }else   /* child */
                write(fd[1], 0, 0);
        return 0;
}

伪造.c

代码语言:javascript
复制
#define _GNU_SOURCE     1
#include 
#include 
#include 
#include 
#include 
#include 

int main(int ac, char **av){
        union {
                struct cmsghdr h;
                char data[CMSG_SPACE(sizeof(struct ucred))];
        } cm;
        int fd; char buf[256];
        struct ucred *uc = (struct ucred*)CMSG_DATA(&cm.h);
        struct msghdr m = {0};
        struct sockaddr_un ua = {AF_UNIX, "/dev/log"};
        struct iovec iov = {buf};
        if((fd = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1) err(1, "socket");
        if(connect(fd, (struct sockaddr*)&ua, SUN_LEN(&ua))) err(1, "connect");
        m.msg_control = &cm;
        m.msg_controllen = cm.h.cmsg_len = CMSG_LEN(sizeof(struct ucred));
        cm.h.cmsg_level = SOL_SOCKET;
        cm.h.cmsg_type = SCM_CREDENTIALS;
        uc->pid = ac > 1 ? atoi(av[1]) : getpid();
        uc->uid = ac > 2 ? atoi(av[2]) : geteuid();
        uc->gid = ac > 3 ? atoi(av[3]) : getegid();
        iov.iov_len = snprintf(buf, sizeof buf, "<13>%s from %d",
                ac > 4 ? av[4] : "fake log message", getpid());
        if(iov.iov_len >= sizeof buf) errx(1, "message too long");
        m.msg_iov = &iov;
        m.msg_iovlen = 1;
        if(sendmsg(fd, &m, 0) == -1) err(1, "sendmsg");
        return 0;
}
票数 5
EN

Unix & Linux用户

发布于 2018-12-29 07:56:00

内核告诉它的.

连接AF_LOCAL流套接字的原始客户端进程的EUID、EGID和PID可以通过SO_PEERCRED套接字选项它使用的从内核获得。UCSPI-UNIX工具通过同一个系统调用获得相同的信息。

当然,子服务进程继承已经打开的标准I/O文件描述符(当然,除非父服务进程更改了这一点),因此对于systemd-journald,所有日志输出都具有原始父进程的凭据。

通过AF_LOCAL套接字在/run/systemd/journal/socket上生成的日志输出是通过数据报套接字(而不是流套接字)实现的,该套接字讲的是特殊的systemd-journald协议。这个套接字将使用SO_PASSCRED套接字选项使内核在发送的每个数据报中记录相同的信息,这是从每个数据报中提取通过systemd-journald发送的。

再读

  • getsockopt()。Linux程序员手册2017-09-15。
  • socket。Linux程序员手册2018-02-02
  • Jonathan de Boyne Pollard (2017)。local-stream-socket-accept。诺什指南。软件。
  • Jonathan de Boyne Pollard (2015年)。"环境变量“。UNIX客户机-服务器程序接口上的gen。经常给出答案。
票数 2
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/491416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档