Как заставить dtrace запускать отслеживаемую команду с привилегиями non-root?
OS X не хватает linux strace
, но имеет dtrace
, который должен быть намного лучше.
Тем не менее, я пропускаю возможность простейшего отслеживания по отдельным командам. Например, в linux я могу написать strace -f gcc hello.c
для caputre всех системных вызовов, что дает мне список всех имен файлов, необходимых компилятору для компиляции моей программы (отличный memoize script построен на этом трюке)
Я хочу переносить memoize на mac, поэтому мне нужен какой-то strace
. Мне действительно нужен список файлов gcc
для чтения и записи, поэтому мне нужно больше truss
. Конечно, я могу сказать dtruss -f gcc hello.c
и получить несколько ту же функциональность, но тогда компилятор запускается с привилегиями root, что явно нежелательно (кроме огромного риска для безопасности, одна проблема заключается в том, что файл a.out
теперь принадлежит root: -)
Затем я попробовал dtruss -f sudo -u myusername gcc hello.c
, но это кажется немного неправильным и не работает в любом случае (я все время не получаю файл a.out
, не знаю, почему)
Вся эта длинная история пытается мотивировать мой первоначальный вопрос: как мне получить dtrace
для запуска моей команды с обычными пользовательскими привилегиями, точно так же, как strace
делает в linux?
Изменить: кажется, что я не единственный, кто задается вопросом, как это сделать: вопрос # 1204256 в значительной степени похож на мой (и имеет тот же субоптимальный ответ sudo:-)
Ответы
Ответ 1
Не ответ на ваш вопрос, но что-то знать. OpenSolaris решил эту проблему (частично) с помощью "привилегий" - см. эту страницу. Даже в OpenSolaris было бы невозможно разрешить пользователю без каких-либо дополнительных привилегий обрабатывать собственный процесс.
Причина в том, как работает dtrace - он позволяет зонды в ядре. Таким образом, позволяя не-привилегированному пользователю исследовать ядро, пользователь может делать много нежелательных вещей, например. sniffing другого пользователя passwd путем включения зондов в драйвере клавиатуры!
Ответ 2
Самый простой способ - использовать sudo:
sudo dtruss -f sudo -u $USER whoami
Другим решением было бы сначала запустить отладчик и контролировать новые конкретные процессы.
Например.
sudo dtruss -fn whoami
Затем в другом терминале просто запустите:
whoami
Просто как это.
Более сложные аргументы вы найдете в руководстве: man dtruss
В качестве альтернативы вы можете подключить dtruss к запущенному пользовательскому процессу, например. на Mac:
sudo dtruss -fp PID
или аналогичный в Linux/Unix с помощью strace:
sudo strace -fp PID
Другой хакерский трюк может состоять в том, чтобы выполнить команду и сразу после этого присоединить к процессу. Вот несколько примеров:
sudo true; (./Pages &); sudo dtruss -fp `pgrep -n -x Pages`
sudo true; (sleep 1 &); sudo dtruss -fp `pgrep -n -x sleep`
sudo true; (tail -f /var/log/system.log &); sudo dtruss -fp `pgrep -n -x tail`
Примечание:
-
первый sudo предназначен только для кэширования пароля при первом запуске,
-
этот трюк не работает для быстрых командных строк, таких как ls, date
, так как требуется некоторое время, пока отладчик не присоединяется к процессу,
-
вам нужно ввести команду в двух местах,
-
вы можете игнорировать &
, чтобы запустить процесс в фоновом режиме, если он уже делает это,
-
после завершения отладки вам придется вручную убить фоновый процесс (например, killall -v tail
)
Ответ 3
Аргумент -n
для dtruss
заставит dtruss ждать и проверять процессы, соответствующие аргументу -n
. Опция -f
будет по-прежнему работать, чтобы следить за процессами, вызванными процессами, согласованными с -n
.
Все это означает, что если вы хотите обработать процесс (ради аргумента, скажем, whoami
), выполняемого как ваш непривилегированный пользователь, выполните следующие действия:
- Откройте корневую оболочку
- Выполнить
dtruss -fn whoami
- это будет сидеть и ждать процесса с именем "whoami" для существования
- Откройте непривилегированную оболочку
- Выполнить
whoami
- это будет выполняться и нормально работать
- Соблюдайте трассировку системного вызова в окне dtruss.
- dtruss не выйдет сам по себе - он будет продолжать ждать совпадения процессов - так выйдет из него, когда вы закончите
Этот ответ дублирует последнюю часть ответа @kenorb, но он заслуживает того, чтобы быть первоклассным ответом.
Ответ 4
Я не знаю, можете ли вы заставить dtruss быть неинвазивным, как strace.
Вариант "sudo [to root] dtruss sudo [back to nonroot] cmd", который, кажется, работает лучше в некоторых быстрых тестах для меня:
sudo dtruss -f su -l `whoami` cd `pwd` && cmd....
Внешнее sudo, конечно же, dtruss работает как root.
Внутреннее su возвращается ко мне, а с -l оно воссоздает среду должным образом, после чего нам нужно вернуться к тому, с чего мы начали.
Я думаю, что "su -l user" лучше, чем "sudo -u user", если вы хотите, чтобы среда была тем, что обычно получает пользователь. Однако это будет их среда входа; Я не знаю, есть ли хороший способ позволить среде наследовать через два пользовательских изменения.
В вашем вопросе еще одна жалоба, которую вы описали об обходном решении sudo dtruss sudo, кроме уродства, заключалась в том, что "я не получаю никакого файла a.out на все это время, не знаю, почему". Я тоже не знаю, почему, но в моем маленьком тесте script вариант sudo dtruss sudo также не удалось записать в тестовый выходной файл, а вариант "sudo dtruss su" выше создал выходной файл.
Ответ 5
Кажется, что OS X не поддерживает использование dtrace для репликации всех функций strace, которые вам нужны. Тем не менее, я предлагаю попробовать создать обертку вокруг подходящих системных вызовов. Похоже, DYLD_INSERT_LIBRARIES - это переменная среды, которую вы хотите взломать. Это в основном то же самое, что и LD_PRELOAD
для Linux.
Более простой способ выполнения переопределений библиотечных функций - использование Переменная среды DYLD_INSERT_LIBRARIES (аналогично LD_PRELOAD on Linux). Концепция проста: во время загрузки динамический компоновщик (dyld) загрузит любые динамические библиотеки, указанные в DYLD_INSERT_LIBRARIES перед любыми библиотеками, которые исполняемый файл хочет загрузить. Именование функции то же, что и в библиотечной функции, он отменяет любые вызовы оригинал.
Исходная функция также загружается и может быть восстановлена с помощью dlsym (RTLD_NEXT, "function_name" ); функция. Это позволяет метод обертывания существующих библиотечных функций.
В соответствии с примером Том Робинсон вы можете необходимо также установить DYLD_FORCE_FLAT_NAMESPACE=1
.
Копия исходного примера (lib_overrides.c
), который переопределяет только fopen
:
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
// for caching the original fopen implementation
FILE * (*original_fopen) (const char *, const char *) = NULL;
// our fopen override implmentation
FILE * fopen(const char * filename, const char * mode)
{
// if we haven’t already, retrieve the original fopen implementation
if (!original_fopen)
original_fopen = dlsym(RTLD_NEXT, "fopen");
// do our own processing; in this case just print the parameters
printf("== fopen: {%s,%s} ==\n", filename, mode);
// call the original fopen with the same arugments
FILE* f = original_fopen(filename, mode);
// return the result
return f;
}
Использование:
$ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c
$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib command-to-test
Ответ 6
Отказ от ответственности: это происходит из ответа @kenorb . Это имеет некоторые преимущества: PID более специфичен, чем execname. И мы можем сделать краткосрочный процесс ожидания DTrace до его начала.
Это немного гонка-условие, но...
Скажем, мы хотим проследить cat /etc/hosts
:
sudo true && \
(sleep 1; cat /etc/hosts) &; \
sudo dtrace -n 'syscall:::entry /pid == $1/ {@[probefunc] = count();}' $!; \
kill $!
Мы используем sudo true
, чтобы убедиться, что мы очистим пароль пароля sudo, прежде чем мы начнем запускать что-нибудь чувствительное к времени.
Мы начинаем фоновый процесс ( "подождите 1 сек, затем сделайте что-нибудь интересное" ). Между тем, мы начинаем DTrace. Мы захватили PID фонового процесса в $!
, поэтому мы можем передать это DTrace как arg.
kill $!
запускается после закрытия DTrace. Это не нужно для нашего примера cat
(процесс закрывается сам по себе), но он помогает нам завершить длительные фоновые процессы, такие как ping
. Передача -p $!
в DTrace - это предпочтительный способ сделать это, но на macOS, по-видимому, требуется исполняемый код с кодом.
Другое, что вы можете сделать, это запустить команду в отдельной оболочке и отследить эту оболочку. См. Мой ответ .
Ответ 7
Я не знаю, как запустить то, что вы хотите, как обычный пользователь, так как кажется, что dtruss, который использует dtrace, требует привилегий su.
Однако я верю, что команда, которую вы искали вместо
dtruss -f sudo -u myusername gcc hello.c
является
sudo dtruss -f gcc hello.c
После ввода пароля, dtruss будет запускать dtrace будет sudo привилегий, и вы получите трассировку, а также файл a.out.
Извините, я не могу помочь.