5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 04:59:38 +08:00

[v2, windows] Handle webview2 process crashes and add DisableWebViewRendererCodeIntegrity flag (#2627)

* Add flag to disable webview RendererCodeIntegrity checks
* Handle webview2 process crashes
This commit is contained in:
stffabi 2023-04-27 23:03:26 +02:00 committed by GitHub
parent d249c2207b
commit 3853d2d1bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 220 additions and 0 deletions

View File

@ -12,6 +12,7 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"os"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
@ -428,6 +429,9 @@ func (f *Frontend) setupChromium() {
if opts.WebviewGpuIsDisabled { if opts.WebviewGpuIsDisabled {
chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu") chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu")
} }
if opts.WebviewDisableRendererCodeIntegrity {
disableFeatues = append(disableFeatues, "RendererCodeIntegrity")
}
} }
if len(disableFeatues) > 0 { if len(disableFeatues) > 0 {
@ -442,6 +446,37 @@ func (f *Frontend) setupChromium() {
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0) w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
return false return false
} }
chromium.ProcessFailedCallback = func(sender *edge.ICoreWebView2, args *edge.ICoreWebView2ProcessFailedEventArgs) {
kind, err := args.GetProcessFailedKind()
if err != nil {
f.logger.Error("GetProcessFailedKind: %s", err)
return
}
f.logger.Error("WebVie2wProcess failed with kind %d", kind)
switch kind {
case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED:
// => The app has to recreate a new WebView to recover from this failure.
messages := windows.DefaultMessages()
if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.Messages != nil {
messages = f.frontendOptions.Windows.Messages
}
winc.Errorf(f.mainWindow, messages.WebView2ProcessCrash)
os.Exit(-1)
case edge.COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED,
edge.COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED:
// => A new render process is created automatically and navigated to an error page.
// => Make sure that the error page is shown.
if !f.hasStarted {
// NavgiationCompleted didn't come in, make sure the chromium is shown
chromium.Show()
}
if !f.mainWindow.hasBeenShown {
// The window has never been shown, make sure to show it
f.ShowWindow()
}
}
}
chromium.Embed(f.mainWindow.Handle()) chromium.Embed(f.mainWindow.Handle())
chromium.Resize() chromium.Resize()

View File

@ -0,0 +1,49 @@
//go:build windows
package edge
type COREWEBVIEW2_PROCESS_FAILED_KIND uint32
const (
// Indicates that the browser process ended unexpectedly. The WebView
// automatically moves to the Closed state. The app has to recreate a new
// WebView to recover from this failure.
COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED = 0
// Indicates that the main frame's render process ended unexpectedly. A new
// render process is created automatically and navigated to an error page.
// You can use the `Reload` method to try to reload the page that failed.
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED = 1
// Indicates that the main frame's render process is unresponsive.
//
// Note that this does not seem to work right now.
// Does not fire for simple long running script case, the only related test
// SitePerProcessBrowserTest::NoCommitTimeoutForInvisibleWebContents is
// disabled.
COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE = 2
// Indicates that a frame-only render process ended unexpectedly. The process
// exit does not affect the top-level document, only a subset of the
// subframes within it. The content in these frames is replaced with an error
// page in the frame.
COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED = 3
// Indicates that a utility process ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED = 4
// Indicates that a sandbox helper process ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED = 5
// Indicates that the GPU process ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED = 6
// Indicates that a PPAPI plugin process ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED = 7
// Indicates that a PPAPI plugin broker process ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED = 8
// Indicates that a process of unspecified kind ended unexpectedly.
COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED = 9
)

View File

@ -0,0 +1,41 @@
//go:build windows
package edge
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type _ICoreWebView2ProcessFailedEventArgsVtbl struct {
_IUnknownVtbl
GetProcessFailedKind ComProc
}
type ICoreWebView2ProcessFailedEventArgs struct {
vtbl *_ICoreWebView2ProcessFailedEventArgsVtbl
}
func (i *ICoreWebView2ProcessFailedEventArgs) GetProcessFailedKind() (COREWEBVIEW2_PROCESS_FAILED_KIND, error) {
kind := COREWEBVIEW2_PROCESS_FAILED_KIND(0xffffffff)
hr, _, err := i.vtbl.GetProcessFailedKind.Call(
uintptr(unsafe.Pointer(i)),
uintptr(unsafe.Pointer(&kind)),
)
if windows.Handle(hr) != windows.S_OK {
return 0, syscall.Errno(hr)
}
if kind == 0xffffffff {
if err == nil {
err = fmt.Errorf("unknown error")
}
return 0, err
}
return kind, nil
}

View File

@ -0,0 +1,53 @@
//go:build windows
package edge
type _ICoreWebView2ProcessFailedEventHandlerVtbl struct {
_IUnknownVtbl
Invoke ComProc
}
type ICoreWebView2ProcessFailedEventHandler struct {
vtbl *_ICoreWebView2ProcessFailedEventHandlerVtbl
impl _ICoreWebView2ProcessFailedEventHandlerImpl
}
func (i *ICoreWebView2ProcessFailedEventHandler) AddRef() uintptr {
return i.AddRef()
}
func _ICoreWebView2ProcessFailedEventHandlerIUnknownQueryInterface(this *ICoreWebView2ProcessFailedEventHandler, refiid, object uintptr) uintptr {
return this.impl.QueryInterface(refiid, object)
}
func _ICoreWebView2ProcessFailedEventHandlerIUnknownAddRef(this *ICoreWebView2ProcessFailedEventHandler) uintptr {
return this.impl.AddRef()
}
func _ICoreWebView2ProcessFailedEventHandlerIUnknownRelease(this *ICoreWebView2ProcessFailedEventHandler) uintptr {
return this.impl.Release()
}
func _ICoreWebView2ProcessFailedEventHandlerInvoke(this *ICoreWebView2ProcessFailedEventHandler, sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr {
return this.impl.ProcessFailed(sender, args)
}
type _ICoreWebView2ProcessFailedEventHandlerImpl interface {
_IUnknownImpl
ProcessFailed(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr
}
var _ICoreWebView2ProcessFailedEventHandlerFn = _ICoreWebView2ProcessFailedEventHandlerVtbl{
_IUnknownVtbl{
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownQueryInterface),
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownAddRef),
NewComProc(_ICoreWebView2ProcessFailedEventHandlerIUnknownRelease),
},
NewComProc(_ICoreWebView2ProcessFailedEventHandlerInvoke),
}
func newICoreWebView2ProcessFailedEventHandler(impl _ICoreWebView2ProcessFailedEventHandlerImpl) *ICoreWebView2ProcessFailedEventHandler {
return &ICoreWebView2ProcessFailedEventHandler{
vtbl: &_ICoreWebView2ProcessFailedEventHandlerFn,
impl: impl,
}
}

View File

@ -31,6 +31,7 @@ type Chromium struct {
webResourceRequested *iCoreWebView2WebResourceRequestedEventHandler webResourceRequested *iCoreWebView2WebResourceRequestedEventHandler
acceleratorKeyPressed *ICoreWebView2AcceleratorKeyPressedEventHandler acceleratorKeyPressed *ICoreWebView2AcceleratorKeyPressedEventHandler
navigationCompleted *ICoreWebView2NavigationCompletedEventHandler navigationCompleted *ICoreWebView2NavigationCompletedEventHandler
processFailed *ICoreWebView2ProcessFailedEventHandler
environment *ICoreWebView2Environment environment *ICoreWebView2Environment
@ -50,6 +51,7 @@ type Chromium struct {
MessageCallback func(string) MessageCallback func(string)
WebResourceRequestedCallback func(request *ICoreWebView2WebResourceRequest, args *ICoreWebView2WebResourceRequestedEventArgs) WebResourceRequestedCallback func(request *ICoreWebView2WebResourceRequest, args *ICoreWebView2WebResourceRequestedEventArgs)
NavigationCompletedCallback func(sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs) NavigationCompletedCallback func(sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs)
ProcessFailedCallback func(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs)
AcceleratorKeyCallback func(uint) bool AcceleratorKeyCallback func(uint) bool
} }
@ -73,6 +75,7 @@ func NewChromium() *Chromium {
e.webResourceRequested = newICoreWebView2WebResourceRequestedEventHandler(e) e.webResourceRequested = newICoreWebView2WebResourceRequestedEventHandler(e)
e.acceleratorKeyPressed = newICoreWebView2AcceleratorKeyPressedEventHandler(e) e.acceleratorKeyPressed = newICoreWebView2AcceleratorKeyPressedEventHandler(e)
e.navigationCompleted = newICoreWebView2NavigationCompletedEventHandler(e) e.navigationCompleted = newICoreWebView2NavigationCompletedEventHandler(e)
e.processFailed = newICoreWebView2ProcessFailedEventHandler(e)
e.permissions = make(map[CoreWebView2PermissionKind]CoreWebView2PermissionState) e.permissions = make(map[CoreWebView2PermissionKind]CoreWebView2PermissionState)
return e return e
@ -253,6 +256,11 @@ func (e *Chromium) CreateCoreWebView2ControllerCompleted(res uintptr, controller
uintptr(unsafe.Pointer(e.navigationCompleted)), uintptr(unsafe.Pointer(e.navigationCompleted)),
uintptr(unsafe.Pointer(&token)), uintptr(unsafe.Pointer(&token)),
) )
e.webview.vtbl.AddProcessFailed.Call(
uintptr(unsafe.Pointer(e.webview)),
uintptr(unsafe.Pointer(e.processFailed)),
uintptr(unsafe.Pointer(&token)),
)
e.controller.AddAcceleratorKeyPressed(e.acceleratorKeyPressed, &token) e.controller.AddAcceleratorKeyPressed(e.acceleratorKeyPressed, &token)
@ -376,6 +384,13 @@ func (e *Chromium) NavigationCompleted(sender *ICoreWebView2, args *ICoreWebView
return 0 return 0
} }
func (e *Chromium) ProcessFailed(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr {
if e.ProcessFailedCallback != nil {
e.ProcessFailedCallback(sender, args)
}
return 0
}
func (e *Chromium) NotifyParentWindowPositionChanged() error { func (e *Chromium) NotifyParentWindowPositionChanged() error {
//It looks like the wndproc function is called before the controller initialization is complete. //It looks like the wndproc function is called before the controller initialization is complete.
//Because of this the controller is nil //Because of this the controller is nil

View File

@ -478,6 +478,19 @@ func (i *ICoreWebView2) AddNavigationCompleted(eventHandler *ICoreWebView2Naviga
return nil return nil
} }
func (i *ICoreWebView2) AddProcessFailed(eventHandler *ICoreWebView2ProcessFailedEventHandler, token *_EventRegistrationToken) error {
var err error
_, _, err = i.vtbl.AddProcessFailed.Call(
uintptr(unsafe.Pointer(i)),
uintptr(unsafe.Pointer(eventHandler)),
uintptr(unsafe.Pointer(&token)),
)
if err != windows.ERROR_SUCCESS {
return err
}
return nil
}
func (i *ICoreWebView2) OpenDevToolsWindow() error { func (i *ICoreWebView2) OpenDevToolsWindow() error {
var err error var err error
_, _, err = i.vtbl.OpenDevToolsWindow.Call( _, _, err = i.vtbl.OpenDevToolsWindow.Call(

View File

@ -13,6 +13,7 @@ type Messages struct {
PressOKToInstall string PressOKToInstall string
ContactAdmin string ContactAdmin string
InvalidFixedWebview2 string InvalidFixedWebview2 string
WebView2ProcessCrash string
} }
const ( const (
@ -102,6 +103,16 @@ type Options struct {
// WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview // WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview
WebviewGpuIsDisabled bool WebviewGpuIsDisabled bool
// WebviewDisableRendererCodeIntegrity disables the `RendererCodeIntegrity` of WebView2. Some Security Endpoint
// Protection Software inject themself into the WebView2 with unsigned or wrongly signed dlls, which is not allowed
// and will stop the WebView2 processes. Those security software need an update to fix this issue or one can disable
// the integrity check with this flag.
//
// The event viewer log contains `Code Integrity Errors` like mentioned here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/2051
//
// !! Please keep in mind when disabling this feature, this also allows malicious software to inject into the WebView2 !!
WebviewDisableRendererCodeIntegrity bool
} }
func DefaultMessages() *Messages { func DefaultMessages() *Messages {
@ -116,5 +127,6 @@ func DefaultMessages() *Messages {
PressOKToInstall: "Press Ok to install.", PressOKToInstall: "Press Ok to install.",
ContactAdmin: "The WebView2 runtime is required to run this application. Please contact your system administrator.", ContactAdmin: "The WebView2 runtime is required to run this application. Please contact your system administrator.",
InvalidFixedWebview2: "The WebView2 runtime is manually specified, but It is not valid. Check minimum required version and webview2 path.", InvalidFixedWebview2: "The WebView2 runtime is manually specified, but It is not valid. Check minimum required version and webview2 path.",
WebView2ProcessCrash: "The WebView2 process crashed and the application needs to be restarted.",
} }
} }

View File

@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for WebKit2GTK 2.40+ on Linux. This brings additional features for the [AssetServer](/docs/reference/options#assetserver), like support for HTTP Request Bodies. The app must be compiled with the Go build tag `webkit2_40` to activate support for this features. This also bumps the minimum requirement of WebKit2GTK to 2.40 for your app. Added by @stffabi in this [PR](https://github.com/wailsapp/wails/pull/2592) - Added support for WebKit2GTK 2.40+ on Linux. This brings additional features for the [AssetServer](/docs/reference/options#assetserver), like support for HTTP Request Bodies. The app must be compiled with the Go build tag `webkit2_40` to activate support for this features. This also bumps the minimum requirement of WebKit2GTK to 2.40 for your app. Added by @stffabi in this [PR](https://github.com/wailsapp/wails/pull/2592)
- macOS: Added Window menu role with well known shortcuts "Minimize, Full-Screen and Zoom". Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586) - macOS: Added Window menu role with well known shortcuts "Minimize, Full-Screen and Zoom". Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586)
- macOS: Added "Hide, Hide Others, Show All“ to appmenu. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586) - macOS: Added "Hide, Hide Others, Show All“ to appmenu. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2586)
- Windows: Added flag to disable the WebView2 `RendererCodeIntegrity` checks, please see the comment on the flag for more information. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2627)
- Windows: Added handling of WebView2 process crashes, for unrecoverable errors an error message is shown that the app needs to be restarted. If an error occurs that shows a chromium error page, make sure the Window and the WebView2 is visible. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2627)
### Changed ### Changed