Кто-нибудь знает простой способ мониторинга порождения корневого процесса
Я хочу выполнить скрипт, когда появляется новый корневой процесс. (на Linux) Как я могу просто сделать это?
Спасибо
3 ответа
Это звучит как идеальная работа для аудита. Запустив Audit, службу по умолчанию в современных системах на базе RedHat, вы можете создать правило, которое будет выполнять именно то, что вы хотите, выполнив
auditctl -a task,always -F uid=0
Нарушая это правило команды, чрезмерно используя страницу руководства, мы находим, что:
-a list,action task Add a rule to the per task list. This rule list is used only at the time a task is created -- when fork() or clone() are called by the parent task. When using this list, you should only use fields that are known at task creation time, such as the uid, gid, etc. always Allocate an audit context, always fill it in at syscall entry time, and always write out a record at syscall exit time.
Поэтому всегда записывайте запись для этого действия всякий раз, когда завершается системный вызов fork или clone.
Последний вариант может рассматриваться как строка фильтра, в нашем использовании -F uid=0
просто ограничивает нас случаями, когда uid владельца процесса равен 0.
Обратите внимание, что это правило можно выполнить во время выполнения, убедившись, что audit правильно настроен, и добавив правило-a task,always -F uid=0
в соответствующий файл для вашего дистрибутива, скорее всего /etc/audit/audit.rules
Просто имейте в виду, что это будет чертовски шумно, и кто бы ни делал ваши обзоры журналов, он должен быть готов к этому.
Я не думаю, что есть чистый способ сделать это без перекомпиляции вашего ядра с CONFIG_PROC_EVENTS и / или CONFIG_KPROBES (хотя я хотел бы знать, есть ли способ сделать это, поэтому я поставил ваш вопрос на голосование).
У меня была идея использовать iwatch/inotify для создания каталога внутри /proc, но, похоже, это не сработало, как и audctl. Похоже, что ваш лучший выбор, хотя и грязный, это постоянно анализировать ps на предмет изменений в скрипте. Следующий код на Perl сделает это, хотя будет склонен пропускать некоторые и игнорировать ps
(так как иначе это сработало бы):
perl -e 'my %pids; while(1) { my @pids = `ps -U root -u root`; foreach (@pids) { next if /ps$/; ($pid) = /^\s*(\d+)\D/; if (!$pids{$pid}) { $pids{$pid}++; print "Process $pid created (" . `cat /proc/$pid/cmdline` . ")\n"; } } }
Вы можете сделать это с помощью exec-snoop (на основе ebpf), точек трассировки, аудита, коннектора процесса netlink и некоторых других механизмов. Я написал здесь сравнение всех методов.
Лучший способ, которым я могу придумать, это создать библиотеку Snoopy. snoopy - очень маленькая общая библиотека, которая подключается к /etc/ld.so.preload
и обвивает execve()
системные вызовы. Это настраивается, чтобы войти все exec()
или просто от root. В своем текущем воплощении snoopy регистрирует в системном журнале каждый раз, когда происходит соответствующее событие (системный вызов для execve()
) бывает. Это небольшая программа (не более пары сотен строк кода), и ее можно изменить без особых трудностей, чтобы выполнить сценарий вместо (или в дополнение к) регистрации действия. Снупи написан на C.
Несколько вещей, на которые стоит обратить внимание:
- Если вы запускаете скрипт каждый раз, когда запускается корневой процесс, ваш сценарий будет корневым процессом, который должен будет снова запустить сценарий, который будет другим корневым процессом и т. Д. Будьте осторожны, чтобы не попасть в цикл там.
- В типичном Linux-боксе есть много процессов, которые запускаются от имени root и регулярно создаются. Например, cron может порождать системные cronjobs как root каждую минуту или несколько минут. Если вы просто ожидаете, что это произойдет, когда пользователь войдет в систему как root, это будет больше работы.