Как я могу заставить dtrace запускать трассированную команду с привилегиями не-root? - PullRequest
54 голосов
/ 09 июня 2010

OS X не хватает Linux strace, но имеет dtrace, что должно быть намного лучше.

Однако мне не хватает возможности выполнять простую трассировку по отдельным командам. Например, в Linux я могу написать strace -f gcc hello.c, чтобы скрыть все системные вызовы, что дает мне список всех имен файлов, необходимых компилятору для компиляции моей программы (превосходный memoize сценарий построен на этой уловке)

Я хочу перенести памятку на Mac, поэтому мне нужен какой-то strace. Что мне действительно нужно, так это список файлов, которые gcc читает и записывает, так что мне нужно больше truss. Разумеется, я могу сказать dtruss -f gcc hello.c и получить несколько такой же функциональности, но затем компилятор запускается с привилегиями суперпользователя, что, очевидно, нежелательно (кроме огромного риска для безопасности, одна проблема заключается в том, что файл a.out теперь принадлежит root: -)

Затем я попытался dtruss -f sudo -u myusername gcc hello.c, но это немного не так, и все равно не работает (у меня все время нет файла a.out, не знаю почему)

Вся эта длинная история пытается мотивировать мой оригинальный вопрос: как мне заставить dtrace запускать мою команду с обычными привилегиями пользователя, точно так же, как strace делает в linux?

Редактировать: кажется, что я не единственный, кто задается вопросом, как это сделать: вопрос # 1204256 во многом совпадает с моим (и имеет тот же субоптимальный ответ sudo :-)

Ответы [ 7 ]

44 голосов
/ 29 июля 2012

Самый простой способ - использовать 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`

Примечание:

  • first sudo только для кэширования пароля при первом запуске,

  • этот прием не работает для быстрых командных строк, таких как ls, date, так как требуется некоторое время, пока отладчик не подключится к процессу,

  • вы должны ввести команду в двух местах,

  • Вы можете игнорировать &, чтобы запустить процесс в фоновом режиме, если он уже это делает,

  • после завершения отладки вам придется вручную убить фоновый процесс (например, killall -v tail)

8 голосов
/ 03 января 2014

Аргумент -n для dtruss заставит dtruss ждать и проверять процессы, которые соответствуют аргументу -n.Опция -f будет по-прежнему работать для отслеживания процессов, разветвленных из процессов, сопоставленных с -n.

Все это означает, что если вы хотите обработать процесс (для аргументации, скажем, это whoami) работает как непривилегированный пользователь, выполните следующие действия:

  1. Откройте корневую оболочку
  2. Запустите dtruss -fn whoami
    • , это будет сидеть и ждать процесса с именем"whoami" существует
  3. Откройте непривилегированную оболочку
  4. Запустите whoami
    • , она будет выполнена и нормально завершится
  5. Наблюдение за трассировкой системного вызова в окне dtruss
    • dtruss не выйдет сам по себе - он продолжит ждать соответствующих процессов - так что прекратите его, когда закончите

Этот ответ дублирует последнюю часть ответа @ kenorb, но он заслуживает того, чтобы быть ответом первого класса.

5 голосов
/ 15 января 2011

Не ответ на ваш вопрос, но что-то знать.OpenSolaris решил эту проблему (частично) с «привилегиями» - см. эту страницу .Даже в OpenSolaris было бы невозможно позволить пользователю без каких-либо дополнительных привилегий управлять своим собственным процессом.Причина в том, как работает dtrace - он позволяет проверять в ядре.Таким образом, разрешение непривилегированному пользователю проверять ядро ​​означает, что пользователь может совершать множество нежелательных действий, например, прослушивать пароль другого пользователя, включив проверку в драйвере клавиатуры!

5 голосов
/ 14 января 2011

Я не знаю, можно ли заставить 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", кроме уродства.было то, что «я не получаю файл .out все это время, не знаю почему».Я тоже не знаю, почему, но в моем небольшом тестовом сценарии вариант «sudo dtruss sudo» также не смог записать в тестовый выходной файл, а вариант «sudo dtruss su», приведенный выше, действительно создал выходной файл.

3 голосов
/ 28 августа 2014

Похоже, что OS X не поддерживает использование dtrace для репликации всех необходимых вам функций strace. Тем не менее, я бы посоветовал попытаться создать оболочку вокруг подходящих системных вызовов. Похоже, DYLD_INSERT_LIBRARIES - это переменная окружения, которую вы хотите немного взломать. Это в основном то же самое, что LD_PRELOAD для Linux.

Гораздо более простой способ переопределения библиотечных функций - использовать Переменная окружения DYLD_INSERT_LIBRARIES (аналог LD_PRELOAD в Linux). Концепция проста: во время загрузки динамический компоновщик (dyld) загрузит любые динамические библиотеки, указанные в DYLD_INSERT_LIBRARIES перед любой библиотеки исполняемый файл хочет загрузить. Называя функцию так же, как в библиотечной функции, он отменяет любые вызовы оригинал.

Исходная функция также загружается и может быть получена с помощью dlsym (RTLD_NEXT, «имя_функции»); функция. Это позволяет простой метод упаковки существующих библиотечных функций.

В соответствии с примером от Томом Робинсоном вам также может потребоваться установить 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
2 голосов
/ 25 июня 2017

Отказ от ответственности: это получено из ответа @ 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 в виде аргумента.

kill $! запускается после закрытия DTrace. Это не обязательно для нашего cat примера (процесс закрывается сам по себе), но это помогает нам завершить длительные фоновые процессы, такие как ping. Передача -p $! в DTrace является предпочтительным способом сделать это, но в macOS, очевидно, требуется исполняемый файл с кодовой подписью.


Другое, что вы можете сделать, это запустить команду в отдельной оболочке и отследить эту оболочку. Смотрите мой ответ .

1 голос
/ 12 января 2011

Я не знаю способа запустить то, что вы хотите, как обычный пользователь, так как кажется, что dtruss, который использует dtrace, требует привилегий su.

Тем не менее, я считаю, что вы искали команду вместо

dtruss -f sudo -u myusername gcc hello.c

есть

sudo dtruss -f gcc hello.c

После ввода пароля dtruss запустит dtrace с привилегиями sudo, и вы получите трассировку и файл a.out.

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

...