systemadmin.es > Utilidades > Capturar llamadas al sistema con LD_PRELOAD

Capturar llamadas al sistema con LD_PRELOAD

Mediante el uso de la variable de entorno LD_PRELOAD podemos cargar librerías dinámicas que sobrescriban llamadas al sistema. Vamos a ver como:

Un ejemplo en el que muy bien podemos utilizar LD_PRELOAD es cuando algún daemon no tiene la opción de funcionar sin pasar a background y luego no utiliza más la llamada fork().

Primero de todo creamos una función igual que la que queremos substituir con cualquier acción que queramos que se haga, en este caso no realizar el fork i devolver el zero:

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void)
{
        return 0;
}

Para crear la librería dinámica lo haremos mediante el siguiente comando:

gcc -Wall -fPIC -shared -o forkfaker.so forkfaker.c

A continuación podremos ejecutar el daemon con la variable LD_PRELOAD:

LD_PRELOAD="./forkfaker.so" /usr/bin/daemon.ejemplo

En el caso que el daemon vaya a background pero después necesite realizar más forks no nos vale ya que los siguientes forks no funcionaran correctamente. Para ello podemos crear una librería que no realice el primer fork pero si todo el resto mediante la llamada a syscall() para realizar el fork real:

#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

static int count=0;

pid_t fork(void)
{
        if (count < 1)
        {
                ++count;
                return 0;
        }
        return syscall(SYS_fork);
}

De esta manera podemos usar con daemontools cualquier daemon que pase a background y del cual no queramos modificar el código fuente. Un ejemplo sería el miniserv de webmin:

#!/bin/bash
LD_PRELOAD="/usr/local/lib/forkfaker.so" exec /usr/bin/perl /usr/local/webmin/miniserv.pl /usr/local/webmin/etc/miniserv.conf

En el caso que sea necesario más de un fork inicial sólo deberemos cambiar la condición del if que cuenta las veces que denegamos los forks.

5 comments to “Capturar llamadas al sistema con LD_PRELOAD”

  1. ¡Sencillamente EXCELENTE!

  2. Hola,

    un poco tarde, pero buscando cosas sobre LD_PRELOAD salió este artículo. ¿No es posible sobreescribir funciones internas del programa con LD_PRELOAD? Es decir, imagina que en vez de fork queremos sobreescribir una función propia del programa:

    char* haz_cosas(char, int, char);

    ¿Hay alguna forma?

    Saludos y gracias

  3. Puedes sobrescribir llamadas a funciones de librerías, pero no el propio código. Si quieres modificar la ejecución de una función sin el código fuente deberías parchear el binario.

  4. oye, una preguntita.
    veo que has definido la variable count como static, eso quere decir que su valor se guarda para futuras ejecuciones de la función, pero esto como funciona cuando hay varios procesos realizando llamadas a fork()?
    cada uno tendría su propio valor para esta función? imagina que lo que yo quiero sobreescribir la función read o write, esa variable estática tendría un valor para cada proceso que la llamara? y los hijos de estos procesos herederían el valor de count, o habría que inicializarla para cada proceso?
    Mil gracias

  5. El valor es global para cada proceso (para cada carga) no global del sistema, por lo que son valores independientes a cada proceso

Deja un comentario:

XHTML - Tags permitidos:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>