2010-06-09 12 views
51

OS X manca di strace di linux, ma ha dtrace che dovrebbe essere molto meglio.Come si può ottenere dtrace per eseguire il comando tracciato con privilegi non di root?

Tuttavia, mi manca la possibilità di eseguire semplici tracing sui singoli comandi. Per esempio, su linux posso scrivere strace -f gcc hello.c a caputre tutte le chiamate di sistema, che mi dà l'elenco dei tutti i nomi dei file necessari al compilatore per compilare il mio programma (l'ottimo memoize sceneggiatura è costruita su questo trucco)

I voglio portare memoize sul mac, quindi ho bisogno di una sorta di strace. Quello di cui ho effettivamente bisogno è l'elenco dei file gcc in lettura e scrittura, quindi quello che mi serve è più di un truss. Certo, posso dire dtruss -f gcc hello.c e avere in qualche modo la stessa funzionalità, ma poi il compilatore viene eseguito con privilegi di root, che è ovviamente indesiderabile (a parte l'enorme rischio di sicurezza, un problema è che il file a.out è ora di proprietà di root :-)

allora ho provato dtruss -f sudo -u myusername gcc hello.c, ma questo si sente un po 'sbagliato, e non funziona comunque (ottengo alcun file a.out in tutto questo tempo, non so perché)

tutto ciò che lunga storia cerca di motivare la mia domanda iniziale : come ottengo dtrace per eseguire il mio comando con i normali privilegi dell'utente, proprio come fa strace in linux?

Edit: è sembra che io non sono l'unico a chiedersi come fare questo: domanda #1204256 è praticamente uguale al mio (e ha la stessa risposta sub-ottimale sudo :-)

risposta

5

Non è una risposta alla tua domanda, ma qualcosa da sapere. OpenSolaris ha risolto questo problema (parzialmente) con "privilegi" - vedi this page. Anche in OpenSolaris, non sarebbe possibile consentire a un utente, senza alcun privilegio aggiuntivo, di elaborare il proprio processo. Il motivo è il modo in cui dtrace funziona: abilita le sonde nel kernel. Quindi consentire a un utente non privilegiato di sondare il kernel significa che l'utente può fare molte cose indesiderate, ad es. annusando il passwd di altri utenti abilitando le sonde nel driver della tastiera!

+0

Probabilmente hai ragione. anche se ottenere i privilegi di root non è un problema qui, dal momento che sul mio laptop posso (e ho fatto) 'chmod a + s dtrace', tuttavia, dtrace non è inteso come uno strumento" unix power user ", ma come un" unix administrator "tool. Ecco perché provare a usarlo dai programmi utente porta a una situazione così artificiosa. Grazie mille per la tua risposta. – Gyom

+0

Non potrebbe avere una "modalità limitata", in cui solo alcune sonde (come le sonde syscall o le sonde userspace) si attiverebbero, e solo in alcuni processi (quelli di proprietà dell'utente interessato) e solo alcune funzioni sarebbero disponibili : quelli che possono essere fatti facilmente per ispezionare solo i processi dell'utente o che forniscono accesso ad informazioni già disponibili all'utente in altri modi? – SamB

1

I don' So di un modo per eseguire ciò che si desidera come utente normale, poiché sembra che dtruss, che usa dtrace, richieda i privilegi su.

Tuttavia, credo che il comando che stavi cercando invece di

dtruss -f sudo -u myusername gcc hello.c

è

sudo dtruss -f gcc hello.c

Dopo aver digitato la password, dtruss verrà eseguito privilegi sudo DTrace volontà, e otterrete la traccia e il file a.out.

Scusa, non ho potuto essere di ulteriore aiuto.

+3

il problema con l'esecuzione del comando stesso come root (a parte l'ovvio rischio di sicurezza gigantesco) è che l'ambiente di runtime di sudo (PATH, variabili env, permessi) è molto diverso da quello normale, e l'impatto drammatico sul comportamento di il programma tracciato. Linux 'strace', al contrario, è quasi trasparente in termini di comportamento funzionale del comando tracciato. – Gyom

5

Non so se è possibile ottenere che il disturbo sia non invasivo quanto strace.

Una variante del "sudo [per sradicare] dtruss sudo [torna a non root] cmd" che sembra funzionare meglio in qualche rapido test per me è:

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

Il sudo esterno è ovviamente così dtruss viene eseguito come root.

L'interno su è tornato a me, e con -l ricrea correttamente l'ambiente, a quel punto abbiamo bisogno di tornare indietro al punto in cui abbiamo iniziato.

Penso che "su -l utente" sia meglio di "sudo -u utente" se si desidera che l'ambiente sia ciò che normalmente ottiene l'utente.Quello sarà il loro ambiente di accesso però; Non so se c'è un buon modo per lasciare ereditare l'ambiente attraverso le due modifiche dell'utente.

Nella tua domanda, un altro reclamo che avevi sulla soluzione "sudo dtruss sudo", a parte la bruttezza, era che "non ho un file a.out in questo momento, non sono sicuro del perché". Non so neanche perché, ma nel mio piccolo script di test, una variante "sudo dtruss sudo" non è riuscita a scrivere su un file di output di test, e la variante "sudo dtruss su" sopra ha creato il file di output.

+0

davvero, grazie per questo tentativo. comunque, sembra che dovrò rinunciare a questo.Su linux, usavo i comandi 'strace' da uno script makefile-replacement, per spiare quali file venivano toccati dai comandi. Volevo portare questi script su mac os x, ma alla fine della giornata mi rendo conto che non mi piace l'idea di avere tutte le mie build che coinvolgono diversi livelli di sudo solo per spiare i miei comandi. – Gyom

+0

Sì. Cercare direttamente di fare in modo che i dtruss si comportino come una sostituzione non invasiva di strass sembra come abbaiare dall'albero sbagliato per i motivi che descrivi. Forse è necessario un approccio alternativo. 2 cose che potrebbero accadermi: 1) prendere il sorgente dtrace, modificare il frontend userlevel (che deve essere eseguito come root) in modo che inizi solo nuovi processi e solo spioni su quelli, aggiungi un'opzione per dirgli chi avvia tali processi come, quindi rendi setuid di proprietà di root. – metamatt

+0

E # 2 (continua dal commento precedente): usa direttamente dtrace il modo in cui è stato progettato per rispondere alla domanda a cui vuoi rispondere, invece di provare a usarlo come sostituto dropin per strace nei tuoi makefile per vedere cosa stavano facendo i comandi del bambino - puoi scrivere sonde dtrace al di fuori del processo di produzione che identificano e annotano ciò che sta facendo il processo? – metamatt

39

Il modo più semplice è quello di utilizzare sudo:

sudo dtruss -f sudo -u $USER whoami 

Altro soluzione sarebbe quella di eseguire il debugger prima e monitorare per i nuovi processi specifici. E.g.

sudo dtruss -fn whoami 

Poi, in un altro terminale gestita semplicemente:

whoami 

Semplice come quello.

argomenti più difficili si possono trovare nel manuale: man dtruss


In alternativa è possibile collegare dtruss al processo utente che esegue ad esempio su Mac:

sudo dtruss -fp PID 

o simili su Linux/Unix utilizzando strace:

sudo strace -fp PID 

Un altro trucco hacky potrebbe essere quella di eseguire il comando e subito dopo connettersi al processo.Ecco alcuni esempi:

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` 

Nota:

  • prima sudo è solo per il caching della password alla prima volta di correre,

  • questo trucco non funziona per il comando rapido linee come ls, date come ci vuole un po 'di tempo fino a che il debugger si allegherà al processo,

  • devi digitare il comando in due ces,

  • si può ignorare & per eseguire il processo in secondo piano, se è già facendo,

  • dopo aver terminato il debugging, dovrete uccidere manualmente il processo in background (ad esempio killall -v tail)

+5

Sei una rockstar per indicare l'opzione '-n' per dtruss. Questa è la risposta corretta al 100%. – wfaulk

7

La -n argomento per dtruss causerà dtruss aspettare ed esaminare i processi che corrispondono l'argomento -n. L'opzione -f continuerà a funzionare per seguire i processi biforcati dai processi corrispondenti a -n.

Tutto questo significa che se si desidera dtruss un processo (per amor di discussione, diciamo che è whoami) in esecuzione come utente non privilegiato, attenersi alla seguente procedura:

  1. aprire una shell di root
  2. eseguire dtruss -fn whoami
    • questo sarà sedersi e aspettare per un processo chiamato "whoami" esistere
  3. Aprire un nonprivilege d shell
  4. Run whoami
    • questo verrà eseguito e uscire normalmente
  5. Osservare traccia chiamata di sistema nella finestra di dtruss
    • dtruss non uscirà da solo - che continuerà in attesa per i processi corrispondenti - quindi uscire quando hai finito

Questa risposta duplica l'ultima parte della risposta di @ kenorb, ma merita di essere una risposta di prima classe.

3

Sembra che OS X non supporti l'uso di dtrace per replicare tutte le funzionalità di strace di cui si ha bisogno. Tuttavia, suggerirei di provare a creare un wrapper su syscalls adatti. Sembra che DYLD_INSERT_LIBRARIES sia la variabile di ambiente che vuoi modificare un po '. Questo è fondamentalmente lo stesso di LD_PRELOAD per Linux.

Un modo molto più semplice di fare l'override di funzione di libreria sta usando la variabile d'ambiente DYLD_INSERT_LIBRARIES (analogo a LD_PRELOAD sul Linux). Il concetto è semplice: al momento del caricamento, il linker dinamico (dyld) carica qualsiasi libreria dinamica specificata in DYLD_INSERT_LIBRARIES prima di qualsiasi libreria che l'eseguibile desidera caricare. Denominando una funzione uguale a quella di una funzione di libreria, essa sostituirà qualsiasi chiamata a originale.

La funzione originale viene anche caricata e può essere recuperata utilizzando il dlsym (RTLD_NEXT, "nome_funzione"); funzione. Ciò consente un semplice metodo per il wrapping delle funzioni di libreria esistenti.

Secondo il example da Tom Robinson potrebbe essere necessario impostare DYLD_FORCE_FLAT_NAMESPACE=1, anche.

Copia dell'esempio originale (lib_overrides.c) che sostituisce solo 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 
2

Esonero di responsabilità: questo è derivato da @ di answer kenorb. Tuttavia presenta alcuni vantaggi: PID è più specifico di execname. E possiamo fare in modo che un processo di breve durata attenda DTrace prima che inizi.

Questa è una gara-conditiony po ', ma ...

Diciamo che vogliamo tracciare cat /etc/hosts:

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

Usiamo sudo true fare in modo che abbiamo chiaro richiesta di password di sudo prima di iniziare a correre qualsiasi cosa sensibile al tempo.

Iniziamo un processo in background ("attendere 1 secondo, quindi fare qualcosa di interessante"). Nel frattempo, iniziamo DTrace. Abbiamo acquisito il PID del processo in background in $!, quindi possiamo passarlo a DTrace come argomento.

kill $! viene eseguito dopo aver chiuso DTrace. Non è necessario per il nostro esempio cat (il processo si chiude da solo), ma ci aiuta a terminare processi in background di lunga durata come ping. Passare -p $! a DTrace è il modo migliore per farlo, ma su macOS apparentemente richiede un eseguibile con firma del codice.


L'altra cosa che puoi fare è quello di eseguire il comando in una shell separata, e Snoop quel guscio. Vedi il mio answer.