AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 491416
Accepted
炸鱼薯条德里克
炸鱼薯条德里克
Asked: 2018-12-29 21:51:03 +0800 CST2018-12-29 21:51:03 +0800 CST 2018-12-29 21:51:03 +0800 CST

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

  • 772

当我查看时journalctl,它会告诉我日志条目的 PID 和程序名称(或服务名称?)。

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

我应该阅读有关此的任何文档吗?

我阅读了 JdeBP 的答案并知道systemd-journald在 Unix Domian Socket 上侦听,但是即使可以知道发送日志消息的对等套接字地址,它如何知道 PID?如果该发送套接字被许多非父子进程打开怎么办?

ipc systemd-journald
  • 2 2 个回答
  • 1916 Views

2 个回答

  • Voted
  1. Best Answer
    mosvy
    2018-12-29T23:04:09+08:002018-12-29T23:04:09+08:00

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

    例子:

    $ cc -Wall scm_cred.c -o scm_cred
    $ ./scm_cred
    scm_cred: received from 10114: pid=10114 uid=2000 gid=2000
    

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

    # 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处理通过辅助数据发送的数据报和凭据在server_process_datagram()函数 from 中journald-server.c。默认情况下,syslog(3)标准函数 fromlibc和sd_journal_sendv()from都libsystemd将通过套接字发送数据,并且不适用于数据报(无连接)套接字。既不也不接受. _SOCK_DGRAMgetsockopt(SO_PEERCRED)systemd-journaldrsyslogdSOCK_STREAM/dev/log

    scm_cred.c

    #define _GNU_SOURCE     1
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    #include <err.h>
    
    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

    #define _GNU_SOURCE     1
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <err.h>
    
    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
  2. JdeBP
    2018-12-29T23:56:00+08:002018-12-29T23:56:00+08:00

    内核告诉它。

    AF_LOCAL连接流套接字的原始客户端进程的 EUID、EGID 和 PID/run/systemd/journal/stdout可通过内核使用的套接字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。
    • 乔纳森·德博因·波拉德 (2017)。local-stream-socket-accept. 小吃指南。软件。
    • 乔纳森·德博因·波拉德 (2015)。“环境变量”。 UNIX 客户端-服务器程序接口上的 gen。经常给出答案。
    • 1

相关问题

  • 如果我使用按单元过滤,为什么 journalctl 不显示日志消息?

  • 我可以屏蔽 systemd-journal-flush 服务并稍后手动运行 journalctl --flush 吗?

  • 处理消息队列中的多条消息

  • 以两种不同的方式处理 SIGALRM

  • 没有服务器的命令行 pub/sub?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve