61 votes

Comment puis-je enregistrer tous les lancements de processus sous Linux ?

Je voudrais obtenir un journal de tous les processus qui sont lancés avec l'heure à laquelle ils ont été lancés et les arguments avec lesquels ils ont été lancés. Est-ce possible sous Linux ?

50voto

Mikel Points 8576

Votre point de départ devrait être auditd.

Essayez quelque chose comme ça :

apt-get install auditd
auditctl -a task,always
ausearch -i -sc execve

12voto

Evgeni Sergeev Points 1735

J'avais besoin de faire cela, sauf que (1) je n'avais pas besoin de temps et (2) je n'étais intéressé que par les processus qui sont lancés par un processus donné, et ses enfants et descendants ultérieurs. En outre, dans l'environnement que j'utilisais, il n'était pas possible d'obtenir auditd o accton mais il y avait valgrind .

Préfixez les éléments suivants au processus qui vous intéresse sur la ligne de commande :

valgrind --trace-children=yes

Les informations dont vous avez besoin se trouvent dans le journal affiché sur STDERR.

7voto

Vous pourriez utiliser snoopy pour ça.

Il est très simple à installer, et depuis la version 2.x il peut enregistrer des données arbitraires (arguments, variables d'environnement, cwd, etc.).

Divulgation : Snoopy maintainer ici.

3voto

Silas S. Brown Points 161

Vous pourriez lancer startmon et suivre sa sortie standard, Ctrl-C quand vous avez fini. Voici comment compiler et exécuter startmon sur les distributions récentes dérivées de Red Hat (RHEL, Fedora, CentOS) :

sudo yum install git cmake gcc-c++
git clone https://github.com/pturmel/startmon
cd startmon
cmake .
make
sudo ./startmon -e

Sous Debian (et Ubuntu, etc.), la première ligne de l'exemple ci-dessus se change en :

sudo apt-get install git cmake g++

Vous pouvez également essayer le execsnoop script dans perf-tools, voir cette réponse . Par défaut, seuls les 8 premiers arguments sont affichés (9 incluant le nom du programme) ; vous pouvez augmenter ce nombre via

sudo ./execsnoop -a 16

Si vous n'avez pas accès à la racine du système, le mieux que vous puissiez faire est de continuer à sonder /proc et espérer qu'il attrape tout (ce qui n'est pas le cas), mais pour être complet, voici un script pour le faire (j'ai mis la suppression des doublons pour simplifier la sortie) - bien que ce ne soit pas aussi bon que de les suivre correctement avec l'une des méthodes ci-dessus, il a le léger avantage d'afficher sans ambiguïté les séparateurs entre les arguments de la ligne de commande, au cas où vous auriez besoin de faire la différence entre les espaces à l'intérieur de un argument et un espace entre arguments. Ce script est inefficace car il utilise le CPU (enfin, un de ses cœurs) 100% du temps.

function pstail () { python -c 'import os
last=set(os.listdir("/proc")) ; o=x=""
while True:
 pids=set(os.listdir("/proc"))
 new=pids.difference(last);last=pids
 for n in new:
  try: o,x=x,[j for j in open("/proc/"+n+"/cmdline")
    .read().split(chr(0)) if j]
  except IOError: pass
  if x and not o==x: print n,x' ; }

pstail

Vous pouvez également rafistoler execsnoop pour vous indiquer plus explicitement quel argument est le bon : grep -v sub.*arg < execsnoop > n && chmod +x n && mv n execsnoop

2voto

CONFIG_FTRACE y CONFIG_KPROBES par le biais de brendangregg/perf-tools

git clone https://github.com/brendangregg/perf-tools.git
cd perf-tools
git checkout 98d42a2a1493d2d1c651a5c396e015d4f082eb20
sudo ./execsnoop

Sur un autre Shell :

while true; do sleep 1; date; done

Le premier Shell montre des données de format :

Tracing exec()s. Ctrl-C to end.                                                        
Instrumenting sys_execve                                                               
   PID   PPID ARGS 
 20109   4336 date                                                                                       
 20110   4336 sleep 1                                                                                    
 20111   4336 date                                                                                                                                                                                                 
 20112   4336 sleep 1                                                                                    
 20113   4336 date                                                                                       
 20114   4336 sleep 1                                                                                    
 20115   4336 date                                                                                       
 20116   4336 sleep 1

CONFIG_PROC_EVENTS

Exemple de session :

$ su
# ./proc_events &
# /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_EVENTS expose les événements à l'utilisateur via un prise netlink .

proc_events.c adapté de : https://bewareofgeek.livejournal.com/2945.html

#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 .

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_event contient 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 à partir de /proc mais il y a un risque que le processus se termine et qu'un autre prenne son PID, donc ce ne serait pas fiable.

Testé dans Ubuntu 17.10.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X