2011-07-01 31 views
9

Tôi đang chơi với LD_PRELOAD để chặn cuộc gọi libc, có vẻ như cuộc gọi ghi không bị chặn với wc, mặc dù nó dường như hoạt động với con mèo. Phiên bản rút gọn của sự cố xuất hiện bên dưới.Tại sao LD_PRELOAD dường như không hoạt động để viết với 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 
} 

Output:

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 

Bất kỳ lời giải thích?

Trả lời

7

Đó là bởi vì trong khi cat sử dụng write, wc sử dụng printf, mà có lẽ bằng cách sử dụng một phiên bản inlined của write, hoặc tham chiếu của nó để write là ràng buộc để libc, vì vậy không thể xen.

này có thể dễ dàng được nhìn thấy sử dụng 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

cũng xem: http://stackoverflow.com/questions/6538501/linking-two-shared-libraries-with-some-of-the-same-symbols/6540059#6540059 để biết biểu tượng có thể bị ràng buộc như thế nào bản sao nội bộ trong thư viện. – ninjalj

+0

Cảm ơn con trỏ tới ltrace. Tôi đã nhầm lẫn giữa cuộc gọi viết libc với cuộc gọi viết hệ thống đã xuất hiện khi tôi chạy strace trên lệnh wc. –

1

LD_PRELOAD thực sự là một phương pháp rất nghèo cho chặn và chuyển hướng cuộc gọi. Nó chỉ hoạt động với các thư viện chia sẻ và tùy thuộc vào cách thư viện được liên kết và mức độ tối ưu hóa và nội tuyến đang được sử dụng, các cuộc gọi bạn muốn chặn có thể không đáng tin cậy.

Một giải pháp thay thế tuyệt vời tránh được tất cả các sự cố này, đặc biệt khi đó là các syscalls bạn muốn chặn và viết lại, đang sử dụng giao diện truy tìm/gỡ lỗi ptrace. Thật không may dường như không có công cụ nào để tự động hóa phương pháp này vào lúc này.

Các vấn đề liên quan