Подтвердить что ты не робот

Как заставить 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:-)

4b9b3361

Ответ 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.

Извините, я не могу помочь.