Jak wykryć uruchamianie programów na Linuksie?

Napisałem prosty Demon. Ten Demon powinien odpowiedzieć, gdy uruchamiam jakikolwiek program. Jak to zrobić? W dużej pętli demona:

while(1)
{
   /* function which catches new programm running */
}

Jakie funkcje wywołać w Linuksie, gdy uruchamiam nowy program (create new process)?

 23

8 answers

Nie wiem, czy istnieje lepszy sposób, ale można okresowo skanować /proc system plików.

Na przykład, /proc/<pid>/exe jest dowiązaniem symbolicznym do pliku wykonywalnego procesu.

W moich systemach (Ubuntu/RedHat), /proc/loadavg zawiera liczbę uruchomionych procesów (liczbę po ukośniku) oraz pid ostatnio uruchomionego procesu. Jeśli twój Demon przepytuje plik, każda zmiana na którąkolwiek z dwóch liczb powie mu, kiedy będzie musiał ponownie zeskanować /proc w poszukiwaniu nowego procesy.

Nie jest to bynajmniej kuloodporne, ale jest najbardziej odpowiednim mechanizmem, jaki przychodzi mi do głowy.
 1
Author: NPE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-20 17:45:45

Dla Linuksa wydaje się, że w jądrze istnieje interfejs. Badając ten problem natknąłem się na ludzi używających CONFIG_CONNECTOR i CONFIG_PROC_EVENTS konfiguracji jądra, aby uzyskać zdarzenia na śmierć procesu.

Trochę Więcej google i znalazłem to:

Http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/

Filtry złączy i gniazd Proc Posted on Luty 9, 2011 by scott

Złącze proc jest jednym z te ciekawe funkcje jądra, z którymi większość ludzi rzadko się spotyka, a jeszcze rzadziej znajduje dokumentację. Podobnie filtr gniazd. Szkoda, ponieważ oba są naprawdę bardzo przydatnymi interfejsami, które mogłyby służyć różnym celom, gdyby były lepiej udokumentowane.

Złącze proc pozwala na otrzymywanie powiadomień o zdarzeniach procesu, takich jak wywołania fork i exec, a także o zmianach w uid, gid lub sid procesu (identyfikator sesji). Są one dostarczane za pośrednictwem interfejs oparty na gniazdach poprzez odczyt instancji struct proc_event zdefiniowanych w nagłówku jądra....

Nagłówek zainteresowania to:

#include <linux/cn_proc.h>

Znalazłem tutaj przykładowy kod:

Http://bewareofgeek.livejournal.com/2945.html

/* This file is licensed under the GPL v2 (http://www.gnu.org/licenses/gpl2.txt) (some parts was originally borrowed from proc events example)

pmon.c

code highlighted with GNU source-highlight 3.1
*/

#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>

/*
* connect to netlink
* returns netlink socket, or -1 on error
*/
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;
}

/*
* subscribe on proc events (process notifications)
*/
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;
}

/*
* handle a single process event
*/
static volatile bool need_exit = false;
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(int unused)
{
need_exit = true;
}

int main(int argc, const char *argv[])
{
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);
}

Odkryłem, że ten kod musi działać jako root, aby uzyskać powiadomienia.

 60
Author: David Crookes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-06 08:50:38

Chciałem dowiedzieć się, jak to zrobić bez sondaży. inotify () wydaje się nie działać na / proc, więc ten pomysł nie działa.

Jednak każdy program, który jest dynamicznie połączony, uzyska dostęp do określonych plików podczas uruchamiania, takich jak dynamiczny łącznik. Byłoby to bezużyteczne ze względów bezpieczeństwa, ponieważ nie uruchomi się na statycznie powiązanym programie, ale nadal może być interesujące: {]}

#include <stdio.h>
#include <sys/inotify.h>
#include <assert.h>
int main(int argc, char **argv) {
    char buf[256];
    struct inotify_event *event;
    int fd, wd;
    fd=inotify_init();
    assert(fd > -1);
    assert((wd=inotify_add_watch(fd, "/lib/ld-linux.so.2", IN_OPEN)) > 0);
    printf("Watching for events, wd is %x\n", wd);
    while (read(fd, buf, sizeof(buf))) {
      event = (void *) buf;
      printf("watch %d mask %x name(len %d)=\"%s\"\n",
         event->wd, event->mask, event->len, event->name);
    }
    inotify_rm_watch(fd, wd);
    return 0;
}

Wydarzenia, które drukuje, nie zawierają żadnych ciekawych informacji - pid procesu wyzwalania nie wydaje się być dostarczany przez inotify. Można go jednak użyć do wybudzenia i wywołania ponownego skanowania /proc

Należy również pamiętać, że krótkotrwałe programy mogą ponownie zniknąć, zanim to coś się obudzi i skończy skanowanie / proc-prawdopodobnie dowiesz się, że istniały, ale nie będziesz w stanie dowiedzieć się, czym były. I oczywiście każdy mógł ciągle otwierać i zamykać fd do dyanmic linker, aby utopić cię w hałasie.

 18
Author: Chris Stratton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-20 18:03:23

Spójrz na Ten mały program autorstwa Sebastiana Krahmera robi dokładnie to, o co prosisz w sposób efektywny pod względem zasobów i dość prosty kod.

Wymaga, aby twoje jądro miało włączone CONFIG_PROC_EVENTS, co nie ma miejsca na przykład w najnowszym obrazie Amazon Linux (2012.09).

Aktualizacja: po prośba do Amazon Jądra obrazów Amazon Linux obsługują teraz PROC_EVENTS

 10
Author: Arnaud Meuret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-23 16:20:37

Użyj forkstat, jest to najbardziej kompletny klient dla zdarzeń proc:

sudo forkstat -e exec,comm,core

Spakowane w Ubuntu, Debianie i AUR.


Wcześniej było cn_proc :

 bzr branch lp:~kees/+junk/cn_proc

Plik Makefile wymaga małej zmiany (LDLIBS zamiast LDFLAGS).

Cn_proc i exec-notify.C (które opublikował Arnaud) ma wspólnego przodka; cn_proc obsługuje jeszcze kilka zdarzeń i ma czystsze wyjście, ale nie jest odporny, gdy procesy szybko kończą pracę.


Ooh, znalazłem kolejny widelec exec-notify, extrace . Ten zapisuje procesy potomne poniżej ich rodzica (używając heurystyki pid_depth).

 9
Author: Tobu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-19 16:49:47

Słowo kluczowe dla wybranej wyszukiwarki to "process event connector".

Znalazłem dwa narzędzia, które je wykorzystują, exec-notify i cn_proc .

Bardziej lubię te późniejsze, ale obie wykonują swoją pracę bardzo dobrze.

 3
Author: Ikem Krueger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-04 00:29:44

Możesz albo przeskanować system operacyjny w poszukiwaniu programów, które pasują do twojego kryterium, albo poczekać, aż program zgłosi się do twojego demona. To, którą technikę wybierzesz, zależy w dużej mierze od tego, jak dużą kontrolę masz nad programami Nie-demonowymi.

Skanowanie moĹźe byÄ ‡ wykonane przez wywoĹ ' anie systemowe kernela lub przez odczyt przestrzeni uĹźytkownika reklamowanego kernela (tak jak w systemie plików /proc). Zauważ, że skanowanie nie jest gwarancją, że znajdziesz jakiś konkretny program, tak jakby program udaje się uruchomić i zakończyć między cyklami skanowania, nie zostanie wykryty w ogóle.

Bardziej skomplikowane techniki wykrywania procesów są możliwe, ale wymagają również bardziej skomplikowanych implementacji. Ważne jest, aby wiedzieć, co jest naprawdę potrzebne, zanim zaczniesz sięgać po rozwiązania egzotyczne (wstawianie sterowników jądra itp.), ponieważ wszystko, co robisz, nie jest niezależne od systemu, który monitorujesz; w rzeczywistości zmieniasz środowisko, obserwując go, a niektóre metody obserwowania środowiska mogą go niewłaściwie zmienić.

 0
Author: Edwin Buck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-20 16:51:17

CONFIG_FTRACE i CONFIG_KPROBES przez brendangregg/perf-tools

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

Na innej powłoce:

while true; do sleep 1; date; done

Pierwsza powłoka pokazuje dane w formacie:

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
 0
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-06 08:49:05