Ответы:
Это звучит как идеальная работа для аудита. Запустив Audit, службу по умолчанию в современных системах на базе RedHat, вы можете создать правило, которое будет выполнять именно то, что вы хотите, выполнив
auditctl -a task,always -F uid=0
Нарушая это правило команды, чрезмерно используя man-страницу, мы находим, что:
-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"; } } }
Лучший способ, которым я могу придумать, это создать библиотеку Snoopy . snoopy - это очень небольшая разделяемая библиотека, которая подключается /etc/ld.so.preload
и обрабатывает execve()
системные вызовы. Это настраивается для регистрации всех exec()
или только из корня. В своем текущем воплощении snoopy регистрирует в syslog каждый раз, когда происходит соответствующее событие (системный вызов execve()
). Это небольшая программа (не более пары сотен строк кода), и ее можно изменить без особых трудностей для выполнения сценария вместо (или в дополнение к) регистрации действия. Снупи написан на C.
Несколько вещей, на которые стоит обратить внимание: