Reputation: 129
Is that true that Go dynamic linked to libc in Linux and Mac is different? I am trying to evaluate the use of LD_PRELOAD (Linux) or DYLD_INSERT_LIBRARIES (macOS) to intercept the bind (listen) function. It's working on macOS but not on Linux.
On macOS:
❯ otool -tV main | grep bind
_x_cgo_bindm:
0000000100090134 bl _syscall.bind
_syscall.bind:
0000000100090578 b _syscall.bind
_syscall.libc_bind_trampoline.abi0:
On Linux:
# objdump -T ./main
./main: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000545a80 g DF .text 0000000000000063 Base crosscall2
0000000000545a40 g DF .text 0000000000000037 Base _cgo_panic
0000000000466ae0 g DF .text 0000000000000019 Base _cgo_topofstack
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) __errno_location
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) getaddrinfo
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) free
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) freeaddrinfo
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) gai_strerror
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) stderr
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) fwrite
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) vfprintf
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) fputc
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) abort
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) pthread_mutex_lock
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.3.2) pthread_cond_wait
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) pthread_mutex_unlock
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.3.2) pthread_cond_broadcast
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.34) pthread_create
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) nanosleep
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.34) pthread_detach
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) strerror
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) fprintf
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) malloc
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) pthread_attr_init
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.34) pthread_attr_getstacksize
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) pthread_attr_destroy
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) sigfillset
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.32) pthread_sigmask
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) mmap
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) munmap
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) setenv
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) unsetenv
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) sigemptyset
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) sigaddset
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) sigaction
0000000000000000 DO *UND* 0000000000000000 (GLIBC_2.2.5) sigismember
Is there anyway to force Go binary in Linux use bind/connect function as macOS?
Upvotes: 0
Views: 91
Reputation: 213879
On Linux:
The binary doesn't depend on the bind
symbol, but that doesn't necessarily mean that you can't use LD_PRELOAD
to interpose bind
for that binary.
If that binary was built with gccgo
, chances are it depends on libgo.so.*
, which (on my system) does depend on bind
and connect
:
readelf -Ws /usr/lib64/libgo.so.22 | grep -E ' (bind|connect)'
77: 0000000000000000 0 FUNC GLOBAL DEFAULT UND connect@GLIBC_2.2.5 (2)
224: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bind@GLIBC_2.2.5 (2)
140156: 0000000000000000 0 FUNC GLOBAL DEFAULT UND connect@GLIBC_2.2.5
163145: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bind@GLIBC_2.2.5
Update:
curious if your building with gccgo actually get hooked by LD_PRELOAD simple bind function?
Yes, it does. I compiled this example with gccgo tcp_server.go
, and compiled this code:
void bind() { abort(); }
with gcc -w -shared -fPIC -o bind.so bind.c
Finally I ran: LD_PRELOAD=./bind.so ./a.out
and it produced:
SIGABRT: abort
PC=0x7f83d3965884 m=0 sigcode=18446744073709551610
goroutine 1 [syscall]:
__pthread_kill_implementation
:0
gsignal
:0
__GI_abort
:0
syscall.Bind
:0
...
Note however, that my ldd
output shows dependency on libgo.so
, while yours does not. Here is what I see:
ldd a.out
linux-vdso.so.1 (0x00007ffc574f8000)
libgo.so.22 => /lib64/libgo.so.22 (0x00007f21d5f7d000)
libm.so.6 => /lib64/libm.so.6 (0x00007f21d5e9c000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f21d5e78000)
libc.so.6 => /lib64/libc.so.6 (0x00007f21d5c9a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f21d7bb1000)
Upvotes: 0