user1929999
user1929999

Reputation: 129

Dynamic linked to libc in Linux does not have bind/connect

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

Answers (1)

Employed Russian
Employed Russian

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

Related Questions