-
Notifications
You must be signed in to change notification settings - Fork 66
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
Use wasm start-function linking and __cxa_atexit #25
Comments
I'm a little ambivalent about this. First, destruction because to me that's a simpler argument.
In favor of the alternative:
On balance I think it makes sense to go with the alternative for now but I don't have a strong opinion. Construction is more interesting:
In favor of the alternative:
The security issue is an interesting one. It's basically in the general class of "don't have read-write function pointers anywhere it can be helped", and specifically "don't have read-write init function pointers." (and possibly fini function pointers, in the case of Making the constructors not address-taken might be useful though? |
I guess one other advantage of synthesizing a start function would be that if we do LTO, we could inline the init functions into it (and move it to the front of the code section). That seems like a win. And I guess a smart VM could also take advantage by e.g. not running the slow optimized codegen or something. |
And while I still don't really buy the security advantage of protecting the init process itself, keeping the init functions out of the table is probably still good as a means of reducing the amount of code that an attacker could cause to be called in some other context. Ok, so... maybe I'm sold. |
Any concerns about the reentrancy issues with the start function, that forced us to introduce |
I think we should consider separately whether or not to use the wasm start function. How this function is called can be a different discussion than whether or not this start function is linker synthesized. |
I agree with @sbc100; if it turns out that we can't use the wasm start function, we can use the See also WebAssembly/design#1160 for another report of this issue. |
One issue is that plain start-function linking doesn't have an obvious way to implement init function priorities. It could be implemented with linker metadata. It would consist of a list of (function index, priority) pairs. This isn't quite as pretty, but it does retain most of the advantages discussed above. Optionally, it might be nice to continue to use the wasm start function, as a special case for priority 65535, which is the default priority for C++ constructors and |
Related: The new data-segment initialization in the current threads proposal (see specifically https://github.com/WebAssembly/threads/blob/master/proposals/threads/ConditionalSegmentInitialization.md and the discussion at WebAssembly/threads#62) switches data segment initialization from being done implicitly by the VM to being done explicitly, in the start function. This means we'll have to at least have some initialization function that's called during instantiation (i.e. from the start function), at least for threaded code. Maybe we want to just have the same mechanism for that, as for constructors. |
https://reviews.llvm.org/D40759 is now updated with a patch implementing the LLVM side of both the ctor and dtor parts of this proposal, including support for init priorities. |
Summary: This change lays the groundwork lowering of @llvm.global_ctors and @llvm.global_dtors for the wasm object format. Some parts of this patch are subset of: https://reviews.llvm.org/D40759 See WebAssembly/tool-conventions#25 Subscribers: jfb, dschuff, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D41208 llvm-svn=320742
Summary: This change lays the groundwork lowering of @llvm.global_ctors and @llvm.global_dtors for the wasm object format. Some parts of this patch are subset of: https://reviews.llvm.org/D40759 See WebAssembly/tool-conventions#25 Subscribers: jfb, dschuff, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D41208 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@320742 91177308-0d34-0410-b5e6-96231b3b80d8
Summary: - lowers @llvm.global_dtors by adding @llvm.global_ctors functions which register the destructors with `__cxa_atexit`. - impements @llvm.global_ctors with wasm start functions and linker metadata See [here](WebAssembly/tool-conventions#25) for more background. Subscribers: jfb, dschuff, mgorny, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D41211 llvm-svn=320774
Summary: - lowers @llvm.global_dtors by adding @llvm.global_ctors functions which register the destructors with `__cxa_atexit`. - impements @llvm.global_ctors with wasm start functions and linker metadata See [here](WebAssembly/tool-conventions#25) for more background. Subscribers: jfb, dschuff, mgorny, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D41211 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@320774 91177308-0d34-0410-b5e6-96231b3b80d8
This change create a new synthetic function in the final output binary which calls the static constructors in sequence. See: WebAssembly/tool-conventions#25 Differential Revision: https://reviews.llvm.org/D41893 llvm-svn=322388
.init_array/.fini_array and .ctors/.dtors have a history of being exploitable. For example, "Abusing .CTORS and .DTORS For FUN and PROFIT", and other examples are easy to find. Modern ELF systems have mitigated it with RELRO which makes these sections read-only. However, WebAssembly doesn't support read-only memory. This may change in the future (or perhaps we could use a separate linear memory space), though at present there are no proposals. If we implement traditional .init_array/.fini_array support now, we'd be opening up an attack vector.
WebAssembly would be less vulnerable than traditional ELF sysystems without RELRO, because wasm's indirect calls can only call into defined function entry points, and type signatures have to match, however theoretical exploits are still possible.
I propose to avoid
.init_array
and.fini_array
, and instead:.init_array
, as suggested here.__attribute__((destructor))
, into functions registered with__cxa_atext
by initializers. I've implemented this in LLVM here.To be sure, with current
__cxa_atexit
implementations, function pointers are still stored in writeable linear memory, so the problem already exists. However,.init_array
/.fini_array
are dense arrays of pointers, making them easier to hit, and they're more likely to live at a predictable address.__cxa_atexit
is also generally more robust than.fini_array
becauseThis approach also doesn't preclude implementing
.init_array
and.fini_array
in the future. We could always add support for .fini_array in the tools without breaking the ABI.The main downside of this approach is that it's different from how other platforms work, and would require more adaptation when porting libc and other low-level tools. However, I believe it's worth the effort.
The text was updated successfully, but these errors were encountered: