aboutsummaryrefslogtreecommitdiffhomepage
path: root/sandbox
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-03-17 22:13:22 +0900
committerOphestra <cat@gensokyo.uk>2025-03-17 22:13:22 +0900
commitcc89dbdf63dd8d6025a2158562295a74f923765e (patch)
tree25dd41b1f981c60196b063c3320392ae59e2d65a /sandbox
parent228f3301f2e152855c2b63160945d6d01bb8cb30 (diff)
sandbox: place files with content
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'sandbox')
-rw-r--r--sandbox/container_test.go13
-rw-r--r--sandbox/sequential.go53
2 files changed, 64 insertions, 2 deletions
diff --git a/sandbox/container_test.go b/sandbox/container_test.go
index 41fd849a..c8bdcd0e 100644
--- a/sandbox/container_test.go
+++ b/sandbox/container_test.go
@@ -88,7 +88,8 @@ func TestContainer(t *testing.T) {
Tmpfs("/tmp", 0, 0755).
Bind(os.Args[0], os.Args[0], 0).
Mkdir("/usr/bin").
- Link(os.Args[0], "/usr/bin/sandbox.test")
+ Link(os.Args[0], "/usr/bin/sandbox.test").
+ Place("/etc/hostname", []byte(container.Args[5]))
// in case test has cgo enabled
var libPaths []string
if entries, err := ldd.ExecFilter(ctx,
@@ -109,7 +110,9 @@ func TestContainer(t *testing.T) {
mnt = append(mnt, tc.mnt...)
mnt = append(mnt,
&check.Mntent{FSName: "tmpfs", Dir: "/tmp", Type: "tmpfs", Opts: "host_passthrough"},
- &check.Mntent{FSName: "\x00", Dir: os.Args[0], Type: "\x00", Opts: "\x00"})
+ &check.Mntent{FSName: "\x00", Dir: os.Args[0], Type: "\x00", Opts: "\x00"},
+ &check.Mntent{FSName: "rootfs", Dir: "/etc/hostname", Type: "tmpfs", Opts: "host_passthrough"},
+ )
for _, name := range libPaths {
mnt = append(mnt, &check.Mntent{FSName: "\x00", Dir: name, Type: "\x00", Opts: "\x00", Freq: -1, Passno: -1})
}
@@ -175,6 +178,12 @@ func TestHelperCheckContainer(t *testing.T) {
} else if name != os.Args[5] {
t.Errorf("Hostname: %q, want %q", name, os.Args[5])
}
+
+ if p, err := os.ReadFile("/etc/hostname"); err != nil {
+ t.Fatalf("%v", err)
+ } else if string(p) != os.Args[5] {
+ t.Errorf("/etc/hostname: %q, want %q", string(p), os.Args[5])
+ }
})
t.Run("seccomp", func(t *testing.T) { check.MustAssertSeccomp() })
t.Run("mntent", func(t *testing.T) { check.MustAssertMounts("", "/proc/mounts", "/proc/self/fd/0") })
diff --git a/sandbox/sequential.go b/sandbox/sequential.go
index f9c2e29d..153de0a0 100644
--- a/sandbox/sequential.go
+++ b/sandbox/sequential.go
@@ -6,6 +6,7 @@ import (
"math"
"os"
"path"
+ "slices"
"syscall"
"unsafe"
)
@@ -262,3 +263,55 @@ func (f *Ops) Mkdir(dest string) *Ops {
*f = append(*f, Mkdir(dest))
return f
}
+
+func init() { gob.Register(new(Tmpfile)) }
+
+// Tmpfile places a file in container Path containing Data.
+type Tmpfile struct {
+ Path string
+ Data []byte
+}
+
+func (t *Tmpfile) apply(*Params) error {
+ if !path.IsAbs(t.Path) {
+ return msg.WrapErr(syscall.EBADE,
+ fmt.Sprintf("path %q is not absolute", t.Path))
+ }
+
+ var tmpPath string
+ if f, err := os.CreateTemp("/", "tmp.*"); err != nil {
+ return msg.WrapErr(err, err.Error())
+ } else if _, err = f.Write(t.Data); err != nil {
+ return wrapErrSuffix(err,
+ "cannot write to intermediate file:")
+ } else if err = f.Close(); err != nil {
+ return wrapErrSuffix(err,
+ "cannot close intermediate file:")
+ } else {
+ tmpPath = f.Name()
+ }
+
+ if err := bindMount(tmpPath, t.Path, BindSource|bindAbsolute); err != nil {
+ return err
+ } else if err = os.Remove(tmpPath); err != nil {
+ return msg.WrapErr(err, err.Error())
+ }
+ return nil
+}
+
+func (t *Tmpfile) Is(op Op) bool {
+ vt, ok := op.(*Tmpfile)
+ return ok && t.Path == vt.Path && slices.Equal(t.Data, vt.Data)
+}
+func (*Tmpfile) prefix() string { return "placing" }
+func (t *Tmpfile) String() string {
+ return fmt.Sprintf("tmpfile %q (%d bytes)", t.Path, len(t.Data))
+}
+func (f *Ops) Place(name string, data []byte) *Ops { *f = append(*f, &Tmpfile{name, data}); return f }
+func (f *Ops) PlaceP(name string, dataP **[]byte) *Ops {
+ t := &Tmpfile{Path: name}
+ *dataP = &t.Data
+
+ *f = append(*f, t)
+ return f
+}