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)?
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.
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.
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.
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
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
- GitWeb: http://kernel.ubuntu.com/git?p=cking/forkstat.git
- Ogłoszenie: http://smackerelofopinion.blogspot.com/2014/03/forkstat-new-tool-to-trace-process.html
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).
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.
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ć.
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
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