Wie verfolge ich neu erstellte Prozesse unter Linux?

31

Ich weiß, dass psich mit die Liste oder den Baum der aktuellen Prozesse im System sehen kann. Was ich aber erreichen möchte, ist, den neuen Prozessen zu "folgen", die bei der Verwendung des Computers entstehen.

Analog dazu tail -fmöchte ich , wenn Sie den neuen Inhalten folgen, die an eine Datei oder eine Eingabe angehängt werden, eine Verfolgungsliste des Prozesses führen, der gerade erstellt wird.

Ist das überhaupt möglich?

Pablo Matias Gomez
quelle

Antworten:

28

Wenn kprobes im Kernel aktiviert sind, können Sie execsnoopvon perf-tools aus Folgendes verwenden :

Im ersten Terminal:

% while true; do uptime; sleep 1; done

In einem anderen Terminal:

% git clone https://github.com/brendangregg/perf-tools.git
% cd perf-tools
% sudo ./execsnoop
Tracing exec()s. Ctrl-C to end.
Instrumenting sys_execve
   PID   PPID ARGS
 83939  83937 cat -v trace_pipe
 83938  83934 gawk -v o=1 -v opt_name=0 -v name= -v opt_duration=0 [...]
 83940  76640 uptime
 83941  76640 sleep 1
 83942  76640 uptime
 83943  76640 sleep 1
 83944  76640 uptime
 83945  76640 sleep 1
^C
Ending tracing...
Kirill Spitsyn
quelle
2
Für neue Kernel-Versionen (> = 4,17, wenn ich das richtig verstehe) auf x84_64 funktionieren die Perf-Tools von Gregg nicht mehr - sie werden ausgeführt, aber es gibt überhaupt keine Berichte, da sie einen nicht verwendeten Aufruf anzeigen. Laut Greggs Kommentaren an anderer Stelle besteht die richtige Lösung für Kernel> = 4.7 darin, die BPF-Implementierung in der BPF-Compiler-Sammlung zu verwenden, die hier verfügbar ist: github.com/iovisor/bcc#tools und unter Ubuntu und modernen Linuxen wie bpfcc-tools.
Guss
7

Am einfachsten ist es, die Überwachung von Systemanrufen zu aktivieren

Siehe folgenden Link für Details following

Kennt jemand einen einfachen Weg, um Root-Prozess-Spawn zu überwachen? Serverfehler

Wenn Sie alle Prozesse überwachen, entfernen Sie einfach das -F uid=0Teil

Protokolle werden in geschrieben /var/log/audit/audit.log

Gänseblümchen
quelle
Keiner dieser 3 Links beantwortet meine Frage. Bei den ersten beiden geht es darum, etwas zu codieren, um dies zu beheben, und bei der letzten wird weder geantwortet noch. Was ich frage, ist über ein Kommando und kein Stück Code zu schreiben
Pablo Matias Gomez
@ PabloMatíasGomez aktualisiert
Daisy
3

CONFIG_PROC_EVENTS=y

Beispielsitzung:

$ su
# ./proc_events.out &
set mcast listen ok
# sleep 2 & sleep 1 &
fork: parent tid=48 pid=48 -> child tid=56 pid=56
fork: parent tid=48 pid=48 -> child tid=57 pid=57
exec: tid=57 pid=57
exec: tid=56 pid=56
exit: tid=57 pid=57 exit_code=0
exit: tid=56 pid=56 exit_code=0

CONFIG_PROC_EVENTSLegt die Ereignisse über einen Netlink-Socket für das Benutzerland offen .

proc_events.c

#define _XOPEN_SOURCE 700
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>
#include <signal.h>
#include <errno.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

static volatile bool need_exit = false;

static int nl_connect()
{
    int rc;
    int nl_sock;
    struct sockaddr_nl sa_nl;

    nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
    if (nl_sock == -1) {
        perror("socket");
        return -1;
    }
    sa_nl.nl_family = AF_NETLINK;
    sa_nl.nl_groups = CN_IDX_PROC;
    sa_nl.nl_pid = getpid();
    rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
    if (rc == -1) {
        perror("bind");
        close(nl_sock);
        return -1;
    }
    return nl_sock;
}

static int set_proc_ev_listen(int nl_sock, bool enable)
{
    int rc;
    struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
        struct nlmsghdr nl_hdr;
        struct __attribute__ ((__packed__)) {
            struct cn_msg cn_msg;
            enum proc_cn_mcast_op cn_mcast;
        };
    } nlcn_msg;

    memset(&nlcn_msg, 0, sizeof(nlcn_msg));
    nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
    nlcn_msg.nl_hdr.nlmsg_pid = getpid();
    nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;

    nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
    nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
    nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);

    nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;

    rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
    if (rc == -1) {
        perror("netlink send");
        return -1;
    }

    return 0;
}

static int handle_proc_ev(int nl_sock)
{
    int rc;
    struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
        struct nlmsghdr nl_hdr;
        struct __attribute__ ((__packed__)) {
            struct cn_msg cn_msg;
            struct proc_event proc_ev;
        };
    } nlcn_msg;
    while (!need_exit) {
        rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
        if (rc == 0) {
            /* shutdown? */
            return 0;
        } else if (rc == -1) {
            if (errno == EINTR) continue;
            perror("netlink recv");
            return -1;
        }
        switch (nlcn_msg.proc_ev.what) {
            case PROC_EVENT_NONE:
                printf("set mcast listen ok\n");
                break;
            case PROC_EVENT_FORK:
                printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n",
                        nlcn_msg.proc_ev.event_data.fork.parent_pid,
                        nlcn_msg.proc_ev.event_data.fork.parent_tgid,
                        nlcn_msg.proc_ev.event_data.fork.child_pid,
                        nlcn_msg.proc_ev.event_data.fork.child_tgid);
                break;
            case PROC_EVENT_EXEC:
                printf("exec: tid=%d pid=%d\n",
                        nlcn_msg.proc_ev.event_data.exec.process_pid,
                        nlcn_msg.proc_ev.event_data.exec.process_tgid);
                break;
            case PROC_EVENT_UID:
                printf("uid change: tid=%d pid=%d from %d to %d\n",
                        nlcn_msg.proc_ev.event_data.id.process_pid,
                        nlcn_msg.proc_ev.event_data.id.process_tgid,
                        nlcn_msg.proc_ev.event_data.id.r.ruid,
                        nlcn_msg.proc_ev.event_data.id.e.euid);
                break;
            case PROC_EVENT_GID:
                printf("gid change: tid=%d pid=%d from %d to %d\n",
                        nlcn_msg.proc_ev.event_data.id.process_pid,
                        nlcn_msg.proc_ev.event_data.id.process_tgid,
                        nlcn_msg.proc_ev.event_data.id.r.rgid,
                        nlcn_msg.proc_ev.event_data.id.e.egid);
                break;
            case PROC_EVENT_EXIT:
                printf("exit: tid=%d pid=%d exit_code=%d\n",
                        nlcn_msg.proc_ev.event_data.exit.process_pid,
                        nlcn_msg.proc_ev.event_data.exit.process_tgid,
                        nlcn_msg.proc_ev.event_data.exit.exit_code);
                break;
            default:
                printf("unhandled proc event\n");
                break;
        }
    }

    return 0;
}

static void on_sigint(__attribute__ ((unused)) int unused)
{
    need_exit = true;
}

int main()
{
    int nl_sock;
    int rc = EXIT_SUCCESS;

    signal(SIGINT, &on_sigint);
    siginterrupt(SIGINT, true);
    nl_sock = nl_connect();
    if (nl_sock == -1)
        exit(EXIT_FAILURE);
    rc = set_proc_ev_listen(nl_sock, true);
    if (rc == -1) {
        rc = EXIT_FAILURE;
        goto out;
    }
    rc = handle_proc_ev(nl_sock);
    if (rc == -1) {
        rc = EXIT_FAILURE;
        goto out;
    }
    set_proc_ev_listen(nl_sock, false);
out:
    close(nl_sock);
    exit(rc);
}

GitHub-Upsatream , Code angepasst von: https://bewareofgeek.livejournal.com/2945.html

Ich glaube jedoch nicht, dass Sie Prozessdaten wie UID und Prozessargumente abrufen können, da diese exec_proc_eventso wenig Daten enthalten: https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 Wir könnten versuchen, es sofort zu lesen /proc, aber es besteht die Gefahr, dass der Prozess beendet wird und ein anderer seine PID erhält, so dass es nicht zuverlässig ist.

Getestet unter Ubuntu 17.10, das CONFIG_PROC_EVENTS=ystandardmäßig aktiviert ist.

Ciro Santilli ist ein Schauspieler
quelle
2

Sie können anscheinend einen Prozess mit verfolgenstrace . Wenn Sie die PID des Prozesses kennen, können Sie Folgendes tun:

strace -o strace-<pid>.out -f -p <pid>

Beachten Sie den -fSchalter. Es wird Ihnen helfen, neu erstellten Prozessen zu folgen, die Nachkommen des Prozesses sind, dessen PID im obigen Befehl verwendet wurde. Informationen zu strace finden Sie in dieser Frage.

tejus
quelle
Anscheinend wollten Sie sich mit pid = 1 an den init-Prozess binden, oder? Leider funktioniert es nicht, ich sehe in der Ausgabe keine Erstellung neuer Prozesse und die Anzahl der Zeilen beträgt einige Dutzend, während die aktuelle PID für neue Prozesse einige Hundert durchlief.
Hi-Angel