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