FastNetMon

Thursday 7 January 2010

Аудит запуска процессов в Linux

Стоит задача - максимально оперативно получать pid ы всех вновь создаваемых процессов. Документации по сабжу я не нашел (плохо искал, скорее всего) и скатился до поисков в сорцах 2.6.30 ядра.

В файле "kernel/fork.c" при успешном форке процесса происходит вызов функции audit_finish_fork(p), которая реализована в файле "kernel/auditsc.c", а объявлена в "include/linux/audit.h" и там упомянуто следующее "audit.h -- Auditing support". Далее посредством Гугла узнаем, что эта подсистема читается спец утилитой auditd.

Также в процессе поиска более легкого способа решения задачи, чем audit натолкнулся на следующий вызовы в функции copy_process (kernel/fork.c), который реализован в файле drivers/connector/cn_proc.c:


proc_fork_connector(p);


Который выглядит вот так (внимание! это самый что ни на есть легкий и правильный способ решения задачи! Осталось научиться писать netlink клиентов; этот метод назовем "Коннектор" и обсудим в самом низу):

void proc_fork_connector(struct task_struct *task)
{
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
struct timespec ts;

if (atomic_read(&proc_event_num_listeners) < 1) return; msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
ev->what = PROC_EVENT_FORK;
ev->event_data.fork.parent_pid = task->real_parent->pid;
ev->event_data.fork.parent_tgid = task->real_parent->tgid;
ev->event_data.fork.child_pid = task->pid;
ev->event_data.fork.child_tgid = task->tgid;

memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
msg->ack = 0; /* not used */
msg->len = sizeof(*ev);
/* If cn_netlink_send() failed, the data is not sent */
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
}


Также у ядра обнаружен флаг CONFIG_AUDITSYSCALL который активирует следующее:

Enable low-overhead system-call auditing infrastructure that can be used independently or with another kernel subsystem, such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured.


Кстати, вот с рассылки:

On Friday 24 October 2008 18:43:34 Bruno Gustavo Wallauer wrote:
> I'm working on a system that needs a realtime process creation tool
> (using C programming), getting the pid ppid and path of the process.

Should be possible, but it requires a kernel patch to really be right. I think
the patch is landing in the RHEL5.3 kernel and 2.6.28. What it does is gives
2 event records on fork/clone.


Ставим (вариант для Debian):
apt-get install -y auditd


Запускаем сервис:
/etc/init.d/auditd start


Удаляем все правила:
auditctl -D


А вот здесь я нашел решение: http://www.mail-archive.com/linux-audit@redhat.com/msg02692.html

Добавляем правило для аудита системного вызова brk (слава тому чуваку с рассылки, это блэк меджик!):

auditctl -a entry,always -S brk -F 'a0=0'


К слову, a0 - это первый аргумент системного вызова brk и мы его приравниваем нулю.

Просматриваем список правил:
auditctl -l
LIST_RULES: entry,always a0=0 syscall=brk


В итоге на каждый запуск программ мы получаем:

type=SYSCALL msg=audit(1262819232.527:10840): arch=c000003e syscall=12 success=yes exit=8294400 a0=0 a1=0 a2=7fff3ed7e140 a3=7fff3edff000 items=0 ppid=31987 pid=31994 auid=4294967295 uid=1001 gid=1001 euid=1001 suid=1001 fsuid=1001 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=4294967295 comm="perl" exe="/usr/bin/perl" key=(null)
type=SYSCALL msg=audit(1262819232.527:10841): arch=c000003e syscall=12 success=yes exit=8294400 a0=0 a1=0 a2=0 a3=7f0928cfaa50 items=0 ppid=31987 pid=31994 auid=4294967295 uid=1001 gid=1001 euid=1001 suid=1001 fsuid=1001 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=4294967295 comm="perl" exe="/usr/bin/perl" key=(null)


Источник: рассылка audit

Коннектор

Как показало копание в исходниках, чтобы эта функция заработала необходимы следующие опции при сборке ядра:


CONNECTOR=y
PROC_EVENTS=y


Вот с комментариями по пунктам:

CONNECTOR
This is unified userspace <-> kernelspace connector working on top of the netlink socket protocol.
PROC_EVENTS
Provide a connector that reports process events to userspace. Send events such as fork, exec, id change (uid, gid, suid, etc), and exit.


А вот последовательность настроек для menuconfig - device drivers - "Connector - unified userspace <-> kernelspace linker" и включем его пробелом, чтобы стал * и чтобы внутри активировался "Report process events to userspace (NEW)".

Ну что же, придется пересобрать ядро :)

1 comment :

  1. Жаль что вариант с хуком вызова fork подменой записи в sys_call_table в ядре через LKM стал хаком (
    а то решение могло бы быть веселее )
    Круто, что нашел способ достичь цели ;-)

    ReplyDelete

Note: only a member of this blog may post a comment.