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

GOT hook all functions to be interposed #1039

Closed
iapaddler opened this issue Jul 12, 2022 · 5 comments
Closed

GOT hook all functions to be interposed #1039

iapaddler opened this issue Jul 12, 2022 · 5 comments
Assignees
Labels

Comments

@iapaddler
Copy link
Contributor

GOT hook all functions that would otherwise by interposed by ld.so. This is an extension what we do during attach.

@iapaddler iapaddler self-assigned this Jul 12, 2022
@ghost ghost added this to the Next Feature Version (1.2.0) milestone Jul 12, 2022
@iapaddler
Copy link
Contributor Author

iapaddler commented Jul 12, 2022

Turns out that curl does not work when we GOT hook. Because, every shared object has its' own GOT:

readelf -e /lib/x86_64-linux-gnu/libcurl.so.4
[13] .plt.got          PROGBITS         000000000000ecb0  0000ecb0

@iapaddler
Copy link
Contributor Author

iapaddler commented Jul 12, 2022

Allowing all shared objects to be checked for GOT entries enables all data:

{"type":"evt","id":"ubuntu-curl-curl http://wttr.in","_channel":"16582141668938","body":{"sourcetype":"http","_time":1657645094.817934,"source":"http.req","host":"ubuntu","proc":"curl","cmd":"curl http://wttr.in","pid":6951,"data":{"http_method":"GET","http_target":"/","http_flavor":"1.1","http_scheme":"http","http_host":"wttr.in","http_user_agent":"curl/7.68.0","net_transport":"IP.TCP","net_peer_ip":"5.9.243.187","net_peer_port":80,"net_host_ip":"172.16.198.210","net_host_port":39694}}}

Need to determine which objects really should not be examined for GOT entries.

@iapaddler
Copy link
Contributor Author

Discovered an issue where a node app encountered a segfault. It occurs in dlopen(RTLD_LAZY). There are fundamental changes in behavior in an interposed dlopen in support of replacing preload with GOT hooking of all interposed functions. This is due to the fact that all shared objects have their own unique PLT & GOT. Therefore, dlopen() needs to update the GOT of a dynamic loaded object.

It appeared initially to be related to lazy loading. After investigation, much shorter version of a long story, it turns out that the use of errno as a global applied with the internal libc update caused a check of errno to appear as though a strtoull() failed, when it did not actually fail.

The current solution is to create an array of errno values and index from the TID. We need to continue to avoid the use of the %fs register and TLS support in order to maintain proper functionality in Go static apps. Refer to contrib/musl/src/errno/__errno_location.c for details.

@iapaddler
Copy link
Contributor Author

With the internal libc implementation we deliberately made the errno value used by the internal libc not thread specific. We did this to avoid the use of TLS and the %fs register in order to ensure Go apps work without an %fs register context switch.

Given this implementation there are 2 errno values to consider; errno and scope_errno.

errno is set by the application. It should be
used, for the most part, by interposed functions where
results of application behavior needs to be checked. It
should only ever be set by libscope in specific cases.

scope_errno is used by the internal libc.
This value is not thread specific, thread safe.

Use scope_errno only for functions called from the periodic
thread, during libscope constructor, from ldscope or from ldscopedyn.

Other functions, primarily those called from interposed functions, can
not safely reference scope_errno.

References to scope_errno in the context of an application thread were checking for errors in calls to strtoul and strtoull. A check of the return value for max range has replaced the scope_errno checks.

Going forward we will need to be aware of not referencing scope_errno in the context of an application thread. That may be easy to miss or difficult to avoid at which point we may want to change this approach.

@iapaddler
Copy link
Contributor Author

Updated sigSafeNanosleep to not use scope_errno. Get the current RTC, on return if nanosleep was interrupted, get elapsed time and nanosleep again if elapsed time is less than intended.

This represents the short term strategy to not reference scope_errno from an application thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants