syscalls.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package ebpf
  2. import (
  3. "bytes"
  4. "path/filepath"
  5. "runtime"
  6. "strconv"
  7. "strings"
  8. "unsafe"
  9. "github.com/cilium/ebpf/internal/unix"
  10. "github.com/pkg/errors"
  11. )
  12. var errClosedFd = errors.New("use of closed file descriptor")
  13. type bpfFD struct {
  14. raw int64
  15. }
  16. func newBPFFD(value uint32) *bpfFD {
  17. fd := &bpfFD{int64(value)}
  18. runtime.SetFinalizer(fd, (*bpfFD).close)
  19. return fd
  20. }
  21. func (fd *bpfFD) String() string {
  22. return strconv.FormatInt(fd.raw, 10)
  23. }
  24. func (fd *bpfFD) value() (uint32, error) {
  25. if fd.raw < 0 {
  26. return 0, errClosedFd
  27. }
  28. return uint32(fd.raw), nil
  29. }
  30. func (fd *bpfFD) close() error {
  31. if fd.raw < 0 {
  32. return nil
  33. }
  34. value := int(fd.raw)
  35. fd.raw = -1
  36. fd.forget()
  37. return unix.Close(value)
  38. }
  39. func (fd *bpfFD) forget() {
  40. runtime.SetFinalizer(fd, nil)
  41. }
  42. func (fd *bpfFD) dup() (*bpfFD, error) {
  43. if fd.raw < 0 {
  44. return nil, errClosedFd
  45. }
  46. dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0)
  47. if err != nil {
  48. return nil, errors.Wrap(err, "can't dup fd")
  49. }
  50. return newBPFFD(uint32(dup)), nil
  51. }
  52. // bpfObjName is a null-terminated string made up of
  53. // 'A-Za-z0-9_' characters.
  54. type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte
  55. // newBPFObjName truncates the result if it is too long.
  56. func newBPFObjName(name string) (bpfObjName, error) {
  57. idx := strings.IndexFunc(name, invalidBPFObjNameChar)
  58. if idx != -1 {
  59. return bpfObjName{}, errors.Errorf("invalid character '%c' in name '%s'", name[idx], name)
  60. }
  61. var result bpfObjName
  62. copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
  63. return result, nil
  64. }
  65. func invalidBPFObjNameChar(char rune) bool {
  66. switch {
  67. case char >= 'A' && char <= 'Z':
  68. fallthrough
  69. case char >= 'a' && char <= 'z':
  70. fallthrough
  71. case char >= '0' && char <= '9':
  72. fallthrough
  73. case char == '_':
  74. return false
  75. default:
  76. return true
  77. }
  78. }
  79. type bpfMapCreateAttr struct {
  80. mapType MapType
  81. keySize uint32
  82. valueSize uint32
  83. maxEntries uint32
  84. flags uint32
  85. innerMapFd uint32 // since 4.12 56f668dfe00d
  86. numaNode uint32 // since 4.14 96eabe7a40aa
  87. mapName bpfObjName // since 4.15 ad5b177bd73f
  88. }
  89. type bpfMapOpAttr struct {
  90. mapFd uint32
  91. padding uint32
  92. key syscallPtr
  93. value syscallPtr
  94. flags uint64
  95. }
  96. type bpfMapInfo struct {
  97. mapType uint32
  98. id uint32
  99. keySize uint32
  100. valueSize uint32
  101. maxEntries uint32
  102. flags uint32
  103. mapName bpfObjName // since 4.15 ad5b177bd73f
  104. }
  105. type bpfPinObjAttr struct {
  106. fileName syscallPtr
  107. fd uint32
  108. padding uint32
  109. }
  110. type bpfProgLoadAttr struct {
  111. progType ProgramType
  112. insCount uint32
  113. instructions syscallPtr
  114. license syscallPtr
  115. logLevel uint32
  116. logSize uint32
  117. logBuf syscallPtr
  118. kernelVersion uint32 // since 4.1 2541517c32be
  119. progFlags uint32 // since 4.11 e07b98d9bffe
  120. progName bpfObjName // since 4.15 067cae47771c
  121. progIfIndex uint32 // since 4.15 1f6f4cb7ba21
  122. expectedAttachType AttachType // since 4.17 5e43f899b03a
  123. }
  124. type bpfProgInfo struct {
  125. progType uint32
  126. id uint32
  127. tag [unix.BPF_TAG_SIZE]byte
  128. jitedLen uint32
  129. xlatedLen uint32
  130. jited syscallPtr
  131. xlated syscallPtr
  132. loadTime uint64 // since 4.15 cb4d2b3f03d8
  133. createdByUID uint32
  134. nrMapIDs uint32
  135. mapIds syscallPtr
  136. name bpfObjName
  137. }
  138. type bpfProgTestRunAttr struct {
  139. fd uint32
  140. retval uint32
  141. dataSizeIn uint32
  142. dataSizeOut uint32
  143. dataIn syscallPtr
  144. dataOut syscallPtr
  145. repeat uint32
  146. duration uint32
  147. }
  148. type bpfProgAlterAttr struct {
  149. targetFd uint32
  150. attachBpfFd uint32
  151. attachType uint32
  152. attachFlags uint32
  153. }
  154. type bpfObjGetInfoByFDAttr struct {
  155. fd uint32
  156. infoLen uint32
  157. info syscallPtr // May be either bpfMapInfo or bpfProgInfo
  158. }
  159. type bpfGetFDByIDAttr struct {
  160. id uint32
  161. next uint32
  162. }
  163. func newPtr(ptr unsafe.Pointer) syscallPtr {
  164. return syscallPtr{ptr: ptr}
  165. }
  166. func bpfProgLoad(attr *bpfProgLoadAttr) (*bpfFD, error) {
  167. for {
  168. fd, err := bpfCall(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
  169. // As of ~4.20 the verifier can be interrupted by a signal,
  170. // and returns EAGAIN in that case.
  171. if err == unix.EAGAIN {
  172. continue
  173. }
  174. if err != nil {
  175. return nil, err
  176. }
  177. return newBPFFD(uint32(fd)), nil
  178. }
  179. }
  180. func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error {
  181. _, err := bpfCall(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
  182. return err
  183. }
  184. func bpfMapCreate(attr *bpfMapCreateAttr) (*bpfFD, error) {
  185. fd, err := bpfCall(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
  186. if err != nil {
  187. return nil, err
  188. }
  189. return newBPFFD(uint32(fd)), nil
  190. }
  191. func bpfMapLookupElem(m *bpfFD, key, valueOut syscallPtr) error {
  192. fd, err := m.value()
  193. if err != nil {
  194. return err
  195. }
  196. attr := bpfMapOpAttr{
  197. mapFd: fd,
  198. key: key,
  199. value: valueOut,
  200. }
  201. _, err = bpfCall(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  202. return err
  203. }
  204. func bpfMapUpdateElem(m *bpfFD, key, valueOut syscallPtr, flags uint64) error {
  205. fd, err := m.value()
  206. if err != nil {
  207. return err
  208. }
  209. attr := bpfMapOpAttr{
  210. mapFd: fd,
  211. key: key,
  212. value: valueOut,
  213. flags: flags,
  214. }
  215. _, err = bpfCall(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  216. return err
  217. }
  218. func bpfMapDeleteElem(m *bpfFD, key syscallPtr) error {
  219. fd, err := m.value()
  220. if err != nil {
  221. return err
  222. }
  223. attr := bpfMapOpAttr{
  224. mapFd: fd,
  225. key: key,
  226. }
  227. _, err = bpfCall(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  228. return err
  229. }
  230. func bpfMapGetNextKey(m *bpfFD, key, nextKeyOut syscallPtr) error {
  231. fd, err := m.value()
  232. if err != nil {
  233. return err
  234. }
  235. attr := bpfMapOpAttr{
  236. mapFd: fd,
  237. key: key,
  238. value: nextKeyOut,
  239. }
  240. _, err = bpfCall(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  241. return err
  242. }
  243. const bpfFSType = 0xcafe4a11
  244. func bpfPinObject(fileName string, fd *bpfFD) error {
  245. dirName := filepath.Dir(fileName)
  246. var statfs unix.Statfs_t
  247. if err := unix.Statfs(dirName, &statfs); err != nil {
  248. return err
  249. }
  250. if uint64(statfs.Type) != bpfFSType {
  251. return errors.Errorf("%s is not on a bpf filesystem", fileName)
  252. }
  253. value, err := fd.value()
  254. if err != nil {
  255. return err
  256. }
  257. _, err = bpfCall(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{
  258. fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])),
  259. fd: value,
  260. }), 16)
  261. return errors.Wrapf(err, "pin object %s", fileName)
  262. }
  263. func bpfGetObject(fileName string) (*bpfFD, error) {
  264. ptr, err := bpfCall(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{
  265. fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])),
  266. }), 16)
  267. if err != nil {
  268. return nil, errors.Wrapf(err, "get object %s", fileName)
  269. }
  270. return newBPFFD(uint32(ptr)), nil
  271. }
  272. func bpfGetObjectInfoByFD(fd *bpfFD, info unsafe.Pointer, size uintptr) error {
  273. value, err := fd.value()
  274. if err != nil {
  275. return err
  276. }
  277. // available from 4.13
  278. attr := bpfObjGetInfoByFDAttr{
  279. fd: value,
  280. infoLen: uint32(size),
  281. info: newPtr(info),
  282. }
  283. _, err = bpfCall(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  284. return errors.Wrapf(err, "fd %d", value)
  285. }
  286. func bpfGetProgInfoByFD(fd *bpfFD) (*bpfProgInfo, error) {
  287. var info bpfProgInfo
  288. err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
  289. return &info, errors.Wrap(err, "can't get program info")
  290. }
  291. func bpfGetMapInfoByFD(fd *bpfFD) (*bpfMapInfo, error) {
  292. var info bpfMapInfo
  293. err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
  294. return &info, errors.Wrap(err, "can't get map info:")
  295. }
  296. var haveObjName = featureTest{
  297. Fn: func() bool {
  298. name, err := newBPFObjName("feature_test")
  299. if err != nil {
  300. // This really is a fatal error, but it should be caught
  301. // by the unit tests not working.
  302. return false
  303. }
  304. attr := bpfMapCreateAttr{
  305. mapType: Array,
  306. keySize: 4,
  307. valueSize: 4,
  308. maxEntries: 1,
  309. mapName: name,
  310. }
  311. fd, err := bpfMapCreate(&attr)
  312. if err != nil {
  313. return false
  314. }
  315. _ = fd.close()
  316. return true
  317. },
  318. }
  319. func bpfGetMapFDByID(id uint32) (*bpfFD, error) {
  320. // available from 4.13
  321. attr := bpfGetFDByIDAttr{
  322. id: id,
  323. }
  324. ptr, err := bpfCall(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  325. if err != nil {
  326. return nil, errors.Wrapf(err, "can't get fd for map id %d", id)
  327. }
  328. return newBPFFD(uint32(ptr)), nil
  329. }
  330. func bpfGetProgramFDByID(id uint32) (*bpfFD, error) {
  331. // available from 4.13
  332. attr := bpfGetFDByIDAttr{
  333. id: id,
  334. }
  335. ptr, err := bpfCall(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
  336. if err != nil {
  337. return nil, errors.Wrapf(err, "can't get fd for program id %d", id)
  338. }
  339. return newBPFFD(uint32(ptr)), nil
  340. }
  341. func bpfCall(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) {
  342. r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size)
  343. runtime.KeepAlive(attr)
  344. var err error
  345. if errNo != 0 {
  346. err = errNo
  347. }
  348. return r1, err
  349. }
  350. func convertCString(in []byte) string {
  351. inLen := bytes.IndexByte(in, 0)
  352. if inLen == -1 {
  353. return ""
  354. }
  355. return string(in[:inLen])
  356. }