GNU/Linux >> Znalost Linux >  >> Linux

Jak zjistit spouštění programů na Linuxu?

Zajímalo mě pokusit se přijít na to, jak to udělat bez hlasování. Zdá se, že inotify() nefunguje na /proc, takže tento nápad je mimo.

Každý program, který je dynamicky propojen, však při spuštění získá přístup k určitým souborům, jako je například dynamický linker. To by bylo z bezpečnostních důvodů k ničemu, protože se nespustí u staticky propojeného programu, ale přesto by to mohlo být zajímavé:

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

Události, které se vytisknou, neobsahují žádné zajímavé informace – nezdá se, že by inotify poskytoval pid spouštěcího procesu. Lze jej však použít k probuzení a spuštění opětovného skenování /proc

Uvědomte si také, že programy s krátkou životností mohou znovu zmizet, než se tato věc probudí a dokončí skenování /proc - pravděpodobně byste se dozvěděli, že existovaly, ale nebudete schopni zjistit, co byly. A samozřejmě by kdokoli mohl pořád jen otevírat a zavírat fd do dynamického linkeru, aby vás utopil v hluku.


Zdá se, že pro Linux existuje rozhraní v jádře. Při zkoumání tohoto problému jsem narazil na lidi, kteří používají konfiguraci jádra CONFIG_CONNECTOR a CONFIG_PROC_EVENTS k získávání událostí při smrti procesu.

Ještě google a našel jsem toto:

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

The Proc Connector and Socket FiltersZveřejněno dne 9. února 2011 Scott

Konektor proc je jednou z těch zajímavých funkcí jádra, se kterou se většina lidí setká jen zřídka a ještě vzácněji na ní najde dokumentaci. Stejně tak zásuvkový filtr. To je škoda, protože obě jsou opravdu velmi užitečná rozhraní, která by mohla sloužit různým účelům, pokud by byla lépe zdokumentována.

Konektor proc vám umožňuje přijímat oznámení o událostech procesu, jako jsou volání fork a exec, a také změny v uid, gid nebo sid procesu (id relace). Ty jsou poskytovány prostřednictvím rozhraní založeného na soketu čtením instancí struct proc_event definované v hlavičce jádra....

Zájmové záhlaví je:

#include <linux/cn_proc.h>

Příklad kódu jsem našel zde:

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);
}

Zjistil jsem, že tento kód musí být spuštěn jako root, aby mohl dostávat oznámení.


Linux
  1. Jak používat Linuxový příkaz grep

  2. Jak se Linux dostal k sálovému počítači

  3. Jak nastavit IP adresu z C v linuxu

  1. Jak používat příkaz historie v Linuxu

  2. Jak ladit programy C v Linuxu pomocí gdb

  3. Jak změnit identitu systému Linux

  1. Jak používat příkaz historie Linuxu

  2. Jak získat počet CPU v Linuxu pomocí C?

  3. Jak získat cestu k aktuálnímu souboru (pwd) v Linuxu z C?