Bagaimana cara melacak proses yang baru dibuat di Linux?

31

Saya tahu bahwa dengan pssaya dapat melihat daftar atau pohon dari proses saat ini berjalan di sistem. Tetapi yang ingin saya capai adalah "mengikuti" proses baru yang dibuat saat menggunakan komputer.

Sebagai analogi, ketika Anda menggunakan tail -funtuk mengikuti konten baru yang ditambahkan ke file atau input apa pun, maka saya ingin menyimpan daftar tindak dari proses yang saat ini sedang dibuat.

Apakah ini bahkan mungkin?

Pablo Matias Gomez
sumber

Jawaban:

28

Jika kprobes diaktifkan di kernel yang dapat Anda gunakan execsnoopdari perf-tools :

Di terminal pertama:

% while true; do uptime; sleep 1; done

Di terminal lain:

% 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
sumber
2
Untuk versi kernel baru (> = 4.17 jika saya mengerti dengan benar) pada x84_64, alat-alat Gregg tidak lagi berfungsi - mereka berjalan tetapi tidak ada laporan sama sekali karena ia menggunakan panggilan yang tidak digunakan. Menurut komentar Gregg di tempat lain, solusi yang tepat untuk kernel> = 4.7, adalah dengan menggunakan implementasi BPF dalam Koleksi Kompiler BPF yang tersedia di sini: github.com/iovisor/bcc#tools dan di Ubuntu dan linux modern sebagai bpfcc-tools.
Guss
7

Cara termudah adalah mengaktifkan audit panggilan sistem

Lihat tautan berikut untuk perinciannya ,

Adakah yang tahu cara sederhana untuk memantau proses root spawn | Kesalahan Server

Jika Anda memantau semua proses, hapus saja -F uid=0bagian itu

Log ditulis untuk /var/log/audit/audit.log

bunga aster
sumber
Tidak satu pun dari ketiga tautan itu yang menjawab pertanyaan saya. Dua yang pertama adalah tentang mengkode sesuatu untuk menyelesaikan ini dan yang terakhir tidak menjawab keduanya. Apa yang saya tanyakan adalah tentang beberapa perintah dan tidak menulis beberapa kode
Pablo Matias Gomez
@ PabloMatíasGomez diperbarui
daisy
3

CONFIG_PROC_EVENTS=y

Sesi sampel:

$ 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_EVENTSmemaparkan acara ke userland melalui soket 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 , kode diadaptasi dari: https://bewareofgeek.livejournal.com/2945.html

Namun saya tidak berpikir bahwa Anda dapat memperoleh data proses seperti UID dan memproses argumen karena exec_proc_eventmengandung data yang sangat sedikit: https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 Kita dapat mencoba untuk segera membacanya /proc, tetapi ada risiko bahwa proses selesai dan yang lain mengambil PID-nya, sehingga tidak dapat diandalkan.

Diuji pada Ubuntu 17.10, yang telah CONFIG_PROC_EVENTS=ydiaktifkan secara default.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
2

Anda tampaknya dapat mengikuti proses menggunakan strace. Jika Anda mengetahui PID proses maka Anda dapat melakukan:

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

Perhatikan -fsakelar. Ini akan membantu Anda untuk mengikuti proses yang baru dibuat yang merupakan keturunan dari proses yang PID digunakan dalam perintah di atas. Untuk informasi tentang strace lihat pertanyaan ini .

tejus
sumber
Tampaknya Anda bermaksud untuk melampirkan ke proses init, dengan pid = 1, kan? Sayangnya itu tidak berfungsi, saya tidak melihat dalam output penciptaan proses baru, dan jumlah baris adalah beberapa lusin, sementara pid saat ini untuk proses baru melewati beberapa ratus.
Hi-Angel