Comment suivre les processus nouvellement créés sous Linux?


31

Je sais qu'avec psje peux voir la liste ou l'arborescence des processus en cours d'exécution dans le système. Mais ce que je veux réaliser, c'est "suivre" les nouveaux processus créés lors de l'utilisation de l'ordinateur.

Par analogie, lorsque vous utilisez tail -fpour suivre le nouveau contenu ajouté à un fichier ou à une entrée, je souhaite conserver une liste de suivi du processus en cours de création.

Est-ce même possible?

Réponses:


28

Si les kprobes sont activés dans le noyau, vous pouvez utiliser à execsnooppartir de perf-tools :

Dans le premier terminal:

% while true; do uptime; sleep 1; done

Dans un autre 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...

2
Pour les nouvelles versions du noyau (> = 4.17 si je comprends bien) sur x84_64, les outils de perf de Gregg ne fonctionnent plus - ils fonctionnent mais il n'y a aucun rapport car il instrument un appel inutilisé. Selon les commentaires de Gregg ailleurs, la bonne solution pour les noyaux> = 4.7, est d'utiliser l'implémentation BPF dans la collection de compilateurs BPF disponible ici: github.com/iovisor/bcc#tools et sur Ubuntu et les linux modernes comme bpfcc-tools.
Guss le

7

Le moyen le plus simple consiste à activer l'audit des appels système

Voir le lien suivant pour plus de détails ,

Quelqu'un connaît-il un moyen simple de surveiller le spawn du processus racine | Défaut de serveur

Si vous surveillez tous les processus, supprimez simplement la -F uid=0pièce

Les journaux sont écrits dans /var/log/audit/audit.log


Aucun de ces 3 liens ne répond à ma question. Les deux premiers visent à coder quelque chose pour résoudre ce problème et le dernier ne répond pas non plus. Ce que je demande, c'est une commande et non l'écriture d'un morceau de code
Pablo Matias Gomez

@ PabloMatíasGomez mis à jour
daisy

3

CONFIG_PROC_EVENTS=y

Exemple de session:

$ 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_EVENTSexpose les événements à l'espace utilisateur via une socket netlink .

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 adapté de: https://bewareofgeek.livejournal.com/2945.html

Je ne pense pas cependant que vous puissiez obtenir des données de processus telles que l'UID et les arguments de processus car exec_proc_eventcontient si peu de données: https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 Nous pourrions essayer de le lire immédiatement /proc, mais il y a un risque que le processus se termine et qu'un autre prenne son PID, il ne serait donc pas fiable.

Testé sur Ubuntu 17.10, qui a été CONFIG_PROC_EVENTS=yactivé par défaut.


2

Vous pouvez apparemment suivre un processus en utilisant strace. Si vous connaissez le PID du processus, vous pouvez faire:

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

Remarquez l' -finterrupteur. Il vous aidera à suivre les processus nouvellement créés qui sont des descendants du processus dont le PID a été utilisé dans la commande ci-dessus. Pour plus d'informations sur strace, consultez cette question.


Apparemment, vous vouliez vous attacher au processus d'initialisation, avec pid = 1, non? Malheureusement, cela ne fonctionne pas, je ne vois dans la sortie aucune création de nouveaux processus, et le nombre de lignes est de quelques dizaines, tandis que le pid actuel pour les nouveaux processus est passé par quelques centaines.
Hi-Angel

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.