Linux에서 모든 프로세스 시작을 어떻게 기록 할 수 있습니까?


55

프로세스가 시작된 시간과 시작된 인수로 시작된 모든 프로세스의 로그를 얻고 싶습니다. 리눅스에서 가능합니까?

답변:


43

출발점을 감사해야합니다.

다음과 같이 해보십시오 :

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

1
오류가 발생했습니다. The audit system is disabled어디서 활성화 할 수 있습니까?
Tombart

1
하나의 문제는 해결 될 수 chmod 0750 /sbin/audispd있지만 여전히 작동하지 않습니다 (Debian Wheezy)
Tombart

말한다 Unable to set audit pid, exiting하지만 진짜 문제는 시스템이 LXC 컨테이너에서 실행되고 있는지 될 것 같아요
Tombart

감사는 시스템 저널링과 어떻게 통합됩니까? 기능이 겹치나요?
CMCDragonkai

나는 이것을 살아있는 서버에서 시도했고 효과적으로 그것을 죽였고 거의 응답하지 않았다. 나는이 규칙을 거의 제거하고 서버를 다시 응답하게 만들지 않았다
Shocker

10

나는 (1) 시간이 필요하지 않았으며 (2) 주어진 프로세스와 그 자식 및 후속 자손에 의해 시작된 프로세스에만 관심이 있다는 점을 제외 하고는이 작업을 수행해야했습니다. 또한, 내가 사용하고있는 환경에서 auditd또는 얻을 수 accton없었지만가있었습니다 valgrind.

명령 행에서 관심있는 프로세스 앞에 다음을 접 두부로 사용하십시오.

valgrind --trace-children=yes

필요한 정보는 STDERR에 표시된 로그 출력에 있습니다.


3
기본적으로 valgrind는 memcheck도구 와 함께 실행됩니다 . 도구 및 관련 로깅을 사용하지 않고 프로그램의 일반 출력 외에 새 명령 작성 만 인쇄하려면 다음 명령을 대신 사용하십시오 valgrind --tool=none --trace-children=yes [command and args here]. 하위 프로세스가 생성 될 때마다 Valgrind는 전달 된 인수를 포함하여 전체 명령을 기록합니다.
Rob W

6

스누피 를 사용할 수 있습니다 .

설치가 매우 간단하고 2.x부터는 임의의 데이터 (인수, 환경 변수, cwd 등)를 기록 할 수 있습니다.

공개 : 스누피 관리자.


2

startmon을 실행하고 완료되면 표준 출력 Ctrl-C를 따를 수 있습니다. 최근 Red Hat 파생 배포판 (RHEL, Fedora, CentOS)에서 startmon을 컴파일하고 실행하는 방법은 다음과 같습니다.

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

데비안 (및 우분투 등)에서 위의 첫 줄은 다음과 같이 변경됩니다.

sudo apt-get install git cmake g++

또는 execsnoopperf-tools에서 스크립트를 사용해보십시오 . 이 답변을 참조하십시오 . 기본적으로 처음 8 개의 인수 만 표시됩니다 (프로그램 이름을 포함하여 9 개). 당신은 이것을 통해 이것을 증가시킬 수 있습니다

sudo ./execsnoop -a 16

시스템에 대한 루트 액세스 권한이없는 경우 폴링을 유지 /proc하고 모든 것을 포착하기를 희망하는 것이 최선이지만 (완전히 여기에 대한 스크립트는 다음과 같습니다) 위의 방법 중 하나를 사용하여 올바르게 추적하는 것만 큼 좋지는 않지만 명령 줄 인수 사이에 구분 기호를 명확하게 표시하면 약간의 이점이 있습니다. 공간 차이 내부 인자와 공간 간의 인수. 이 스크립트는 CPU (핵심 중 하나)를 100 % 사용하므로 비효율적입니다.

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

execsnoop어떤 인수가 어떤 인수인지 더 명확하게 알려주기 위해 패치 할 수도 있습니다 .grep -v sub.*arg < execsnoop > n && chmod +x n && mv n execsnoop


1

CONFIG_FTRACE그리고 CONFIG_KPROBES통해brendangregg/perf-tools

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

다른 쉘에서 :

while true; do sleep 1; date; done

첫 번째 쉘은 다음 형식의 데이터를 보여줍니다.

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

샘플 세션 :

$ 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_EVENTSnetlink 소켓을 통해 이벤트를 userland에 노출합니다 .

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

때문에 나는 당신이 같은 UID 등의 공정 데이터 및 프로세스 인수를 얻을 수 있지만 생각하지 않는다 exec_proc_event그래서 약간의 데이터가 포함 https://github.com/torvalds/linux/blob/v4.16/include/uapi/linux/cn_proc .h # L80 에서 즉시 읽을 수는 /proc있지만 프로세스가 완료되고 다른 프로세스가 PID를 취할 위험이 있으므로 신뢰할 수 없습니다.

우분투 17.10에서 테스트되었습니다.


0

또한 프로세스 별 리소스 사용량을보기 위해 top 을 사용할 수 있습니다 . 이것은 각 시간의 자원 사용을 로깅하고 분석하는 데 유용한 도구입니다.


-3

당신이 시도 할 수 cat ~/.bash_history 있다 system log viewer, 이것은 당신을 도울 수 있습니다.


1
~/.bash_history터미널에서 실행 한 명령 만 포함합니다. 예를 들어 아이콘을 클릭하여 전자 메일 클라이언트를 열거 나 gedit을 열거 나 브라우저를 열 때 브라우저가 다른 프로세스를 자체적으로 실행하는 등 실행 된 모든 프로그램의 로그를 찾고 있습니다. new123456의 답변이 트릭을 수행했습니다.
runeks 2016 년

1
명령 history이이 정보에 액세스하는 일반적인 방법이라고 덧붙입니다.
bryn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.