Откуда журналу известен PID процесса, который создает данные журнала?

Используйте ssh -A или установите эквивалент в вашем /etc/ssh/ssh_config файле (на вашей локальной машине:

 -A      Enables forwarding of the authentication agent connection.  This
         can also be specified on a per-host basis in a configuration
         file.

         Agent forwarding should be enabled with caution.  Users with the
         ability to bypass file permissions on the remote host (for the
         agent's UNIX-domain socket) can access the local agent through
         the forwarded connection.  An attacker cannot obtain key mate‐
         rial from the agent, however they can perform operations on the
         keys that enable them to authenticate using the identities
         loaded into the agent.

В вашем /etc/ssh/ssh_config вы должны добавить/установить:

ForwardAgent yes
2
29.12.2018, 08:25
2 ответа

Он получает pid через вспомогательные данные SCM_CREDENTIALSна сокете unix с помощью 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()из journald-server.c. Обе стандартные функции syslog(3)из libcи sd_journal_sendv()из libsystemdбудут отправлять свои данные через сокет SOCK_DGRAMпо умолчанию, а getsockopt(SO_PEERCRED)не работает с дейтаграммами (без установления соединения ). Ни systemd-journald, ни rsyslogdне принимают соединения SOCK_STREAMна /dev/log.

скм _доп.с

#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;
}

фейк.с

#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
27.01.2020, 21:58

Ядро сообщает об этом.

EUID, EGID и PID исходного клиентского процесса, который подключился к потоковому сокету AF_LOCALв /run/systemd/journal/stdout, доступны из ядра через параметр сокета SO_PEERCRED, , который он использует . UCSPI -Инструменты UNIX получают ту же информацию с помощью одного и того же системного вызова.

Дочерние сервисные процессы, конечно, наследуют свои стандартные файловые дескрипторы ввода-вывода, уже открытые (, если только родительский сервисный процесс не изменит это, конечно ), и поэтому 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 -Программный интерфейс сервера . Часто задаваемые ответы.
0
27.01.2020, 21:58

Теги

Похожие вопросы