Làm thế nào để theo dõi các quy trình mới được tạo trong Linux?


31

Tôi biết rằng với pstôi có thể thấy danh sách hoặc cây của các quy trình hiện tại đang chạy trong hệ thống. Nhưng điều tôi muốn đạt được là "làm theo" các quy trình mới được tạo ra khi sử dụng máy tính.

Tương tự như vậy, khi bạn sử dụng tail -fđể theo dõi các nội dung mới được thêm vào một tệp hoặc bất kỳ đầu vào nào, thì tôi muốn giữ một danh sách theo dõi quá trình hiện đang được tạo.

Điều này thậm chí có thể nhìn thấy?

Câu trả lời:


28

Nếu kprobes được bật trong kernel, bạn có thể sử dụng execsnooptừ perf-tools :

Trong thiết bị đầu cuối đầu tiên:

% while true; do uptime; sleep 1; done

Trong một thiết bị đầu cuối khác:

% 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
Đối với các phiên bản kernel mới (> = 4.17 nếu tôi hiểu chính xác) trên x84_64, các công cụ hoàn hảo của Gregg không còn hoạt động nữa - chúng chạy nhưng không có báo cáo nào cả vì đây là một cuộc gọi không sử dụng. Theo ý kiến của Gregg nơi khác, giải pháp đúng cho kernel> = 4.7, là sử dụng triển khai BPF trong Compiler Collection BPF sẵn ở đây: github.com/iovisor/bcc#tools và trên Ubuntu và linuxes hiện đại như bpfcc-tools.
Guss

7

Cách dễ nhất là cho phép kiểm tra cuộc gọi hệ thống

Xem liên kết sau để biết chi tiết

Có ai biết một cách đơn giản để theo dõi quá trình root sinh sản | Lỗi máy chủ

Nếu bạn đang theo dõi tất cả các quy trình, chỉ cần loại bỏ -F uid=0phần

Nhật ký được ghi vào /var/log/audit/audit.log


Không ai trong số 3 liên kết trả lời câu hỏi của tôi. Hai cái đầu tiên là về mã hóa một cái gì đó để giải quyết điều này và cái cuối cùng không trả lời. Những gì tôi đang hỏi là về một số lệnh và không viết một số đoạn mã
Pablo Matias Gomez

@ PabloMatíasGomez được cập nhật
daisy

3

CONFIG_PROC_EVENTS=y

Phiên mẫu:

$ 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_EVENTShiển thị các sự kiện cho người dùng thông qua một ổ cắm 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 upatream , mã được điều chỉnh từ: https : //bnterestofgeek.livejournal.com/2945.html

Tuy nhiên, tôi không nghĩ rằng bạn có thể nhận được dữ liệu xử lý như UID và xử lý các đối số vì exec_proc_eventchứa quá ít dữ liệu: https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 Chúng tôi có thể cố gắng đọc nó ngay lập tức /proc, nhưng có một rủi ro là quá trình đã kết thúc và một quá trình khác đã thực hiện PID của nó, vì vậy nó sẽ không đáng tin cậy.

Đã thử nghiệm trên Ubuntu 17.10, CONFIG_PROC_EVENTS=yđược bật theo mặc định.


2

Bạn rõ ràng có thể làm theo một quá trình sử dụng strace. Nếu bạn biết PID của quá trình thì bạn có thể làm:

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

Chú ý công -ftắc. Nó sẽ giúp bạn theo dõi các quy trình mới được tạo ra là hậu duệ của quy trình có PID được sử dụng trong lệnh ở trên. Để biết thông tin về strace xem câu hỏi này .


Rõ ràng bạn có ý định gắn vào quá trình init, với pid = 1, phải không? Thật không may, nó không hoạt động, tôi không thấy trong đầu ra bất kỳ quá trình tạo mới nào và số lượng dòng là vài chục, trong khi giá trị hiện tại cho các quy trình mới đã trải qua vài trăm.
Hi-Angel

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.