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 }