2011-07-01 11 views
9

Estaba jugando con LD_PRELOAD para interceptar llamadas libc, parece que la llamada de escritura no se intercepta con wc, aunque parece funcionar con cat. Una versión simplificada del problema aparece a continuación.¿Por qué LD_PRELOAD no parece funcionar para escribir con wc

RedHat Linux 2.6.9-42.ELsmp

Makefile

writelib: 
     gcc -Wall -rdynamic -fPIC -c write.c 
     gcc -shared -Wl,-soname,libwrite.so -Wl,-export-dynamic -o libwrite.so write.o -ldl 

write.c:

#include <stdio.h> 
#include <string.h> 
#ifndef __USE_GNU 
#define __USE_GNU 
#define __USE_GNU_DEFINED 
#endif 
#include <dlfcn.h> 
#ifdef __USE_GNU_DEFINED 
#undef __USE_GNU 
#undef __USE_GNU_DEFINED 
#endif 
#include <unistd.h> 
#include <stdlib.h> 

static ssize_t (*libc_write)(int fd, const void *buf, size_t len); 

ssize_t 
write(int fd, const void *buf, size_t len) 
{ 
    static int already; 
    ssize_t ret; 

    if (!already) { 
      if ((libc_write = dlsym(RTLD_NEXT, "write")) == NULL) { 
        exit(1); 
      } 
      already = 1; 
    } 


    ret = (*libc_write)(fd,"LD_PRELOAD\n",11); 
    return len; // not ret so cat doesn't take forever 
} 

Salida:

prompt: make 
gcc -Wall -rdynamic -fPIC -c write.c 
gcc -shared -Wl,-soname,libwrite.so -Wl,-export-dynamic -o libwrite.so write.o -ldl 
prompt: LD_PRELOAD=./libwrite.so /bin/cat write.c 
LD_PRELOAD 
prompt: LD_PRELOAD=./libwrite.so /usr/bin/wc write.c 
32 70 572 write.c 

Toda explicación?

Respuesta

7

Eso es porque mientras cat utiliza write, wc utiliza printf, lo que probablemente está utilizando ya sea una versión inline de write, o su referencia a write está obligado a libc, por lo que no se puede interponer.

Esto se puede ver fácilmente usando ltrace:

$ echo foo | ltrace wc 2>&1 | grep 'write\|print' 
printf("%*s", 7, "1")       = 7 
printf(" %*s", 7, "1")       = 8 
printf(" %*s", 7, "4")       = 8 


$ echo foo | ltrace cat 2>&1 | grep 'write\|print' 
write(1, "foo\n", 4foo 
+0

vea también: http://stackoverflow.com/questions/6538501/linking-two-shared-libraries-with-some-of-the-same-symbols/6540059#6540059 de cómo un símbolo puede estar vinculado a un copia interna en una biblioteca. – ninjalj

+0

Gracias por el puntero a ltrace. Estaba confundiendo la llamada de escritura de libc con la llamada de escritura del sistema que estaba apareciendo cuando ejecuté strace en el comando wc. –

1

LD_PRELOAD es realmente un método muy pobre para interceptar y redirigir las llamadas. Solo funciona con bibliotecas compartidas, y dependiendo de cómo se vinculó la biblioteca y de los niveles de optimización y en línea utilizados, las llamadas que desea interceptar pueden no ser interceptables de manera confiable.

Una gran alternativa que evita todos estos problemas, especialmente cuando se trata de syscalls que desea interceptar y reescribir, está utilizando la interfaz de seguimiento/depuración ptrace. Lamentablemente, no parece haber ninguna herramienta para automatizar este enfoque en este momento.

Cuestiones relacionadas