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


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

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

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

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

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

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

8 53

8 ответов:

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

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

The

Я не знаю, можете ли вы заставить 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", если вы хотите, чтобы среда была тем, что обычно получает этот пользователь. Это будет их среда входа в систему; я не знаю, есть ли хороший способ позволить среде наследовать через два изменения пользователя.

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

по словам пример by Тома Робинсона возможно, Вам потребуется установить 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 == / {@[probefunc] = count();}' $!; \
kill $!

мы используем:sudo true чтобы убедиться, что мы очищаем запрос пароля sudo перед запуском чего-либо чувствительный ко времени.

мы начинаем фоновый процесс ("подождите 1 сек, а затем сделать что-то интересное"). Тем временем, мы начинаем DTrace. Мы захватили PID фонового процесса в $!, Так что мы можем передать, что для потребителя в качестве аргументов.

The 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 привилегии, и вы получите трассировку, а также файл.out.

Извините, я не мог быть дальше помощь.

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

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 "" "$@"' "$@"
        ;;
    esac
}

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