Files
rclone/vfs/vfscommon/recover.go
Nick Craig-Wood 208d7df877 vfs: don't crash the process if a backend panics on a background goroutine GHSA-6jcg-q3wp-x2f4
The VFS calls backends from goroutines of its own. A panic on any of these
cannot be recovered. So a backend panicking on a single file killed the whole
process, taking down a mount or every user of a serve command, even for servers
such as serve http whose library recovers panics raised on its own request
goroutines.

Recover panics at those goroutines and log them with a stack trace. Where the
surrounding code already handles a failure, recover around the backend call
itself rather than the whole goroutine, so a panicking upload is retried like
any other failed upload and a panicking download is reported to the waiters,
instead of abandoning the work part way through and leaving the bookkeeping
inconsistent.

Addresses GHSA-6jcg-q3wp-x2f4
2026-07-31 13:21:59 +01:00

30 lines
808 B
Go

package vfscommon
import (
"fmt"
"runtime/debug"
"github.com/rclone/rclone/fs"
)
// RecoverPanic recovers a panic, logs it against o with a stack trace and,
// if err is not nil, stores it there. Use it as `defer RecoverPanic(o, &err)`.
func RecoverPanic(o any, err *error) {
if r := recover(); r != nil {
fs.Errorf(o, "panic: %v\n%s", r, debug.Stack())
if err != nil {
*err = fmt.Errorf("panic: %v", r)
}
}
}
// RecoverCall calls fn, converting a panic into an error.
//
// Prefer this to recovering a whole goroutine where the caller already
// handles an error, so a panic is retried or reported the same way a failure
// is, rather than abandoning the surrounding work part way through.
func RecoverCall(o any, fn func() error) (err error) {
defer RecoverPanic(o, &err)
return fn()
}