2025-01-25 12:59:11 +09:00
|
|
|
package seccomp
|
|
|
|
|
|
|
|
import (
|
2025-02-03 18:10:29 +09:00
|
|
|
"io/fs"
|
2025-01-25 12:59:11 +09:00
|
|
|
"os"
|
2025-02-03 18:10:29 +09:00
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
2025-01-25 12:59:11 +09:00
|
|
|
)
|
|
|
|
|
2025-02-03 18:10:29 +09:00
|
|
|
type exporter struct {
|
|
|
|
opts SyscallOpts
|
|
|
|
r, w *os.File
|
|
|
|
|
|
|
|
prepareOnce sync.Once
|
|
|
|
prepareErr error
|
|
|
|
closeErr atomic.Pointer[error]
|
|
|
|
exportErr <-chan error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *exporter) prepare() error {
|
|
|
|
e.prepareOnce.Do(func() {
|
|
|
|
if r, w, err := os.Pipe(); err != nil {
|
|
|
|
e.prepareErr = err
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
e.r, e.w = r, w
|
|
|
|
}
|
|
|
|
|
|
|
|
ec := make(chan error, 1)
|
|
|
|
go func() { ec <- exportFilter(e.w.Fd(), e.opts); close(ec); _ = e.closeWrite() }()
|
|
|
|
e.exportErr = ec
|
|
|
|
runtime.SetFinalizer(e, (*exporter).closeWrite)
|
|
|
|
})
|
|
|
|
return e.prepareErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *exporter) closeWrite() error {
|
|
|
|
if !e.closeErr.CompareAndSwap(nil, &fs.ErrInvalid) {
|
|
|
|
return *e.closeErr.Load()
|
2025-01-25 12:59:11 +09:00
|
|
|
}
|
2025-02-03 18:10:29 +09:00
|
|
|
if e.w == nil {
|
2025-02-07 12:58:20 +09:00
|
|
|
panic("closeWrite called on invalid exporter")
|
2025-01-25 12:59:11 +09:00
|
|
|
}
|
2025-02-03 18:10:29 +09:00
|
|
|
err := e.w.Close()
|
|
|
|
e.closeErr.Store(&err)
|
|
|
|
|
|
|
|
// no need for a finalizer anymore
|
|
|
|
runtime.SetFinalizer(e, nil)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func newExporter(opts SyscallOpts) *exporter {
|
|
|
|
return &exporter{opts: opts}
|
2025-01-25 12:59:11 +09:00
|
|
|
}
|