web-dev-qa-db-fra.com

Comment puis-je obtenir strace pour exécuter la commande strace avec des privilèges non root?

OS X n'a ​​pas de strace de linux, mais il a dtrace qui est censé être tellement mieux.

Cependant, je manque la possibilité de faire un suivi simple sur des commandes individuelles. Par exemple, sur linux, je peux écrire strace -f gcc hello.c pour capter tous les appels système, ce qui me donne la liste tous les noms de fichiers nécessaires au compilateur pour compiler mon programme (l'excellent script memoize est construit sur cette base) tour)

Je veux porter memoize sur le mac, j'ai donc besoin d'une sorte de strace. Ce dont j'ai réellement besoin, c'est de la liste des fichiers gcc lisant et écrivant, donc ce dont j'ai besoin est plus d'un truss. Bien sûr, je peux dire dtruss -f gcc hello.c et obtenir quelque peu les mêmes fonctionnalités, mais le compilateur est alors exécuté avec les privilèges root, ce qui n'est évidemment pas souhaitable (à part le risque de sécurité énorme, un problème est que le a.out le fichier appartient maintenant à root :-)

J'ai ensuite essayé dtruss -f Sudo -u myusername gcc hello.c, mais cela semble un peu faux et ne fonctionne pas de toute façon (je n'ai pas de a.out fichier à tout moment, je ne sais pas pourquoi)

Toute cette longue histoire tente de motiver ma question d'origine: comment puis-je obtenir dtrace pour exécuter ma commande avec des privilèges utilisateur normaux, tout comme strace le fait sous linux ?

Edit: il semble que je ne sois pas le seul à me demander comment faire: la question # 1204256 est à peu près la même que la mienne (et a la même réponse Sudo sous-optimale :-)

57
Gyom

Pas une réponse à votre question mais quelque chose à savoir. OpenSolaris a résolu ce problème (partiellement) avec des "privilèges" - voir cette page . Même dans OpenSolaris, il ne serait pas possible d'autoriser un utilisateur, sans privilèges supplémentaires, à analyser son propre processus. La raison en est le fonctionnement de dtrace - il active les sondes dans le noyau. Ainsi, permettre à un utilisateur non privilégié de sonder le noyau signifie que l'utilisateur peut faire beaucoup de choses indésirables, par exemple renifler le mot de passe d'un autre utilisateur en activant les sondes dans le pilote du clavier!

5
netcharmer

La façon la plus simple est d'utiliser Sudo:

Sudo dtruss -f Sudo -u $USER whoami

Une autre solution serait d'exécuter le débogueur en premier et de surveiller les nouveaux processus spécifiques. Par exemple.

Sudo dtruss -fn whoami

Ensuite, dans un autre terminal, exécutez simplement:

whoami

Aussi simple que cela.

Des arguments plus délicats que vous pouvez trouver dans le manuel: man dtruss


Vous pouvez également attacher dtruss au processus utilisateur en cours d'exécution, par exemple sur Mac:

Sudo dtruss -fp PID

ou similaire sous Linux/Unix en utilisant strace:

Sudo strace -fp PID

Une autre astuce hacky pourrait être d'exécuter la commande et juste après l'attacher au processus. Voici quelques exemples:

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`

Remarque:

  • d'abord Sudo est juste pour la mise en cache du mot de passe lors de la première exécution,

  • cette astuce ne fonctionne pas pour les lignes de commande rapides comme ls, date car cela prend un certain temps avant que le débogueur ne s'attache au processus,

  • vous devez taper votre commande à deux endroits,

  • vous pouvez ignorer & pour exécuter le processus en arrière-plan, s'il le fait déjà,

  • après avoir terminé le débogage, vous devrez tuer manuellement le processus d'arrière-plan (par exemple killall -v tail)

44
kenorb

L'argument -n À dtruss fera attendre dtruss et examinera les processus qui correspondent à l'argument à -n. L'option -f Fonctionnera toujours pour suivre les processus issus des processus correspondant à -n.

Tout cela signifie que si vous souhaitez analyser un processus (pour les besoins de l'argument, disons que c'est whoami) exécuté en tant qu'utilisateur non privilégié, procédez comme suit:

  1. Ouvrez un shell racine
  2. Exécutez dtruss -fn whoami
    • cela va attendre et attendre qu'un processus nommé "whoami" existe
  3. Ouvrez un shell non privilégié
  4. Exécutez whoami
    • cela s'exécutera et sortira normalement
  5. Observer la trace des appels système dans la fenêtre dtruss
    • dtruss ne sortira pas de lui-même - il continuera d'attendre les processus de correspondance - alors sortez-en lorsque vous avez terminé

Cette réponse reproduit la dernière partie de la réponse de @ kenorb, mais elle mérite d'être une réponse de première classe.

8
wfaulk

Je ne sais pas si vous pouvez faire en sorte que Dtruss soit aussi non invasif que Strace.

Une variante du "Sudo [pour rooter] dtruss Sudo [retour à nonroot] cmd" qui semble mieux fonctionner dans certains tests rapides pour moi est:

Sudo dtruss -f su -l `whoami` cd `pwd` && cmd....

Le Sudo externe est bien sûr donc dtruss s'exécute en tant que root.

Le su intérieur est de retour pour moi, et avec -l, il recrée l'environnement correctement, à quel point nous devons revenir à l'endroit où nous avons commencé.

Je pense que "su -l user" est meilleur que "Sudo -u user" si vous voulez que l'environnement soit ce que cet utilisateur obtient normalement. Ce sera leur environnement de connexion cependant; Je ne sais pas s'il existe un bon moyen de laisser l'environnement hériter à travers les deux changements d'utilisateur à la place.

Dans votre question, une autre plainte que vous aviez à propos de la solution de contournement "Sudo dtruss Sudo", autre que la laideur, était que "je n'ai pas de fichier a.out à ce moment, je ne sais pas pourquoi". Je ne sais pas pourquoi non plus, mais dans mon petit script de test, une variante "Sudo dtruss Sudo" a également échoué à écrire dans un fichier de sortie de test, et la variante "Sudo dtruss su" ci-dessus a créé le fichier de sortie.

5
metamatt

Il semble qu'OS X ne prenne pas en charge l'utilisation de dtrace pour répliquer toutes les fonctionnalités de strace dont vous avez besoin. Cependant, je suggère d'essayer de créer un wrapper autour des appels système appropriés. Il ressemble à DYLD_INSERT_LIBRARIES est la variable d'environnement que vous souhaitez pirater un peu. C'est essentiellement la même chose que LD_PRELOAD pour Linux.

Un moyen beaucoup plus simple de remplacer les fonctions de bibliothèque consiste à utiliser la variable d'environnement DYLD_INSERT_LIBRARIES (analogue à LD_PRELOAD sous Linux). Le concept est simple: au moment du chargement, l'éditeur de liens dynamique (dyld) chargera toutes les bibliothèques dynamiques spécifiées dans DYLD_INSERT_LIBRARIES avant toutes les bibliothèques que l'exécutable souhaite charger. En nommant une fonction identique à celle d'une fonction de bibliothèque, elle remplacera tous les appels à l'original.

La fonction d'origine est également chargée et peut être récupérée à l'aide du dlsym (RTLD_NEXT, "nom_fonction"); fonction. Cela permet une méthode simple pour encapsuler les fonctions de bibliothèque existantes.

Selon le exemple par Tom Robinson vous devrez peut-être définir DYLD_FORCE_FLAT_NAMESPACE=1, aussi.

Copie de l'exemple d'origine (lib_overrides.c) qui ne remplace que 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;
}

Usage:

$ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c
$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib command-to-test
3
Mikko Rantalainen

Avertissement: cela est dérivé de @ kenorb réponse . Il présente cependant certains avantages: PID est plus spécifique que execname. Et nous pouvons faire attendre un processus de courte durée pour DTrace avant qu'il ne commence.

C'est un peu conditionnel à la course, mais…

Disons que nous voulons tracer cat /etc/hosts:

Sudo true && \
(sleep 1; cat /etc/hosts) &; \
Sudo dtrace -n 'syscall:::entry /pid == $1/ {@[probefunc] = count();}' $!; \
kill $!

Nous utilisons Sudo true pour nous assurer que nous effaçons l'invite de mot de passe de Sudo avant de commencer à exécuter quelque chose de temporel.

Nous commençons un processus d'arrière-plan ("attendez 1 seconde, puis faites quelque chose d'intéressant"). Pendant ce temps, nous démarrons DTrace. Nous avons capturé le PID du processus d'arrière-plan dans $!, nous pouvons donc transmettre cela à DTrace comme argument.

Le kill $! s'exécute après la fermeture de DTrace. Ce n'est pas nécessaire pour notre exemple cat (le processus se ferme tout seul), mais il nous aide à mettre fin aux processus d'arrière-plan de longue durée comme ping. Qui passe -p $! à DTrace est le moyen préféré de le faire, mais sur macOS nécessite apparemment un exécutable signé par code.


L'autre chose que vous pouvez faire est d'exécuter la commande dans un Shell séparé et de fouiner ce Shell. Voir mon réponse .

2
Birchlabs

Je ne connais pas de moyen d'exécuter ce que vous voulez en tant qu'utilisateur normal, car il semble que dtruss, qui utilise dtrace, nécessite des privilèges su.

Cependant, je crois que la commande que vous cherchiez au lieu de

dtruss -f Sudo -u myusername gcc hello.c

est

Sudo dtruss -f gcc hello.c

Après avoir tapé votre mot de passe, dtruss exécutera les privilèges dtrace will Sudo, et vous obtiendrez la trace ainsi que le fichier a.out.

Désolé, je n'ai pas pu vous aider davantage.

1
aqua