golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/syscall_freebsd_test.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build freebsd
     6  
     7  package unix_test
     8  
     9  import (
    10  	"flag"
    11  	"fmt"
    12  	"net"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"testing"
    18  
    19  	"golang.org/x/sys/unix"
    20  )
    21  
    22  func TestSysctlUint64(t *testing.T) {
    23  	_, err := unix.SysctlUint64("vm.swap_total")
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  }
    28  
    29  // FIXME: Infrastructure for launching tests in subprocesses stolen from openbsd_test.go - refactor?
    30  // testCmd generates a proper command that, when executed, runs the test
    31  // corresponding to the given key.
    32  
    33  type testProc struct {
    34  	fn      func() // should always exit instead of returning
    35  	success bool   // whether zero-exit means success or failure
    36  }
    37  
    38  var (
    39  	testProcs = map[string]testProc{}
    40  	procName  = ""
    41  	procArg   = ""
    42  )
    43  
    44  const (
    45  	optName = "sys-unix-internal-procname"
    46  	optArg  = "sys-unix-internal-arg"
    47  )
    48  
    49  func init() {
    50  	flag.StringVar(&procName, optName, "", "internal use only")
    51  	flag.StringVar(&procArg, optArg, "", "internal use only")
    52  
    53  }
    54  
    55  func testCmd(procName string, procArg string) (*exec.Cmd, error) {
    56  	exe, err := filepath.Abs(os.Args[0])
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	cmd := exec.Command(exe, "-"+optName+"="+procName, "-"+optArg+"="+procArg)
    61  	cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
    62  	return cmd, nil
    63  }
    64  
    65  // ExitsCorrectly is a comprehensive, one-line-of-use wrapper for testing
    66  // a testProc with a key.
    67  func ExitsCorrectly(t *testing.T, procName string) {
    68  	s := testProcs[procName]
    69  	c, err := testCmd(procName, t.TempDir())
    70  	if err != nil {
    71  		t.Fatalf("Failed to construct command for %s", procName)
    72  	}
    73  	if (c.Run() == nil) != s.success {
    74  		result := "succeed"
    75  		if !s.success {
    76  			result = "fail"
    77  		}
    78  		t.Fatalf("Process did not %s when it was supposed to", result)
    79  	}
    80  }
    81  
    82  func TestMain(m *testing.M) {
    83  	flag.Parse()
    84  	if procName != "" {
    85  		t := testProcs[procName]
    86  		t.fn()
    87  		os.Stderr.WriteString("test function did not exit\n")
    88  		if t.success {
    89  			os.Exit(1)
    90  		} else {
    91  			os.Exit(0)
    92  		}
    93  	}
    94  	os.Exit(m.Run())
    95  }
    96  
    97  // end of infrastructure
    98  
    99  const testfile = "gocapmodetest"
   100  const testfile2 = testfile + "2"
   101  
   102  func CapEnterTest() {
   103  	_, err := os.OpenFile(filepath.Join(procArg, testfile), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   104  	if err != nil {
   105  		panic(fmt.Sprintf("OpenFile: %s", err))
   106  	}
   107  
   108  	err = unix.CapEnter()
   109  	if err != nil {
   110  		panic(fmt.Sprintf("CapEnter: %s", err))
   111  	}
   112  
   113  	_, err = os.OpenFile(filepath.Join(procArg, testfile2), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   114  	if err == nil {
   115  		panic("OpenFile works!")
   116  	}
   117  	if err.(*os.PathError).Err != unix.ECAPMODE {
   118  		panic(fmt.Sprintf("OpenFile failed wrong: %s %#v", err, err))
   119  	}
   120  	os.Exit(0)
   121  }
   122  
   123  func init() {
   124  	testProcs["cap_enter"] = testProc{
   125  		CapEnterTest,
   126  		true,
   127  	}
   128  }
   129  
   130  func TestCapEnter(t *testing.T) {
   131  	if runtime.GOARCH != "amd64" {
   132  		t.Skipf("skipping test on %s", runtime.GOARCH)
   133  	}
   134  	ExitsCorrectly(t, "cap_enter")
   135  }
   136  
   137  func OpenatTest() {
   138  	f, err := os.Open(procArg)
   139  	if err != nil {
   140  		panic(err)
   141  	}
   142  
   143  	err = unix.CapEnter()
   144  	if err != nil {
   145  		panic(fmt.Sprintf("CapEnter: %s", err))
   146  	}
   147  
   148  	fxx, err := unix.Openat(int(f.Fd()), "xx", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   149  	if err != nil {
   150  		panic(err)
   151  	}
   152  	unix.Close(fxx)
   153  
   154  	// The right to open BASE/xx is not ambient
   155  	_, err = os.OpenFile(procArg+"/xx", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   156  	if err == nil {
   157  		panic("OpenFile succeeded")
   158  	}
   159  	if err.(*os.PathError).Err != unix.ECAPMODE {
   160  		panic(fmt.Sprintf("OpenFile failed wrong: %s %#v", err, err))
   161  	}
   162  
   163  	// Can't make a new directory either
   164  	err = os.Mkdir(procArg+"2", 0777)
   165  	if err == nil {
   166  		panic("MKdir succeeded")
   167  	}
   168  	if err.(*os.PathError).Err != unix.ECAPMODE {
   169  		panic(fmt.Sprintf("Mkdir failed wrong: %s %#v", err, err))
   170  	}
   171  
   172  	// Remove all caps except read and lookup.
   173  	r, err := unix.CapRightsInit([]uint64{unix.CAP_READ, unix.CAP_LOOKUP})
   174  	if err != nil {
   175  		panic(fmt.Sprintf("CapRightsInit failed: %s %#v", err, err))
   176  	}
   177  	err = unix.CapRightsLimit(f.Fd(), r)
   178  	if err != nil {
   179  		panic(fmt.Sprintf("CapRightsLimit failed: %s %#v", err, err))
   180  	}
   181  
   182  	// Check we can get the rights back again
   183  	r, err = unix.CapRightsGet(f.Fd())
   184  	if err != nil {
   185  		panic(fmt.Sprintf("CapRightsGet failed: %s %#v", err, err))
   186  	}
   187  	b, err := unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_LOOKUP})
   188  	if err != nil {
   189  		panic(fmt.Sprintf("CapRightsIsSet failed: %s %#v", err, err))
   190  	}
   191  	if !b {
   192  		panic("Unexpected rights")
   193  	}
   194  	b, err = unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_LOOKUP, unix.CAP_WRITE})
   195  	if err != nil {
   196  		panic(fmt.Sprintf("CapRightsIsSet failed: %s %#v", err, err))
   197  	}
   198  	if b {
   199  		panic("Unexpected rights (2)")
   200  	}
   201  
   202  	// Can no longer create a file
   203  	_, err = unix.Openat(int(f.Fd()), "xx2", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   204  	if err == nil {
   205  		panic("Openat succeeded")
   206  	}
   207  	if err != unix.ENOTCAPABLE {
   208  		panic(fmt.Sprintf("OpenFileAt failed wrong: %s %#v", err, err))
   209  	}
   210  
   211  	// But can read an existing one
   212  	_, err = unix.Openat(int(f.Fd()), "xx", os.O_RDONLY, 0666)
   213  	if err != nil {
   214  		panic(fmt.Sprintf("Openat failed: %s %#v", err, err))
   215  	}
   216  
   217  	os.Exit(0)
   218  }
   219  
   220  func init() {
   221  	testProcs["openat"] = testProc{
   222  		OpenatTest,
   223  		true,
   224  	}
   225  }
   226  
   227  func TestOpenat(t *testing.T) {
   228  	if runtime.GOARCH != "amd64" {
   229  		t.Skipf("skipping test on %s", runtime.GOARCH)
   230  	}
   231  	ExitsCorrectly(t, "openat")
   232  }
   233  
   234  func TestCapRightsSetAndClear(t *testing.T) {
   235  	r, err := unix.CapRightsInit([]uint64{unix.CAP_READ, unix.CAP_WRITE, unix.CAP_PDWAIT})
   236  	if err != nil {
   237  		t.Fatalf("CapRightsInit failed: %s", err)
   238  	}
   239  
   240  	err = unix.CapRightsSet(r, []uint64{unix.CAP_EVENT, unix.CAP_LISTEN})
   241  	if err != nil {
   242  		t.Fatalf("CapRightsSet failed: %s", err)
   243  	}
   244  
   245  	b, err := unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_WRITE, unix.CAP_PDWAIT, unix.CAP_EVENT, unix.CAP_LISTEN})
   246  	if err != nil {
   247  		t.Fatalf("CapRightsIsSet failed: %s", err)
   248  	}
   249  	if !b {
   250  		t.Fatalf("Wrong rights set")
   251  	}
   252  
   253  	err = unix.CapRightsClear(r, []uint64{unix.CAP_READ, unix.CAP_PDWAIT})
   254  	if err != nil {
   255  		t.Fatalf("CapRightsClear failed: %s", err)
   256  	}
   257  
   258  	b, err = unix.CapRightsIsSet(r, []uint64{unix.CAP_WRITE, unix.CAP_EVENT, unix.CAP_LISTEN})
   259  	if err != nil {
   260  		t.Fatalf("CapRightsIsSet failed: %s", err)
   261  	}
   262  	if !b {
   263  		t.Fatalf("Wrong rights set")
   264  	}
   265  }
   266  
   267  func TestGetsockoptXucred(t *testing.T) {
   268  	fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
   269  	if err != nil {
   270  		t.Fatalf("Socketpair: %v", err)
   271  	}
   272  
   273  	srvFile := os.NewFile(uintptr(fds[0]), "server")
   274  	cliFile := os.NewFile(uintptr(fds[1]), "client")
   275  	defer srvFile.Close()
   276  	defer cliFile.Close()
   277  
   278  	srv, err := net.FileConn(srvFile)
   279  	if err != nil {
   280  		t.Fatalf("FileConn: %v", err)
   281  	}
   282  	defer srv.Close()
   283  
   284  	cli, err := net.FileConn(cliFile)
   285  	if err != nil {
   286  		t.Fatalf("FileConn: %v", err)
   287  	}
   288  	defer cli.Close()
   289  
   290  	cred, err := unix.GetsockoptXucred(fds[1], unix.SOL_LOCAL, unix.LOCAL_PEERCRED)
   291  	if err == unix.ENOTCONN {
   292  		t.Skip("GetsockoptXucred not supported with Socketpair on FreeBSD 11 and earlier")
   293  	} else if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  	t.Logf("got: %+v", cred)
   297  	if got, want := cred.Uid, os.Getuid(); int(got) != int(want) {
   298  		t.Errorf("uid = %v; want %v", got, want)
   299  	}
   300  }
   301  
   302  // stringsFromByteSlice converts a sequence of attributes to a []string.
   303  // On FreeBSD, each entry consists of a single byte containing the length
   304  // of the attribute name, followed by the attribute name.
   305  // The name is _not_ NULL-terminated.
   306  func stringsFromByteSlice(buf []byte) []string {
   307  	var result []string
   308  	i := 0
   309  	for i < len(buf) {
   310  		next := i + 1 + int(buf[i])
   311  		result = append(result, string(buf[i+1:next]))
   312  		i = next
   313  	}
   314  	return result
   315  }