From eda4d612c2e64321766e1074a698caeae843102a Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 23 Feb 2025 03:24:37 +0900 Subject: [PATCH] fortify: keep external files alive This should eliminate sporadic failures, like the known double close in "seccomp". Signed-off-by: Ophestra --- helper/proc/pipe.go | 12 +++++++++++- helper/seccomp/export.go | 7 ++++++- wl/conn.go | 1 + wl/wayland-bind.c | 2 +- wl/wayland-bind.h | 2 +- wl/wl.go | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/helper/proc/pipe.go b/helper/proc/pipe.go index 92ffe69..838c4ae 100644 --- a/helper/proc/pipe.go +++ b/helper/proc/pipe.go @@ -5,6 +5,7 @@ import ( "errors" "io" "os" + "runtime" ) // 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) 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() { select { case <-done: dispatchErr(nil) case <-ctx.Done(): 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: panic("unreachable") } + runtime.KeepAlive(w) }() go func() { @@ -91,6 +100,7 @@ func (f *statFile) Fulfill(ctx context.Context, dispatchErr func(error)) error { dispatchErr(nil) case <-ctx.Done(): dispatchErr(r.Close()) // this aborts Read with file already closed + runtime.KeepAlive(w) } }() diff --git a/helper/seccomp/export.go b/helper/seccomp/export.go index 52ec414..9efee3b 100644 --- a/helper/seccomp/export.go +++ b/helper/seccomp/export.go @@ -27,7 +27,12 @@ func (e *exporter) prepare() error { } 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 runtime.SetFinalizer(e, (*exporter).closeWrite) }) diff --git a/wl/conn.go b/wl/conn.go index 82c0587..1a7cba6 100644 --- a/wl/conn.go +++ b/wl/conn.go @@ -94,6 +94,7 @@ func bindRawConn(done chan struct{}, rc syscall.RawConn, p, appID, instanceID st // keep socket alive until done is requested <-done + runtime.KeepAlive(syncPipe[1].Fd()) }); err != nil { setupDone <- err } diff --git a/wl/wayland-bind.c b/wl/wayland-bind.c index a177a37..01e8b88 100644 --- a/wl/wayland-bind.c +++ b/wl/wayland-bind.c @@ -23,7 +23,7 @@ static const struct wl_registry_listener registry_listener = { .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 struct wl_display *display; diff --git a/wl/wayland-bind.h b/wl/wayland-bind.h index 67898fc..720dfe4 100644 --- a/wl/wayland-bind.h +++ b/wl/wayland-bind.h @@ -1,3 +1,3 @@ #include -int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd); \ No newline at end of file +int32_t f_bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd); \ No newline at end of file diff --git a/wl/wl.go b/wl/wl.go index da1ed2c..51ad1fd 100644 --- a/wl/wl.go +++ b/wl/wl.go @@ -29,7 +29,7 @@ func bindWaylandFd(socketPath string, fd uintptr, appID, instanceID string, sync if hasNull(appID) || hasNull(instanceID) { 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)] }