https://bugzilla.novell.com/show_bug.cgi?id=463447
Summary: preloading unable to catch system calls made by glibc
Product: openSUSE 11.1
Version: Final
Platform: i686
OS/Version: openSUSE 11.1
Status: NEW
Severity: Normal
Priority: P5 - None
Component: Basesystem
AssignedTo: bnc-team-screening@forge.provo.novell.com
ReportedBy: karls@inet.no
QAContact: qa@suse.de
Found By: Community User
To intercept I/O operations with preloading it is generally desirable
to catch the system calls made by libc rather than the libc functions
called directly by an application. The alternative would be very
fragile and implementation dependent due to frequent changes in system
header files and the internal operation of libc. This approach does
however not work for glibc (2.9-2.3), where preloading does not allow e.g.,
read() and write(), which are eventually called by functions such as
getc() and fputs(), to be intercepted.
The program below illustrates this problem:
libpreload.c:
----------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#define LIBRARY_SOCKET "/lib/libc.so.6"
#define SYMBOL_SOCKET "socket"
#define LIBRARY_READ "/lib/libc.so.6"
#define SYMBOL_READ "read"
#define LIBRARY_WRITE "/lib/libc.so.6"
#define SYMBOL_WRITE "write"
static void *symbolfunction(const char *symbol, const char *library);
int gethostbyname2_called;
int socket_called;
int read_called;
int write_called;
int
socket(domain, type, protocol)
int domain;
int type;
int protocol;
{
typedef int (*SOCKET_FUNC_T)(int, int, int);
SOCKET_FUNC_T function;
socket_called = 1;
function = symbolfunction(SYMBOL_SOCKET, LIBRARY_SOCKET);
return function(domain, type, protocol);
}
ssize_t
read(d, buf, nbytes)
int d;
void *buf;
size_t nbytes;
{
typedef ssize_t (*READ_FUNC_T)(int, void *, size_t);
READ_FUNC_T function;
read_called = 1;
function = symbolfunction(SYMBOL_READ, LIBRARY_READ);
return function(d, buf, nbytes);
}
ssize_t
write(d, buf, nbytes)
int d;
const void *buf;
size_t nbytes;
{
typedef ssize_t (*WRITE_FUNC_T)(int, const void *, size_t);
WRITE_FUNC_T function;
write_called = 1;
function = symbolfunction(SYMBOL_WRITE, LIBRARY_WRITE);
return function(d, buf, nbytes);
}
static void *
symbolfunction(symbol, library)
const char *symbol;
const char *library;
{
void *handle, *function;
if ((handle = dlopen(library, RTLD_LAZY)) == NULL) {
fprintf(stderr, "dlopen(%s): %s\n", library, dlerror());
exit(1);
}
if ((function = dlsym(handle, symbol)) == NULL) {
fprintf(stderr, "dlsym(%s): %s\n", symbol, dlerror());
exit(1);
}
dlclose(handle);
return function;
}
----------------------------------------------------------------------
preloadtest.c:
----------------------------------------------------------------------
#include
#include
#include
#include
#include
extern int socket_called;
extern int read_called;
extern int write_called;
int
main(argc, argv)
int argc;
char *argv[];
{
int c, s, err = 0;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket()");
exit(1);
}
if (socket_called)
puts("correct socket(2) called");
else {
err = 1;
puts("wrong socket(2) called");
}
printf("type something\n");
/* getc(3) would normaly need to call one of the read systemcalls. */
c = getc(stdin);
if (read_called)
puts("correct read(2) called");
else {
err = 1;
puts("wrong read(2) called");
}
if (fputs("### this should appear on stdout\n", stdout) == EOF) {
perror("fputs()");
exit(1);
}
if (write_called)
puts("correct write(2) called");
else {
err = 1;
puts("wrong write(2) called");
}
return err;
}
----------------------------------------------------------------------
The following set of commands:
gcc -fPIC -g -c -W -Wall libpreload.c && \
gcc -shared -Wl,-soname,libpreload.so -o libpreload.so libpreload.o -ldl && \
gcc -W -Wall -L${PWD} preloadtest.c -lpreload && \
LD_LIBRARY_PATH=${PWD} ./a.out
Results in the following output:
----------------------------------------------------------------------
correct socket(2) called
type something
f
wrong read(2) called
### this should appear on stdout
wrong write(2) called
----------------------------------------------------------------------
The read() and write() functions in libpreload.c are in other words
not called. Executing under strace does however show that these system
calls are being used:
execve("./a.out", ["./a.out"], [/* 57 vars */]) = 0
brk(0) = 0x804b000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb7f1d000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/home/suse/m/tls/i686/sse2/libpreload.so", O_RDONLY) = -1 ENOENT (No such
file or directory)
stat64("/home/suse/m/tls/i686/sse2", 0xbfd3ab54) = -1 ENOENT (No such file or
directory)
open("/home/suse/m/tls/i686/libpreload.so", O_RDONLY) = -1 ENOENT (No such file
or directory)
stat64("/home/suse/m/tls/i686", 0xbfd3ab54) = -1 ENOENT (No such file or
directory)
open("/home/suse/m/tls/sse2/libpreload.so", O_RDONLY) = -1 ENOENT (No such file
or directory)
stat64("/home/suse/m/tls/sse2", 0xbfd3ab54) = -1 ENOENT (No such file or
directory)
open("/home/suse/m/tls/libpreload.so", O_RDONLY) = -1 ENOENT (No such file or
directory)
stat64("/home/suse/m/tls", 0xbfd3ab54) = -1 ENOENT (No such file or directory)
open("/home/suse/m/i686/sse2/libpreload.so", O_RDONLY) = -1 ENOENT (No such
file or directory)
stat64("/home/suse/m/i686/sse2", 0xbfd3ab54) = -1 ENOENT (No such file or
directory)
open("/home/suse/m/i686/libpreload.so", O_RDONLY) = -1 ENOENT (No such file or
directory)
stat64("/home/suse/m/i686", 0xbfd3ab54) = -1 ENOENT (No such file or directory)
open("/home/suse/m/sse2/libpreload.so", O_RDONLY) = -1 ENOENT (No such file or
directory)
stat64("/home/suse/m/sse2", 0xbfd3ab54) = -1 ENOENT (No such file or directory)
open("/home/suse/m/libpreload.so", O_RDONLY) = 3
read(3,
"\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200\6\0\0004\0\0\0"..., 512) =
512
fstat64(3, {st_mode=S_IFREG|0755, st_size=11880, ...}) = 0
mmap2(NULL, 8252, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
0xb7f1a000
fadvise64(3, 0, 8252, POSIX_FADV_WILLNEED) = 0
mmap2(0xb7f1b000, 8192, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xb7f1b000
close(3) = 0
open("/home/suse/m/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=84552, ...}) = 0
mmap2(NULL, 84552, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f05000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`h\1\0004\0\0\0"...,
512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1419604, ...}) = 0
mmap2(NULL, 1422928, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
0xb7da9000
fadvise64(3, 0, 1422928, POSIX_FADV_WILLNEED) = 0
mprotect(0xb7efe000, 4096, PROT_NONE) = 0
mmap2(0xb7eff000, 12288, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x155) = 0xb7eff000
mmap2(0xb7f02000, 9808, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f02000
close(3) = 0
open("/home/suse/m/libdl.so.2", O_RDONLY) = -1 ENOENT (No such file or
directory)
open("/lib/libdl.so.2", O_RDONLY) = 3
read(3,
"\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200\n\0\0004\0\0\0"..., 512) =
512
fstat64(3, {st_mode=S_IFREG|0755, st_size=14012, ...}) = 0
mmap2(NULL, 16504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
0xb7da4000
fadvise64(3, 0, 16504, POSIX_FADV_WILLNEED) = 0
mmap2(0xb7da7000, 8192, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2) = 0xb7da7000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb7da3000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7da3940, limit:1048575,
seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0,
useable:1}) = 0
open("/dev/urandom", O_RDONLY) = 3
read(3, "\34=\256Q", 4) = 4
close(3) = 0
mprotect(0xb7da7000, 4096, PROT_READ) = 0
mprotect(0xb7eff000, 8192, PROT_READ) = 0
mprotect(0xb7f1b000, 4096, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb7f3c000, 4096, PROT_READ) = 0
munmap(0xb7f05000, 84552) = 0
brk(0) = 0x804b000
brk(0x806c000) = 0x806c000
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb7f19000
write(1, "correct socket(2) called\n", 25correct socket(2) called
) = 25
write(1, "type something\n", 15type something
) = 15
fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb7f18000
read(0, f
"f\n", 1024) = 2
write(1, "wrong read(2) called\n", 21wrong read(2) called
) = 21
write(1, "### this should appear on stdout"..., 33### this should appear on
stdout
) = 33
write(1, "wrong write(2) called\n", 22wrong write(2) called
) = 22
exit_group(1) = ?
--
Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.