Comment enregistrer tous les lancements de processus sous Linux?

55

Je voudrais obtenir un journal de tous les processus qui sont lancés avec le moment où ils ont été lancés et les arguments avec lesquels ils ont été lancés. Est-ce possible sous Linux?

Brandon DuRette
la source

Réponses:

43

Votre point de départ devrait être audité.

Essayez quelque chose comme ça:

apt-get install auditd
auditctl -a task,always
ausearch -i -sc execve
Mikel
la source
1
Je reçois une erreur The audit system is disabledOù puis-je l'activer?
Tombart
1
Un problème pourrait être résolu chmod 0750 /sbin/audispdmais il ne fonctionne toujours pas (Debian Wheezy)
Tombart
est dit Unable to set audit pid, exitingmais je suppose que le vrai problème sera que le système fonctionne dans un conteneur LXC
Tombart
Comment l'audit s'intègre-t-il à systemd journald? Est-ce que leurs fonctions se chevauchent?
CMCDragonkai
J'ai essayé cela sur un serveur en direct et je l'ai effectivement tué, il est devenu presque insensible. J'ai à peine réussi à supprimer cette règle et à rendre le serveur réactif
Shocker
10

J'avais besoin de le faire, sauf que (1) je n'avais pas besoin de temps et (2) que je m'intéressais uniquement aux processus démarrés par un processus donné, ainsi qu'à ses enfants et à ses descendants. De plus, dans l'environnement que j'utilisais, il n'était pas possible d'obtenir auditdou accton, mais il y en avait valgrind.

Préfixez ce qui suit au processus d’intérêt sur la ligne de commande:

valgrind --trace-children=yes

Les informations dont vous avez besoin seront dans la sortie du journal affichée sur STDERR.

Evgeni Sergeev
la source
3
Par défaut, valgrind s'exécute avec l' memcheckoutil. Pour désactiver l'outil et son lien avec le journal, et seulement imprimer la création de nouvelles commandes (en plus de la sortie habituelle de votre programme), utilisez la commande suivante à la place: valgrind --tool=none --trace-children=yes [command and args here]. Chaque fois qu'un sous-processus est généré, Valgrind enregistre ensuite la commande complète, y compris les arguments qui lui ont été transmis.
Rob W
6

Vous pouvez utiliser snoopy pour cela.

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: mainteneur Snoopy ici.

Bostjan Skufca
la source
2

Vous pouvez exécuter startmon et suivre sa sortie standard, Ctrl-C lorsque vous avez terminé. Voici comment compiler et exécuter startmon sur des 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

Sur Debian (et Ubuntu, etc.), la première ligne de ce qui précède devient:

sudo apt-get install git cmake g++

Sinon, vous pouvez essayer le execsnoopscript dans perf-tools, voir cette réponse . Par défaut, seuls les 8 premiers arguments sont affichés (9 avec le nom du programme); vous pouvez augmenter cela via

sudo ./execsnoop -a 16

Si vous n'avez pas d'accès root au système, le mieux que vous puissiez faire est de continuer à interroger /procet d'espérer qu'il capture tout (ce qui ne sera pas le cas), mais pour être complet, voici un script permettant de le faire (j'ai mis la suppression des doublons). pour simplifier la sortie) - bien que ce ne soit pas aussi efficace que de les suivre correctement avec l’une des méthodes ci-dessus, cela présente le léger avantage d’afficher sans équivoque des séparateurs entre les arguments de ligne de commande, au cas où vous auriez besoin de dire la différence entre les espaces à l' intérieur d' un argument et l'espace entre les arguments. Ce script est inefficace car il utilise le processeur (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 aussi patcher execsnooppour vous dire plus explicitement quel argument est lequel:grep -v sub.*arg < execsnoop > n && chmod +x n && mv n execsnoop

Silas S. Brown
la source
1

CONFIG_FTRACEet à CONFIG_KPROBEStraversbrendangregg/perf-tools

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

Sur une autre coquille:

while true; do sleep 1; date; done

Le premier shell affiche les 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_EVENTSexpose les événements à l'utilisateur via un socket 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);
}

Upsatream GitHub .

Je ne pense toutefois pas que vous puissiez obtenir des données de processus telles que l'UID et les arguments de processus, car elles exec_proc_eventcontiennent 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 soit terminé et qu'un autre ait pris son PID, de sorte qu'il ne serait pas fiable.

Testé sous Ubuntu 17.10.

Ciro Santilli 改造 中心 六四 事件
la source
0

Vous pouvez également utiliser atop pour afficher l'utilisation des ressources par processus. Ce sont des outils utiles pour enregistrer et analyser l'utilisation des ressources à chaque instant

Quarind
la source
-3

Vous pouvez essayer cat ~/.bash_history Il y a system log viewer, cela peut vous aider.

Kracekumar
la source
1
~/.bash_historyne contient apparemment que des commandes que j'ai exécutées dans un terminal. Je recherche un journal de tous les programmes exécutés, par exemple lorsque je clique sur une icône pour ouvrir mon client de messagerie, gedit ou mon navigateur, et que ce dernier exécute lui-même un autre processus. La réponse de new123456 a fait l'affaire.
Runeks
1
Ajoutons également que la commande historyest le moyen habituel d'accéder à cette information.
Bryry