forked from security/hakurei
internal/pipewire: handle dangling files in roundtrip
This should not be handled on every receive as it could cause valid (though impossible in current upstream implementation) messages to be rejected and raise a protocol error. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -571,6 +571,36 @@ func (ctx *Context) roundtrip() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
var danglingFiles DanglingFilesError
|
||||||
|
if len(ctx.receivedFiles) > 0 {
|
||||||
|
// having multiple *os.File with the same fd causes serious problems
|
||||||
|
slices.Sort(ctx.receivedFiles)
|
||||||
|
ctx.receivedFiles = slices.Compact(ctx.receivedFiles)
|
||||||
|
|
||||||
|
danglingFiles = make(DanglingFilesError, 0, len(ctx.receivedFiles))
|
||||||
|
for _, fd := range ctx.receivedFiles {
|
||||||
|
// hold these as *os.File so they are closed if this error never reaches the caller,
|
||||||
|
// or the caller discards or otherwise does not handle this error, to avoid leaking fds
|
||||||
|
danglingFiles = append(danglingFiles, os.NewFile(uintptr(fd),
|
||||||
|
"dangling fd "+strconv.Itoa(fd)+" received from PipeWire"))
|
||||||
|
}
|
||||||
|
ctx.receivedFiles = ctx.receivedFiles[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// populated early for finalizers, but does not overwrite existing errors
|
||||||
|
if len(danglingFiles) > 0 && err == nil {
|
||||||
|
err = &ProxyFatalError{Err: danglingFiles, ProxyErrs: ctx.cloneAsProxyErrors()}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// this check must happen after everything else passes
|
||||||
|
if len(ctx.pendingIds) != 0 {
|
||||||
|
err = &ProxyFatalError{Err: UnacknowledgedProxyError(slices.Collect(maps.Keys(ctx.pendingIds))), ProxyErrs: ctx.cloneAsProxyErrors()}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var remaining []byte
|
var remaining []byte
|
||||||
for {
|
for {
|
||||||
remaining, err = ctx.consume(remaining)
|
remaining, err = ctx.consume(remaining)
|
||||||
@@ -595,22 +625,6 @@ func (ctx *Context) roundtrip() (err error) {
|
|||||||
// consume receives messages from the server and processes events.
|
// consume receives messages from the server and processes events.
|
||||||
func (ctx *Context) consume(receiveRemaining []byte) (remaining []byte, err error) {
|
func (ctx *Context) consume(receiveRemaining []byte) (remaining []byte, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// anything before this has already been processed and must not be closed
|
|
||||||
// here, as anything holding onto them will end up with a dangling fd that
|
|
||||||
// can be reused and cause serious problems
|
|
||||||
if len(ctx.receivedFiles) > 0 {
|
|
||||||
ctx.closeReceivedFiles()
|
|
||||||
|
|
||||||
// this catches cases where Roundtrip somehow returns without processing
|
|
||||||
// all received files or preparing an error for dangling files, this is
|
|
||||||
// always overwritten by the fatal error being processed below or made
|
|
||||||
// inaccessible due to repanicking, so if this ends up returned to the
|
|
||||||
// caller it indicates something has gone seriously wrong in Roundtrip
|
|
||||||
if err == nil {
|
|
||||||
err = syscall.ENOTRECOVERABLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r := recover()
|
r := recover()
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return
|
return
|
||||||
@@ -677,34 +691,6 @@ func (ctx *Context) consume(receiveRemaining []byte) (remaining []byte, err erro
|
|||||||
ctx.proxyErrors = append(ctx.proxyErrors, proxyErr)
|
ctx.proxyErrors = append(ctx.proxyErrors, proxyErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepared here so finalizers are set up, but should not prevent proxyErrors
|
|
||||||
// from reaching the caller as those describe the cause of these dangling fds
|
|
||||||
var danglingFiles DanglingFilesError
|
|
||||||
if len(ctx.receivedFiles) > 0 {
|
|
||||||
// having multiple *os.File with the same fd causes serious problems
|
|
||||||
slices.Sort(ctx.receivedFiles)
|
|
||||||
ctx.receivedFiles = slices.Compact(ctx.receivedFiles)
|
|
||||||
|
|
||||||
danglingFiles = make(DanglingFilesError, 0, len(ctx.receivedFiles))
|
|
||||||
for _, fd := range ctx.receivedFiles {
|
|
||||||
// hold these as *os.File so they are closed if this error never reaches the caller,
|
|
||||||
// or the caller discards or otherwise does not handle this error, to avoid leaking fds
|
|
||||||
danglingFiles = append(danglingFiles, os.NewFile(uintptr(fd),
|
|
||||||
"dangling fd "+strconv.Itoa(fd)+" received from PipeWire"))
|
|
||||||
}
|
|
||||||
ctx.receivedFiles = ctx.receivedFiles[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// populated early for finalizers
|
|
||||||
if len(danglingFiles) > 0 {
|
|
||||||
return remaining, danglingFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
// this check must happen after everything else passes
|
|
||||||
if len(ctx.pendingIds) != 0 {
|
|
||||||
return remaining, UnacknowledgedProxyError(slices.Collect(maps.Keys(ctx.pendingIds)))
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user