Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall: if $LD_PRELOAD is set, use connect(), execve() in libc #3744

gopherbot opened this issue Jun 16, 2012 · 28 comments

syscall: if $LD_PRELOAD is set, use connect(), execve() in libc #3744

gopherbot opened this issue Jun 16, 2012 · 28 comments


Copy link

by hongruiqi:

cgoLookupHost may return nil addrs with no err report, which leads to the index out of
range in the net.hostPortToIP by indexing addrs[0].

go version weekly.2012-03-27 +5e3661048f2e
Copy link

Comment 1:

Can you please test this with go 1.0.2 (weekly.2012-03-27 is very old).
Can you also please update the issue with your OS, Arch and the full panic message.

Status changed to WaitingForReply.

Copy link

Comment 2 by hongruiqi:

+5e3661048f2e is the tip version now...
Gentoo Linux 64bit
uname -a
Linux HRQ-PC 3.2.12-gentoo #16 SMP Fri Jun 8 23:08:57 CST 2012 x86_64 Intel(R) Core(TM)
i3 CPU M 350 @ 2.27GHz GenuineIntel GNU/Linux
panic message:
panic: runtime error: index out of range
goroutine 1 [running]:
net.hostPortToIP(0x6f0704, 0x3, 0xf8400f6b60, 0x15, 0x0, ...)
    /usr/lib/go/src/pkg/net/ipsock.go:127 +0x3c8
net.ResolveTCPAddr(0x6f0704, 0x3, 0xf8400f6b60, 0x70637400000015, 0xf800000000, ...)
    /usr/lib/go/src/pkg/net/tcpsock.go:31 +0x51
net.resolveNetAddr(0x6fd05c, 0x6c61696400000004, 0x6f0704, 0xf800000003, 0xf8400f6b60,
    /usr/lib/go/src/pkg/net/dial.go:50 +0x504
net.Dial(0x6f0704, 0x3, 0xf8400f6b60, 0x7ff900000015, 0x0, ...)
    /usr/lib/go/src/pkg/net/dial.go:92 +0x62
net/http.(*Transport).dial(0xf8400b0840, 0x6f0704, 0x70637400000003, 0xf8400f6b60, 0x15,
    /usr/lib/go/src/pkg/net/http/transport.go:299 +0xd5
net/http.(*Transport).getConn(0xf8400b0840, 0xf8400f2420, 0xf8400f2420, 0x0, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/transport.go:311 +0xbe
net/http.(*Transport).RoundTrip(0xf8400b0840, 0xf8400b8000, 0x3b, 0x0, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/transport.go:155 +0x2ba
net/http.send(0xf8400b8000, 0xf840083030, 0xf8400b0840, 0x0, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/client.go:133 +0x3ca
net/http.(*Client).doFollowingRedirects(0x8a0a80, 0xf8400b8000, 0x0, 0x0, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/client.go:227 +0x61c
----- stack segment boundary -----
net/http.(*Client).Get(0x8a0a80, 0xf8400f7e00, 0x7ff90000003b, 0x34, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/client.go:176 +0xb8
net/http.Get(0xf8400f7e00, 0x7d0000003b, 0xf8400f7e00, 0x0, 0x0, ...)
    /usr/lib/go/src/pkg/net/http/client.go:158 +0x51
main.httpGET(0xf8400f7e00, 0xf80000003b, 0x0, 0x0, 0x0, ...)
    /usr/lib/go/src/cmd/go/http.go:25 +0x77
main.bitbucketVCS(0xf8400f6b00, 0xf8400f6b00, 0x7025c4, 0x6f70657200000004)
    /usr/lib/go/src/cmd/go/vcs.go:645 +0xce
main.repoRootForImportPathStatic(0xf8400f6840, 0x7ff90000001e, 0x6ee114, 0x0, 0x400, ...)
    /usr/lib/go/src/cmd/go/vcs.go:388 +0x76f
main.repoRootForImportPath(0xf8400f6840, 0x1e, 0x4, 0x30, 0xf840000438, ...)
    /usr/lib/go/src/cmd/go/vcs.go:323 +0x4e
main.downloadPackage(0xf8400faa00, 0xf8400e5180, 0xf8400f6840, 0xf80000001e)
    /usr/lib/go/src/cmd/go/get.go:242 +0x1192, 0x10000001e, 0x7ff9118cbdb0, 0x100000001, 0x100000000, ...)
    /usr/lib/go/src/cmd/go/get.go:161 +0x7ec
main.runGet(0x89b660, 0xf840083020, 0x100000001, 0x0)
    /usr/lib/go/src/cmd/go/get.go:68 +0xc6
    /usr/lib/go/src/cmd/go/main.go:141 +0x48e
goroutine 2 [syscall]:
created by runtime.main

Copy link

Comment 3 by hongruiqi:

I use the proxychains4 to redirect the socks connection in go get, though useless in
pure go, but may be the cause lead to the error...

Copy link

minux commented Jun 16, 2012

Comment 4:

yes, i think proxychains4 is the root cause.
part of go net library calls libc's dns lookup functions, which get intercepted by
but other part of go use networking syscalls directly, and won't be intercepted by
there is no easy solutions to this problem. transparent socks proxy for 'go get' is
not possible, iiuc.

Copy link

rsc commented Jun 19, 2012

Comment 5:

Which system calls does a transparent socks proxy want to hook into?

Copy link

Comment 6 by hongruiqi:

$ nm 
0000000000206d60 a _DYNAMIC
0000000000206fe8 a _GLOBAL_OFFSET_TABLE_
                 w _Jv_RegisterClasses
0000000000206d50 d __DTOR_END__
0000000000207220 A __bss_start
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000207210 d __dso_handle
                 U __errno_location@@GLIBC_2.2.5
                 w __gmon_start__
0000000000207220 A _edata
00000000011843c8 A _end
0000000000005718 T _fini
0000000000001e28 T _init
                 U abort@@GLIBC_2.2.5
00000000002072a0 b addr_name
                 U atoi@@GLIBC_2.2.5
0000000000005740 r base64
00000000002092c0 b buf.5444
0000000000003819 t calc_alive
000000000000387a t chain_step
                 U close@@GLIBC_2.2.5
0000000000005116 T connect
00000000000039c7 T connect_proxy_chain
000000000000233c T dalias_hash
                 U dlerror@@GLIBC_2.2.5
                 U dlsym@@GLIBC_2.2.5
                 U dup2@@GLIBC_2.2.5
0000000000002579 t encode_base_64
                 U exit@@GLIBC_2.2.5
                 U fclose@@GLIBC_2.2.5
                 U fcntl@@GLIBC_2.2.5
                 U fflush@@GLIBC_2.2.5
                 U fgets@@GLIBC_2.2.5
                 U fopen@@GLIBC_2.2.5
                 U fprintf@@GLIBC_2.2.5
                 U fputs@@GLIBC_2.2.5
                 U free@@GLIBC_2.2.5
0000000000005481 T freeaddrinfo
                 U fwrite@@GLIBC_2.2.5
000000000000478d t get_chain_data
00000000000053f5 T getaddrinfo
                 U getenv@@GLIBC_2.2.5
00000000000055de T gethostbyaddr
00000000000053aa T gethostbyname
                 U gethostent@@GLIBC_2.2.5
                 U gethostname@@GLIBC_2.2.5
00000000000054e3 T getnameinfo
                 U getservbyname@@GLIBC_2.2.5
                 U getsockopt@@GLIBC_2.2.5
                 U gettimeofday@@GLIBC_2.2.5
00000000002092e0 b he.5447
0000000000207260 b hostent_space
                 U htons@@GLIBC_2.2.5
000000000000239f T index_from_internal_ip
                 U inet_addr@@GLIBC_2.2.5
                 U inet_aton@@GLIBC_2.2.5
                 U inet_ntop@@GLIBC_2.2.5
                 U inet_pton@@GLIBC_2.2.5
00000000002092b8 b init_l
00000000000044bc t init_lib
0000000000207240 B internal_ips
0000000000209360 B internal_ips_lock
0000000000209300 b ipv4.5445
0000000000209310 b list.5446
00000000000058ac r local_host
00000000011813c0 B localnet_addr
000000000000244b T make_internal_ip
                 U malloc@@GLIBC_2.2.5
                 U memcpy@@GLIBC_2.14
                 U memset@@GLIBC_2.2.5
                 U ntohl@@GLIBC_2.2.5
                 U ntohs@@GLIBC_2.2.5
00000000002092b0 B num_localnet_addr
                 U perror@@GLIBC_2.2.5
                 U poll@@GLIBC_2.2.5
0000000000002499 t poll_retry
0000000000004252 T proxy_getaddrinfo
0000000000003e91 T proxy_gethostbyname
00000000002093a0 B proxychains_ct
00000000002092a0 B proxychains_got_chain_data
0000000000207218 D proxychains_max_chain
00000000002093c0 B proxychains_pd
00000000002092ac B proxychains_proxy_count
00000000002092a4 B proxychains_quiet_mode
00000000002092a8 B proxychains_resolver
00000000000027cf T proxychains_write_log
                 U pthread_mutex_init@@GLIBC_2.2.5
                 U pthread_mutex_lock@@GLIBC_2.2.5
                 U pthread_mutex_unlock@@GLIBC_2.2.5
                 U rand@@GLIBC_2.2.5
                 U read@@GLIBC_2.2.5
000000000000295b t read_n_bytes
                 U realloc@@GLIBC_2.2.5
0000000000003780 t release_all
00000000000037be t release_busy
000000000020721c D remote_dns_subnet
0000000000207280 b resolved_addr
0000000000207290 b resolved_addr_p
0000000000003615 t select_proxy
                 U send@@GLIBC_2.2.5
                 U snprintf@@GLIBC_2.2.5
                 U socket@@GLIBC_2.2.5
                 U srand@@GLIBC_2.2.5
                 U sscanf@@GLIBC_2.2.5
00000000000034e3 t start_chain
                 U stderr@@GLIBC_2.2.5
                 U strcat@@GLIBC_2.2.5
                 U strchr@@GLIBC_2.2.5
                 U strcmp@@GLIBC_2.2.5
                 U strcpy@@GLIBC_2.2.5
00000000000023d9 T string_from_internal_ip
                 U strlen@@GLIBC_2.2.5
                 U strncpy@@GLIBC_2.2.5
                 U strspn@@GLIBC_2.2.5
                 U strstr@@GLIBC_2.2.5
00000000002093a4 B tcp_connect_time_out
00000000011843c0 B tcp_read_time_out
                 U time@@GLIBC_2.2.5
00000000000029f9 t timed_connect
0000000000209340 B true_connect
0000000000209330 B true_freeaddrinfo
0000000000209320 B true_getaddrinfo
0000000000209338 B true_gethostbyaddr
0000000000209348 B true_gethostbyname
0000000000209328 B true_getnameinfo
0000000000002aff t tunnel_to
                 U vsprintf@@GLIBC_2.2.5
                 U write@@GLIBC_2.2.5
00000000000028ec t write_n_bytes

Copy link

minux commented Jun 19, 2012

Comment 7:

Re #5, current transparent sock proxy only uses dynamic linker tricks
to hook libc implementation of socket functions, and it won't hook any
syscall calls (if it does, then this issue won't exist anymore.)

Copy link

rsc commented Jun 19, 2012

Comment 8:

I'm pretty reluctant, but one thing we could possibly do is say that
if $LD_PRELOAD is set, then we'll use cgo for the connect system call
too. It looks like that would be enough.

Copy link

minux commented Aug 21, 2012

Comment 9:

Labels changed: added priority-later, removed priority-triage.

Status changed to Accepted.

Copy link

rsc commented Sep 12, 2012

Comment 10:

Labels changed: added go1.1maybe.

Copy link

minux commented Nov 29, 2012

Comment 11:

maybe we need to also use execve from libc if LD_PRELOAD is set.

Copy link

robpike commented Mar 7, 2013

Comment 12:

Labels changed: removed go1.1maybe.

Copy link

minux commented Jun 19, 2013

Comment 13:

one complexity of this issue: syscall package couldn't rely on cgo
(or there will be circular dependencies between cmd/cgo and syscall).
of course, we can use the same bootstrap mechanism for cmd/go to solve
this problem, but i'd rather not to complicate the build mechanism for
such small feature.
any suggestions? could we move the connect hook to the net package?
but then, what about the execve hook?

Copy link

rsc commented Jun 21, 2013

Comment 14:

This is looking more and more like a mistake.
Unless someone shows me that it's super-simple, let's not do this.

Copy link

minux commented Jun 30, 2013

Comment 15:

i come up with a simple solution:
we make runtime/cgo pulls in connect and execve from libc (only on unix) privately,
and call it conditionally using 6c code in syscall.
if cgo is available, then runtime/cgo will always be there, so this will work whenever
what do you think, Russ?

Copy link

rsc commented Jul 8, 2013

Comment 16:

It would be easier to judge if you can show me the CL.

Copy link

minux commented Jul 8, 2013

Comment 17:

please take a look at the preliminary version
that implements my idea.

Copy link

minux commented Jul 8, 2013

Comment 18:

CL 11010043 is finished and ready for test and review.
for transparent socks proxy to work, it must support nonblocking sockets.
(for example, tsocks 1.8 doesn't, so it has to be patched with the little
patch below:
--- tsocks-1.8/tsocks.c 2002-07-16 06:50:52.000000000 +0800
+++ tsocks-1.8-hacked/tsocks.c  2013-07-09 06:01:36.540725793 +0800
@@ -326,8 +326,13 @@
       errno = ECONNREFUSED;
    } else {
+      int old_flag = fcntl(__fd, F_GETFL);
+      if(old_flag & O_NONBLOCK)
+             fcntl(__fd, F_SETFL, old_flag & ~O_NONBLOCK);
       /* Now we call the main function to handle the connect. */
       rc = handle_request(newconn);
+      if(old_flag & O_NONBLOCK)
+             fcntl(__fd, F_SETFL, old_flag);
       /* If the request completed immediately it mustn't have been
        * a non blocking socket, in this case we don't need to know
        * about this socket anymore. */

Copy link

rsc commented Jul 30, 2013

Comment 19:

Labels changed: added go1.2maybe.

Copy link

rsc commented Jul 30, 2013

Comment 20:

Labels changed: added feature.

Copy link

rsc commented Aug 1, 2013

Comment 21:

CL 11010043 looks okay, I guess, except that I'm still a bit creeped out by
the whole idea.

Copy link

robpike commented Aug 16, 2013

Comment 22:

Is this "fix" going to be in 1.2?

Copy link

rsc commented Sep 6, 2013

Comment 23:

I replied on the CL. Let's hold off on this.

Labels changed: added go1.3maybe, removed go1.2maybe.

Copy link

rsc commented Nov 27, 2013

Comment 24:

Labels changed: removed feature.

Copy link

rsc commented Dec 4, 2013

Comment 25:

Labels changed: added release-none, removed go1.3maybe.

Copy link

rsc commented Dec 4, 2013

Comment 26:

Labels changed: added repo-main.

@rsc rsc added this to the Unplanned milestone Apr 10, 2015
Copy link

ymmt2005 commented Aug 8, 2016

FWIW, transparent proxy can be done without using LD_PRELOAD.
I have blogged one such solution using Go on Linux.

Copy link

bradfitz commented Sep 9, 2016

I don't think this is ever going to happen.

We don't like calling into C from Go more than we have to, and have moved to minimize when we do so (e.g. we prefer our own DNS resolver when possible).

I agree with the page that @ymmt2005 referenced, which says: "Using iptables is far better than LD_PRELOAD for transparent proxy."

@bradfitz bradfitz closed this as completed Sep 9, 2016
@golang golang locked and limited conversation to collaborators Sep 9, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet

No branches or pull requests

7 participants