¿Cómo puedo hacer que dtrace ejecute el comando trace con privilegios no root?


OS X carece de strace de linux, 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 caputre todas las llamadas al sistema, lo que me da la lista de todos los nombres de archivo necesarios por el compilador para compilar mi programa (el excelente script memoize se basa 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 gcc lee y escribe en, por lo que lo que necesito es más de un truss. Por supuesto que puedo decir dtruss -f gcc hello.c y obtener algo la misma funcionalidad, pero luego el compilador se ejecuta con privilegios de root, lo cual es obviamente indeseable (aparte del riesgo de seguridad masivo, un problema es que el archivo a.out ahora es propiedad de root :-)

Luego intenté 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 todo este tiempo, no estoy seguro por qué)

Toda esa larga historia trata de motivar mi pregunta original: ¿cómo consigo que dtrace ejecute mi comando con privilegios de usuario normales, al igual que strace hace en linux ?

Editar: parece que no soy el único que se pregunta cómo hacer esto: pregunta #1204256 es más o menos lo mismo que el mío (y tiene la misma respuesta subóptima a sudo: -)

Author: Gyom, 2010-06-09

8 answers

No es una respuesta a tu pregunta, sino algo que debes saber. OpenSolaris resolvió este problema (parcialmente) con "privilegios" - ver esta página. Incluso en OpenSolaris, no sería posible permitir que un usuario, sin ningún privilegio adicional,procese su propio proceso. La razón es la forma en que funciona dtrace: habilita las sondas en el núcleo. Por lo tanto, permitir que un usuario no privilegiado sondee el núcleo significa que el usuario puede hacer muchas cosas no deseadas, por ejemplo, oler la contraseña de otro usuario al habilitar las sondas en el controlador de teclado!

 5
Author: netcharmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-15 12:16:03

La forma más fácil es usar sudo:

sudo dtruss -f sudo -u $USER whoami

Otra solución sería ejecutar el depurador primero y monitorear nuevos procesos específicos. Por ejemplo,

sudo dtruss -fn whoami

Luego en otra Terminal simplemente ejecute:

whoami

Así de simple.

Argumentos más complicados que puedes 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 podría ser ejecutar el comando y justo después de eso adjuntar al proceso. Estos son algunos 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:

  • First sudo es solo para almacenar en caché la contraseña en la primera vez que se ejecuta,

  • Este truco no funciona para líneas de comandos rápidas como ls, date ya que lleva algún tiempo hasta que el depurador se adjunte al proceso,

  • Tienes que escribir tu comando en dos lugares,

  • Puede ignorar & para ejecutar el proceso en segundo plano, si ya lo está haciendo,

  • Después de terminar la depuración, tendrá que matar manualmente el proceso en segundo plano (p.ej. killall -v tail)

 40
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-15 08:31:58

El argumento -n a dtruss hará que dtruss espere y examine los procesos que coinciden con el argumento a -n. La opción -f seguirá funcionando para seguir los procesos bifurcados de los procesos coincidentes con -n.

Todo esto significa que si quieres hacer dtruss a un proceso (por el bien del argumento, digamos que es whoami) ejecutándose como tu usuario no privilegiado, sigue estos pasos:

  1. Abrir un shell raíz
  2. Corre dtruss -fn whoami
    • esto esperará un proceso llamado "whoami" para existir
  3. Abrir un shell no privilegiado
  4. Corre whoami
    • esto se ejecutará y saldrá normalmente
  5. Observar el seguimiento de llamadas al sistema en la ventana dtruss
    • dtruss no saldrá por sí solo, continuará esperando los 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.

 7
Author: wfaulk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-02 21:28:10

No se si puedes conseguir que Dtruss sea tan no invasivo como Strace.

Una variante del "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, por lo que dtruss se ejecuta como root.

El su interior está de vuelta para mí, y con-l recrea el entorno correctamente, momento en el que necesitamos volver al cd donde empezamos.

Creo que "usuario su-l" es mejor que "usuario sudo-u" si queremos que el entorno sea lo que normalmente obtiene ese usuario. Sin embargo, ese será su entorno de inicio de sesión; no se 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 tenía sobre la solución "sudo dtruss sudo", aparte de la fealdad, fue que "No recibo un archivo.out en todo este tiempo, no estoy seguro de por qué". Yo tampoco se por qué, pero en mi pequeño guión 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.

 5
Author: metamatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-01 03:18:45

Parece que OS X no admite el uso de dtrace para replicar todas las características de strace que necesita. Sin embargo, sugeriría intentar crear un envoltorio alrededor de llamadas de sistema adecuadas. 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 fácil de hacer sobreescrituras de funciones de biblioteca es usar el Variable de entorno DYLD_INSERT_LIBRARIES (análoga a LD_PRELOAD on Linux). El concepto es simple: en el tiempo de carga el enlazador dinámico (dyld) cargará cualquier librería dinámica especificada en DYLD_INSERT_LIBRARIES antes de cualquier biblioteca el ejecutable quiere cargado. Nombrando una función lo mismo que uno en una función de biblioteca que anulará cualquier llamada a original.

La función original también se carga, y se puede recuperar usando el dlsym (RTLD_NEXT, "nombre_función"); función. Esto permite un simple método de envolver la biblioteca existente función.

De acuerdo con el ejemplo de Tom Robinson es posible que también tenga que configurar DYLD_FORCE_FLAT_NAMESPACE=1.

Copia del ejemplo original (lib_overrides.c) que anula 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;
}

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
 3
Author: Mikko Rantalainen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-28 14:00:00

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 por la raza, 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 que borramos la solicitud de contraseña de sudo antes de comenzar a ejecutar cualquier cosa sensible al tiempo.

Iniciamos un proceso en segundo plano ("wait 1 sec, a continuación, hacer algo interesante"). Mientras tanto, empezamos DTrace. Hemos capturado el PID del proceso en segundo plano en $!, así que podemos pasarlo a DTrace como un arg.

El kill $! se ejecuta después de cerrar DTrace. No es necesario para nuestro ejemplo cat (el proceso se cierra por sí solo), pero nos ayuda a terminar procesos en segundo plano de larga duración como ping. Pasar -p $! a DTrace es la forma preferida de hacer esto, pero en macOS aparentemente requiere un ejecutable firmado con código.


El otro lo que puedes hacer es ejecutar el comando en un shell separado, y espiar ese shell. Ver mi respuesta.

 2
Author: Birchlabs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-25 18:51:31

No conozco una forma de ejecutar lo que desea como usuario normal, ya que parece que dtruss, que utiliza dtrace requiere privilegios su.

Sin embargo, creo que el comando que estaba 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á los privilegios dtrace will sudo, y obtendrá el trace así como el archivo a.out.

Siento no haber podido ser de más ayuda.

 1
Author: aqua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-12 08:14:56

¡Lo siento, no puedo ayudar! Escribiría bash {d program under test para ejecutar dtruss de forma segura en una ventana raíz separada, pero parece que MacOSX SIP o lo que sea ahora lisia dtruss -p y opensnoop -p en la misma forma de todo o nada que la antigua raíz Un*x. Por lo tanto, este script bash ya no funciona:

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
}

Hace décadas teníamos computadoras Apple para enviar datos y jeans Levi's para conducir tractores - ahora reina la idiocracia (puh-leaze, gag me both) ambos son meras empresas de moda.

 0
Author: devon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-10 11:26:54