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

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

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

9 ответов

Решение

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

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

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

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

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

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

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

Похоже, что 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

Отказ от ответственности: это получено из ответа @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, очевидно, требуется исполняемый файл с подписью кода.


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

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

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

dtruss -f sudo -u myusername gcc hello.c

является

sudo dtruss -f gcc hello.c

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

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

Я не могу комментировать ответ Кенорба из-за отсутствия репутации. Но просто хотел добавить, что параметр -W заставит dtruss ожидать запуска указанного процесса, чтобы вывод не содержал множество несвязанных системных вызовов. Так

sudo dtruss -fW whoami

позволил мне найти мою проблему, где все было похоронено с помощью параметров -fn.

Извините, я не могу помочь! Я бы набрал Bash$ d program under test чтобы безопасно запустить dtruss в отдельном корневом окне, но, похоже, MacOSX SIP или что-то еще сейчас наносит вред dtruss -p а также opensnoop -p таким же тупым способом "все или ничего", как старый корень Un*x. Таким образом, этот bash-скрипт больше не работает:

d () 
{ 
    case "$*" in 
        [0-9] | [0-9][0-9] | [0-9][0-9][0-9] | [0-9][0-9][0-9][0-9] | [0-9][0-9][0-9][0-9][0-9])
            dtruss -f -p "$*"
        ;;
        *)
            bash -c 'echo -en "\t <<< press return in this window to run after launching trace in root window like this >>> \t # d $$" >/dev/tty; (read -u3 3</dev/tty); exec "$0" "$@"' "$@"
        ;;
    esac
}

Несколько десятилетий назад у нас были компьютеры Apple для сбора данных и джинсы Леви для вождения тракторов - теперь царит идиократия (пух-лиз, дави меня…), обе являются просто модными компаниями.

Другие вопросы по тегам