fortify: keep external files alive
All checks were successful
Test / Create distribution (push) Successful in 19s
Test / Run NixOS test (push) Successful in 3m10s

This should eliminate sporadic failures, like the known double close in "seccomp".

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-02-23 03:24:37 +09:00
parent 2e7e160683
commit eda4d612c2
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
6 changed files with 21 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"io" "io"
"os" "os"
"runtime"
) )
// NewWriterTo returns a [File] that receives content from wt on fulfillment. // NewWriterTo returns a [File] that receives content from wt on fulfillment.
@ -25,13 +26,20 @@ func (f *writeToFile) Fulfill(ctx context.Context, dispatchErr func(error)) erro
f.Set(r) f.Set(r)
done := make(chan struct{}) done := make(chan struct{})
go func() { _, err = f.wt.WriteTo(w); dispatchErr(err); dispatchErr(w.Close()); close(done) }() go func() {
_, err = f.wt.WriteTo(w)
dispatchErr(err)
dispatchErr(w.Close())
close(done)
runtime.KeepAlive(r)
}()
go func() { go func() {
select { select {
case <-done: case <-done:
dispatchErr(nil) dispatchErr(nil)
case <-ctx.Done(): case <-ctx.Done():
dispatchErr(w.Close()) // this aborts WriteTo with file already closed dispatchErr(w.Close()) // this aborts WriteTo with file already closed
runtime.KeepAlive(r)
} }
}() }()
@ -83,6 +91,7 @@ func (f *statFile) Fulfill(ctx context.Context, dispatchErr func(error)) error {
default: default:
panic("unreachable") panic("unreachable")
} }
runtime.KeepAlive(w)
}() }()
go func() { go func() {
@ -91,6 +100,7 @@ func (f *statFile) Fulfill(ctx context.Context, dispatchErr func(error)) error {
dispatchErr(nil) dispatchErr(nil)
case <-ctx.Done(): case <-ctx.Done():
dispatchErr(r.Close()) // this aborts Read with file already closed dispatchErr(r.Close()) // this aborts Read with file already closed
runtime.KeepAlive(w)
} }
}() }()

View File

@ -27,7 +27,12 @@ func (e *exporter) prepare() error {
} }
ec := make(chan error, 1) ec := make(chan error, 1)
go func(fd uintptr) { ec <- exportFilter(fd, e.opts); close(ec); _ = e.closeWrite() }(e.w.Fd()) go func(fd uintptr) {
ec <- exportFilter(fd, e.opts)
close(ec)
_ = e.closeWrite()
runtime.KeepAlive(e.w)
}(e.w.Fd())
e.exportErr = ec e.exportErr = ec
runtime.SetFinalizer(e, (*exporter).closeWrite) runtime.SetFinalizer(e, (*exporter).closeWrite)
}) })

View File

@ -94,6 +94,7 @@ func bindRawConn(done chan struct{}, rc syscall.RawConn, p, appID, instanceID st
// keep socket alive until done is requested // keep socket alive until done is requested
<-done <-done
runtime.KeepAlive(syncPipe[1].Fd())
}); err != nil { }); err != nil {
setupDone <- err setupDone <- err
} }

View File

@ -23,7 +23,7 @@ static const struct wl_registry_listener registry_listener = {
.global_remove = registry_handle_global_remove, .global_remove = registry_handle_global_remove,
}; };
int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd) { int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd) {
int32_t res = 0; // refer to resErr for meaning int32_t res = 0; // refer to resErr for meaning
struct wl_display *display; struct wl_display *display;

View File

@ -1,3 +1,3 @@
#include <stdint.h> #include <stdint.h>
int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd); int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd);

View File

@ -29,7 +29,7 @@ func bindWaylandFd(socketPath string, fd uintptr, appID, instanceID string, sync
if hasNull(appID) || hasNull(instanceID) { if hasNull(appID) || hasNull(instanceID) {
return ErrContainsNull return ErrContainsNull
} }
res := C.bind_wayland_fd(C.CString(socketPath), C.int(fd), C.CString(appID), C.CString(instanceID), C.int(syncFD)) res := C.f_bind_wayland_fd(C.CString(socketPath), C.int(fd), C.CString(appID), C.CString(instanceID), C.int(syncFD))
return resErr[int32(res)] return resErr[int32(res)]
} }