aboutsummaryrefslogtreecommitdiffhomepage
path: root/helper/seccomp/export.go
blob: 6706408f3afa906a50b742059c8c38f486d6870a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package seccomp

import (
	"io/fs"
	"os"
	"runtime"
	"sync"
	"sync/atomic"
)

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()
	}
	if e.w == nil {
		panic("closeWrite called on invalid exporter")
	}
	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}
}