| // Copyright 2023 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| //go:build freebsd | |
| package syscall_test | |
| import ( | |
| "fmt" | |
| "internal/testenv" | |
| "os" | |
| "os/exec" | |
| "path/filepath" | |
| "syscall" | |
| "testing" | |
| "unsafe" | |
| ) | |
| const ( | |
| flagJailCreate = uintptr(0x1) | |
| ) | |
| func prepareJail(t *testing.T) (int, string) { | |
| t.Helper() | |
| root := t.TempDir() | |
| paramPath := []byte("path\x00") | |
| conf := make([]syscall.Iovec, 4) | |
| conf[0].Base = ¶mPath[0] | |
| conf[0].SetLen(len(paramPath)) | |
| p, err := syscall.BytePtrFromString(root) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| conf[1].Base = p | |
| conf[1].SetLen(len(root) + 1) | |
| paramPersist := []byte("persist\x00") | |
| conf[2].Base = ¶mPersist[0] | |
| conf[2].SetLen(len(paramPersist)) | |
| conf[3].Base = nil | |
| conf[3].SetLen(0) | |
| id, _, err1 := syscall.Syscall(syscall.SYS_JAIL_SET, | |
| uintptr(unsafe.Pointer(&conf[0])), uintptr(len(conf)), flagJailCreate) | |
| if err1 != 0 { | |
| t.Fatalf("jail_set: %v", err1) | |
| } | |
| t.Cleanup(func() { | |
| _, _, err1 := syscall.Syscall(syscall.SYS_JAIL_REMOVE, id, 0, 0) | |
| if err1 != 0 { | |
| t.Errorf("failed to cleanup jail: %v", err) | |
| } | |
| }) | |
| return int(id), root | |
| } | |
| func TestJailAttach(t *testing.T) { | |
| if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { | |
| jailed, err := syscall.SysctlUint32("security.jail.jailed") | |
| if err != nil { | |
| fmt.Fprintln(os.Stderr, err) | |
| os.Exit(2) | |
| } | |
| if jailed != 1 { | |
| t.Fatalf("jailed = %d, want 1", jailed) | |
| } | |
| return | |
| } | |
| testenv.MustHaveGoBuild(t) | |
| // Make sure we are running as root, so we have permissions to create | |
| // and remove jails. | |
| if os.Getuid() != 0 { | |
| t.Skip("kernel prohibits jail system calls in unprivileged process") | |
| } | |
| jid, root := prepareJail(t) | |
| // Since jail attach does an implicit chroot to the jail's path, | |
| // we need the binary there, and it must be statically linked. | |
| x := filepath.Join(root, "syscall.test") | |
| cmd := exec.Command(testenv.GoToolPath(t), "test", "-c", "-o", x, "syscall") | |
| cmd.Env = append(os.Environ(), "CGO_ENABLED=0") | |
| if o, err := cmd.CombinedOutput(); err != nil { | |
| t.Fatalf("Build of syscall in jail root failed, output %v, err %v", o, err) | |
| } | |
| cmd = exec.Command("/syscall.test", "-test.run=^TestJailAttach$", "/") | |
| cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") | |
| cmd.SysProcAttr = &syscall.SysProcAttr{Jail: jid} | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| t.Fatalf("Cmd failed with err %v, output: %s", err, out) | |
| } | |
| } |