commit | c5c5210fc79ee04d056091e9236e3832bed04927 | [log] [tgz] |
---|---|---|
author | Cliff Smolinsky <cliffsmo@microsoft.com> | Fri May 03 20:51:54 2019 |
committer | Commit Bot <commit-bot@chromium.org> | Fri May 03 20:51:54 2019 |
tree | 67762dc1723cacc6ca85a72cc36d0229757cc4e3 | |
parent | ff2ae4057af7bcc7c150cba26cb8d4aee4ffec9c [diff] |
Ensure user32 and gdi32 do not load in the renderer process The sandboxed renderer process is explicitly blocked from calling into user32 and gdi32 as a result of the Win32k lockdown. As such, there's no reason to even load those dlls in the renderer process. By delayloading all of the dlls necessary to prevent user32 and gdi32 from ever loading into the renderer process we can achieve significant performance improvements by reducing memory usage in every process. This change adds many delayloads to chrome.exe, chrome.dll, and chrome_child.dll. The most important ones are user32, gdi32, shell32, ole32, and shwlapi, but there's additional ones included because they also reference one of the above so the entire chain needs to be done. There's also delayloads added to a few different component dlls, however this change unfortunately does not completely fix the delayloads in a component build because the the base_win_linker_flags cannot be overridden and the sbox_integration_tests and sbox_validation_tests both require the dlls to be statically linked. The reason they must be statically linked is because of an OS bug related to the delayload handler, as described below. It is prohibitively complicated to add the delayloads to every single dll that depends on base, which is why it hasn't been done. One of the biggest considerations for this change is that there is an OS bug in all versions of Windows which causes LoadLibrary to fail and the delayload handler to crash with error code c06d007e (ERROR_MOD_NOT_FOUND) when they run inside the sandboxed process. The issue here is that there is an access check that fails due to the ACL restrictions of the sandboxed process. While this OS bug is unfortunate, it doesn't prevent this change from occurring; rather it just requires that this change ensures no code executes which results in the delayload handler from running. As such, this change adds calls to IsUser32AndGdi32Available and updates all the calls that use GetProcAddress into user32.dll to do proper LoadLibrary calls first. To help make this cleaner, easier, and more consistent, two new methods were created. First, PinUser32() will load user32.dll if not loaded and ensure it is pinned (using a new PinSystemLibrary method) and cannot be unloaded (as there's no good reason to let it unload). It also caches the module handle to avoid subsequent calls to either GetModuleHandleEx or LoadLibraryEx as those can be potentially blocking and are definitely unnecessary once the module is pinned. The second method is GetUser32FunctionPointer which simplifies the process of callers retrieving function pointers by wrapping and hiding the LoadLibrary requirements. The OS bug which causes a crash actually helped with validation, as this allowed for longhaul testing on private builds looking specifically for crashes. This resulted in updates to this change as well as separate changes that have been made to blink, pdfium, and v8 to remove invalid method calls and dll references. A critical part of this change is the update to CommandLine::ParseFromString(). In this change the command line handler explicitly loads api-ms-win-downlevel-shell32-l1-1-0.dll and finds CommandLineToArgvW via the apiset if possible. This is necessary because the standard delayload handler would normally find this method in shell32, however loading shell32 brings in user32 and this prevents the entire change from working. However, the actual implementation is in shcore.dll, not shell32.dll, and the apiset is able to do this forwarding and avoid shell32.dll entirely. This only works on Win10, unfortunately, which is one reason why the performance benefits of this change can only be accomplished on Win10, not Win7. On Win7, the organization and linking of the system dlls will always bring in user32.dll. Finally, this change also adds a new test library, delayloads_unittests, which is modeled after the existing chrome_elf_import_unittests, which ensures the lists of statically linked dlls for the three main binaries cannot be accidentally updated to break this change and it ensures the dlls can be properly loaded without bringing in user32. We've run some perf comparisons on this change and our findings show a reduction in private COW pages (actual, committed private memory) of ~500K per renderer process! Bug: 948829 Change-Id: I9eab10508866bc09e2f78abbe42e51d67f417186 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1551709 Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Scott Violet <sky@chromium.org> Reviewed-by: Bruce Dawson <brucedawson@chromium.org> Reviewed-by: François Doray <fdoray@chromium.org> Commit-Queue: Cliff Smolinsky <cliffsmo@microsoft.com> Cr-Commit-Position: refs/heads/master@{#656516}
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all users to experience the web.
The project's web site is https://www.chromium.org.
Documentation in the source is rooted in docs/README.md.
Learn how to Get Around the Chromium Source Code Directory Structure .