syscall_freebsd_test.go 7.3 KB

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