¿Cómo puedo registrar todos los inicios de procesos en Linux?

55

Me gustaría obtener un registro de todos los procesos que se inician con el momento en que se iniciaron y los argumentos con los que se iniciaron. ¿Es esto posible en Linux?

Brandon DuRette
fuente

Respuestas:

43

Su punto de partida debe ser auditado.

Intenta algo como esto:

apt-get install auditd
auditctl -a task,always
ausearch -i -sc execve
Mikel
fuente
1
Recibo un error The audit system is disabled¿Dónde puedo habilitarlo?
Tombart
1
bueno, un problema podría resolverse chmod 0750 /sbin/audispdpero todavía no funciona (Debian Wheezy)
Tombart
se dice Unable to set audit pid, exitingpero supongo que el verdadero problema será que el sistema se está ejecutando en un contenedor LXC
Tombart
¿Cómo se integra la auditoría con systemd journald? ¿Se superponen sus funciones?
CMCDragonkai
Probé esto en un servidor en vivo y efectivamente lo maté, casi no respondo. Apenas logré eliminar esta regla y hacer que el servidor responda nuevamente
Shocker
10

Necesitaba hacer esto, excepto que (1) no necesitaba el tiempo y (2) solo estaba interesado en los procesos que se inician en un proceso determinado, y sus hijos y descendientes posteriores. Además, en el entorno que estaba usando, no fue posible conseguir auditdo accton, pero no había valgrind.

Prefije lo siguiente al proceso de interés en la línea de comando:

valgrind --trace-children=yes

La información que necesita estará en la salida del registro que se muestra en STDERR.

Evgeni Sergeev
fuente
3
Por defecto, valgrind se ejecuta con la memcheckherramienta. Para desactivar la herramienta y su registro correspondiente, y sólo imprimir la creación de nuevos comandos (además de la salida habitual de su programa), utilice el siguiente comando: valgrind --tool=none --trace-children=yes [command and args here]. Cada vez que se genera un subproceso, Valgrind registrará el comando completo, incluidos los argumentos que se le pasaron.
Rob W
6

Podrías usar snoopy para esto.

Es muy simple de instalar, y desde 2.x puede registrar datos arbitrarios (argumentos, variables ambientales, cwd, etc.).

Divulgación: Snoopy mantenedor aquí.

Bostjan Skufca
fuente
2

Puede ejecutar startmon y seguir su salida estándar, Ctrl-C cuando haya terminado. Aquí se explica cómo compilar y ejecutar startmon en distribuciones recientes derivadas 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

En Debian (y Ubuntu, etc.), la primera línea de lo anterior cambia a:

sudo apt-get install git cmake g++

Alternativamente, puede probar el execsnoopscript en perf-tools, vea esta respuesta . Por defecto, solo se muestran los primeros 8 argumentos (9 incluyendo el nombre del programa); puedes aumentar esto a través de

sudo ./execsnoop -a 16

Si no tiene acceso de root al sistema, lo mejor que puede hacer es seguir sondeando /procy esperar que detecte todo (lo que no hará), pero para completar, aquí hay una secuencia de comandos para hacerlo (he puesto la eliminación de duplicados para simplificar la salida): aunque esto no es tan bueno como rastrearlos correctamente con uno de los métodos anteriores, tiene la ligera ventaja de mostrar separadores sin ambigüedades entre los argumentos de la línea de comandos, en caso de que alguna vez necesite decirle al diferencia entre espacios dentro de un argumento y espacio entre argumentos. Este script es ineficiente ya que usa la CPU (bueno, uno de sus núcleos) el 100% del tiempo.

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

También puede parchear execsnooppara decirle más explícitamente qué argumento es cuál:grep -v sub.*arg < execsnoop > n && chmod +x n && mv n execsnoop

Silas S. Brown
fuente
1

CONFIG_FTRACEy a CONFIG_KPROBEStravés debrendangregg/perf-tools

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

En otro caparazón:

while true; do sleep 1; date; done

El primer shell muestra datos de formato:

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

Sesión de muestra:

$ 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_EVENTSexpone los eventos a userland a través de un socket de netlink .

proc_events.c adaptado 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 .

Sin embargo, no creo que pueda obtener datos de proceso como UID y argumentos de proceso porque exec_proc_eventcontiene muy pocos datos: https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 Podríamos intentar leerlo de inmediato /proc, pero existe el riesgo de que el proceso finalice y otro tome su PID, por lo que no sería confiable.

Probado en Ubuntu 17.10.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente
0

También puede usar encima para ver el uso de recursos por procesos. Estas son herramientas útiles para registrar y analizar el uso de recursos en cada parte del tiempo

Quarind
fuente
-3

Puedes probar cat ~/.bash_history Hay system log viewer, esto puede ayudarte.

Kracekumar
fuente
1
~/.bash_historysolo contiene comandos que he ejecutado en una terminal, aparentemente. Estoy buscando un registro de todos los programas ejecutados, por ejemplo, cuando hago clic en un icono para abrir mi cliente de correo electrónico, gedit, o abro mi navegador, y mi navegador ejecuta otro proceso por sí mismo. La respuesta de new123456 hizo el truco.
runeks 01 de
1
Agreguemos también que el comando historyes la forma habitual de acceder a esta información.
bryn