macos - ¿Cómo puede hacer que dtrace ejecute el comando rastreado con privilegios no root?
strace (7)
No sé de una manera de ejecutar lo que desea como usuario normal, ya que parece que dtruss, que usa dtrace requiere sus privilegios.
Sin embargo, creo que el comando que estabas buscando en lugar de
dtruss -f sudo -u myusername gcc hello.c
es
sudo dtruss -f gcc hello.c
Después de escribir su contraseña, dtruss ejecutará dtrace y sudo privilegios, y obtendrá el seguimiento así como también el archivo a.out.
Lo siento, no podría ser de más ayuda.
OS X carece de la strace
de strace
, pero tiene dtrace
que se supone que es mucho mejor.
Sin embargo, echo de menos la capacidad de hacer un seguimiento simple en comandos individuales. Por ejemplo, en Linux puedo escribir strace -f gcc hello.c
para capturar todas las llamadas al sistema, lo que me da la lista de todos los nombres de archivo que necesita el compilador para compilar mi programa (el excelente script memoise está basado en este truco)
Quiero portar memoize en el mac, así que necesito algún tipo de strace
. Lo que realmente necesito es la lista de archivos que gcc
lee y escribe, así que lo que necesito es más un truss
. Efectivamente, puedo decir dtruss -f gcc hello.c
y obtener de algún modo la misma funcionalidad, pero luego el compilador se ejecuta con privilegios de root, lo cual es obviamente indeseable (aparte del enorme riesgo de seguridad, un problema es que el archivo a.out
ahora es propiedad de root :-)
Luego probé dtruss -f sudo -u myusername gcc hello.c
, pero esto se siente un poco mal, y no funciona de todos modos (no recibo ningún archivo a.out
en este momento, no estoy seguro de por qué)
Toda esa historia larga intenta motivar mi pregunta original: ¿cómo obtengo dtrace
para ejecutar mi comando con privilegios de usuario normales, al igual que strace
does en Linux?
Editar: parece que no soy el único que se pregunta cómo hacer esto: la pregunta # 1204256 es más o menos la misma que la mía (y tiene la misma respuesta de sudo subóptima :-)
No es una respuesta a su pregunta, sino algo que debe saber. OpenSolaris resolvió este problema (parcialmente) con "privilegios" - vea esta página . Incluso en OpenSolaris, no sería posible permitir que un usuario, sin ningún privilegio adicional, controle su propio proceso. La razón es la forma en que funciona dtrace: habilita sondeos en el kernel. Por lo tanto, permitir que un usuario sin privilegios explore el kernel significa que el usuario puede hacer muchas cosas indeseadas, por ejemplo, olfatear la contraseña de otro usuario habilitando sondeos en el controlador del teclado.
No sé si puedes hacer que Dussuss sea tan no invasivo como Strace.
Una variante de "sudo [to root] dtruss sudo [back to nonroot] cmd" que parece funcionar mejor en algunas pruebas rápidas para mí es:
sudo dtruss -f su -l `whoami` cd `pwd` && cmd....
El sudo externo es, por supuesto, así que dtruss se ejecuta como root.
El su interior está de vuelta a mí, y con -l recrea el entorno de forma adecuada, en cuyo punto debemos volver al lugar donde comenzamos.
Creo que "su -l usuario" es mejor que "sudo -u usuario" si quiere que el entorno sea lo que ese usuario normalmente obtiene. Sin embargo, ese será su entorno de inicio de sesión; No sé si hay una buena manera de dejar que el entorno herede a través de los dos cambios de usuario.
En su pregunta, una queja adicional que tuvo sobre la solución alternativa "sudo dtruss sudo", aparte de la fealdad, fue que "no recibí ningún archivo a.out en todo este tiempo, no estoy seguro de por qué". No sé por qué tampoco, pero en mi pequeño script de prueba, una variante "sudo dtruss sudo" tampoco pudo escribir en un archivo de salida de prueba, y la variante "sudo dtruss su" anterior creó el archivo de salida.
El argumento -n
para dtruss
hará que dtruss espere y examine los procesos que coinciden con el argumento en -n
. La opción -f
seguirá funcionando para seguir los procesos bifurcados de los procesos combinados por -n
.
Todo esto significa que si quieres resolver un proceso (por el bien de la discusión, digamos que es whoami
) ejecutándose como tu usuario no privilegiado, sigue estos pasos:
- Abra un shell raíz
- Ejecute
dtruss -fn whoami
- esto se sentará y esperará a que exista un proceso llamado "whoami"
- Abre un shell sin privilegios
- Ejecutar
whoami
- esto se ejecutará y saldrá normalmente
- Observe el seguimiento de llamadas del sistema en la ventana dtruss
- dtruss no saldrá solo, continuará esperando procesos coincidentes, así que salga de él cuando haya terminado
Esta respuesta duplica la última parte de la respuesta de @ kenorb, pero merece ser una respuesta de primera clase.
La forma más fácil es usar sudo:
sudo dtruss -f sudo -u $USER whoami
Otra solución sería ejecutar primero el depurador y monitorear nuevos procesos específicos. P.ej
sudo dtruss -fn whoami
Luego, en otra Terminal simplemente ejecute:
whoami
Simple como eso.
Argumentos más complicados que puede encontrar en el manual: man dtruss
Alternativamente, puede adjuntar dtruss al proceso de usuario en ejecución, por ejemplo, en Mac:
sudo dtruss -fp PID
o similar en Linux / Unix usando strace:
sudo strace -fp PID
Otro truco hacky podría ser ejecutar el comando y justo después de eso adjuntarlo al proceso. Aquí hay unos ejemplos:
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:
el primer sudo es solo para almacenar en caché la contraseña la primera vez que se ejecuta,
este truco no funciona para líneas de comando rápidas como
ls, date
ya que lleva un tiempo hasta que el depurador se adjunte al proceso,tienes que escribir tu comando en dos lugares,
puede ignorar
&
ejecutar el proceso hasta el fondo, si ya lo está haciendo,después de terminar la depuración, tendrá que eliminar manualmente el proceso en segundo plano (p. ej.,
killall -v tail
)
Parece que OS X no admite el uso de dtrace para replicar todas las características de strace que necesita. Sin embargo, sugeriría tratar de crear un contenedor de syscalls adecuados. Parece que DYLD_INSERT_LIBRARIES es la variable de entorno que quieres hackear un poco. Eso es básicamente lo mismo que LD_PRELOAD
para Linux.
Una forma mucho más sencilla de hacer excepciones de funciones de biblioteca es usar la variable de entorno DYLD_INSERT_LIBRARIES (análoga a LD_PRELOAD en Linux). El concepto es simple: en el momento de la carga, el enlazador dinámico (dyld) cargará cualquier biblioteca dinámica especificada en DYLD_INSERT_LIBRARIES antes de las bibliotecas que quiera cargar el archivo ejecutable. Al nombrar una función igual a una en una función de biblioteca, se anulará cualquier llamada al original.
La función original también está cargada, y se puede recuperar utilizando dlsym (RTLD_NEXT, "nombre_función"); función. Esto permite un método simple para envolver las funciones de biblioteca existentes.
Según el ejemplo de Tom Robinson, es posible que deba establecer DYLD_FORCE_FLAT_NAMESPACE=1
también.
Copia del ejemplo original ( lib_overrides.c
) que reemplaza solo a 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;
}
Uso:
$ gcc -Wall -o lib_overrides.dylib -dynamiclib lib_overrides.c
$ DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=lib_overrides.dylib command-to-test
Descargo de responsabilidad: esto se deriva de la respuesta de @ kenorb. Sin embargo, tiene algunas ventajas: PID es más específico que execname. Y podemos hacer que un proceso de corta duración espere a DTrace antes de que comience.
Esto es un poco condicionado a la carrera, pero ...
Digamos que queremos rastrear cat /etc/hosts
:
sudo true && /
(sleep 1; cat /etc/hosts) &; /
sudo dtrace -n ''syscall:::entry /pid == $1/ {@[probefunc] = count();}'' $!; /
kill $!
Usamos sudo true
para asegurarnos de borrar el mensaje de contraseña de sudo antes de comenzar a ejecutar cualquier elemento sensible al tiempo.
Comenzamos un proceso en segundo plano ("espere 1 segundo, luego haga algo interesante"). Mientras tanto, comenzamos DTrace. ¡Hemos capturado el PID del proceso en segundo plano en $!
, entonces podemos pasar eso a DTrace como un arg.
¡ kill $!
se ejecuta después de cerrar DTrace. No es necesario para nuestro ejemplo de cat
(el proceso se cierra por sí solo), pero nos ayuda a terminar procesos de fondo de larga ejecución como ping
. Pasando -p $!
para DTrace es la forma preferida de hacerlo, pero en MacOS aparentemente se requiere un ejecutable con código firmado.
La otra cosa que puedes hacer es ejecutar el comando en un shell separado y husmear ese shell. Ver mi respuesta