tls.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. package ebpftracer
  2. import (
  3. "bufio"
  4. "bytes"
  5. "debug/buildinfo"
  6. "debug/elf"
  7. "errors"
  8. "fmt"
  9. "os"
  10. "regexp"
  11. "strconv"
  12. "strings"
  13. "github.com/cilium/ebpf/link"
  14. "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
  15. "github.com/coroot/coroot-node-agent/proc"
  16. . "github.com/coroot/coroot-node-agent/utils/modelse"
  17. klog "github.com/sirupsen/logrus"
  18. "golang.org/x/arch/arm64/arm64asm"
  19. "golang.org/x/arch/x86/x86asm"
  20. "golang.org/x/mod/semver"
  21. )
  22. const (
  23. minSupportedGoVersion = "v1.15.0"
  24. goTlsWriteSymbol = "crypto/tls.(*Conn).Write"
  25. goTlsReadSymbol = "crypto/tls.(*Conn).Read"
  26. goExecute = "runtime.execute"
  27. goNewproc1 = "runtime.newproc1"
  28. goRunqget = "runtime.runqget"
  29. goServeHTTP = "net/http.serverHandler.ServeHTTP"
  30. goTransport = "net/http.(*Transport).roundTrip"
  31. goHeaderWriteSubset = "net/http.Header.writeSubset"
  32. goGrpcServerHandleStream = "google.golang.org/grpc.(*Server).handleStream"
  33. goGrpcHttp2OperateHeader = "google.golang.org/grpc/internal/transport.(*http2Server).operateHeaders"
  34. goGrpcServerWritestatus = "google.golang.org/grpc/internal/transport.(*http2Server).WriteStatus"
  35. goGrpcClientConnInvoke = "google.golang.org/grpc.(*ClientConn).Invoke"
  36. goGrpcClientLoopyHeaderHandler = "google.golang.org/grpc/internal/transport.(*loopyWriter).headerHandler"
  37. goGrpcHttp2ClientNewStream = "google.golang.org/grpc/internal/transport.(*http2Client).NewStream"
  38. )
  39. var (
  40. opensslVersionRe = regexp.MustCompile(`OpenSSL\s(\d\.\d+\.\d+)`)
  41. )
  42. func (t *Tracer) AttachOpenSslUprobes(pid uint32) ([]link.Link, error) {
  43. if t.DisableL7Tracing() {
  44. return nil, nil
  45. }
  46. libPath, version := getSslLibPathAndVersion(pid)
  47. if libPath == "" || version == "" {
  48. return nil, nil
  49. }
  50. log := func(msg string, err error) {
  51. if err != nil {
  52. for _, s := range []string{"no such file or directory", "no such process", "permission denied"} {
  53. if strings.HasSuffix(err.Error(), s) {
  54. return
  55. }
  56. }
  57. klog.Errorf("pid=%d libssl_version=%s: %s: %s", pid, version, msg, err)
  58. return
  59. }
  60. klog.Infof("pid=%d libssl_version=%s: %s", pid, version, msg)
  61. }
  62. exe, err := link.OpenExecutable(libPath)
  63. if err != nil {
  64. log("failed to open executable", err)
  65. return nil, err
  66. }
  67. var links []link.Link
  68. writeEnter := "openssl_SSL_write_enter"
  69. readEnter := "openssl_SSL_read_enter"
  70. readExEnter := "openssl_SSL_read_ex_enter"
  71. readExit := "openssl_SSL_read_exit"
  72. switch {
  73. case semver.Compare(version, "v3.0.0") >= 0:
  74. writeEnter = "openssl_SSL_write_enter_v3_0"
  75. readEnter = "openssl_SSL_read_enter_v3_0"
  76. readExEnter = "openssl_SSL_read_ex_enter_v3_0"
  77. case semver.Compare(version, "v1.1.1") >= 0:
  78. writeEnter = "openssl_SSL_write_enter_v1_1_1"
  79. readEnter = "openssl_SSL_read_enter_v1_1_1"
  80. readExEnter = "openssl_SSL_read_ex_enter_v1_1_1"
  81. }
  82. type prog struct {
  83. symbol string
  84. uprobe string
  85. uretprobe string
  86. }
  87. progs := []prog{
  88. {symbol: "SSL_write", uprobe: writeEnter},
  89. {symbol: "SSL_read", uprobe: readEnter},
  90. {symbol: "SSL_read", uretprobe: readExit},
  91. }
  92. if semver.Compare(version, "v1.1.1") >= 0 {
  93. progs = append(progs, []prog{
  94. {symbol: "SSL_write_ex", uprobe: writeEnter},
  95. {symbol: "SSL_read_ex", uprobe: readExEnter},
  96. {symbol: "SSL_read_ex", uretprobe: readExit},
  97. }...)
  98. }
  99. for _, p := range progs {
  100. if p.uprobe != "" {
  101. l, err := exe.Uprobe(p.symbol, t.uprobes[p.uprobe], nil)
  102. klog.Infoln("fucktls crypto/tls uprobes attached", p.symbol)
  103. if err != nil {
  104. //log("failed to attach uprobe", err)
  105. klog.Infoln("fucktls crypto/tls uprobes attached error", p.symbol)
  106. return nil, err
  107. }
  108. links = append(links, l)
  109. }
  110. if p.uretprobe != "" {
  111. klog.Infoln("fucktls crypto/tls uprobes attached ret", p.symbol)
  112. l, err := exe.Uretprobe(p.symbol, t.uprobes[p.uretprobe], nil)
  113. if err != nil {
  114. klog.Infoln("fucktls crypto/tls uprobes attached ret error", p.symbol)
  115. //log("failed to attach uretprobe", err)
  116. return nil, err
  117. }
  118. links = append(links, l)
  119. }
  120. }
  121. //log("libssl uprobes attached", nil)
  122. return links, nil
  123. }
  124. func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint16) ([]link.Link, error) {
  125. if t.DisableL7Tracing() {
  126. return nil, nil
  127. }
  128. path := proc.Path(pid, "exe")
  129. instanceID := appInfo.InstanceIdHash.HashtVal
  130. appID := appInfo.AppIdHash.HashtVal
  131. var err error
  132. var name, version string
  133. log := func(msg string, err error) {
  134. if err != nil {
  135. for _, s := range []string{"not a Go executable", "no such file or directory", "no such process", "permission denied"} {
  136. if strings.HasSuffix(err.Error(), s) {
  137. return
  138. }
  139. }
  140. klog.Errorf("pid=%d golang_app=%s golang_version=%s: %s: %s", pid, name, version, msg, err)
  141. return
  142. }
  143. klog.Infof("pid=%d golang_app=%s golang_version=%s: %s", pid, name, version, msg)
  144. }
  145. bi, err := buildinfo.ReadFile(path)
  146. if err != nil {
  147. log("failed to read build info", err)
  148. return nil, err
  149. }
  150. // isGolangApp = true
  151. name, err = os.Readlink(path)
  152. if err != nil {
  153. log("failed to read name", err)
  154. return nil, err
  155. }
  156. version = strings.Replace(bi.GoVersion, "go", "v", 1)
  157. if semver.Compare(version, minSupportedGoVersion) < 0 {
  158. log(fmt.Sprintf("go_versions below %s are not supported", minSupportedGoVersion), nil)
  159. return nil, err
  160. }
  161. ef, err := elf.Open(path)
  162. if err != nil {
  163. log("failed to open as elf binary", err)
  164. return nil, err
  165. }
  166. defer ef.Close()
  167. symbols, err := ef.Symbols()
  168. if err != nil {
  169. if errors.Is(err, elf.ErrNoSymbols) {
  170. log("no symbol section", nil)
  171. return nil, err
  172. }
  173. log("failed to read symbols", err)
  174. return nil, err
  175. }
  176. textSection := ef.Section(".text")
  177. if textSection == nil {
  178. log("no text section", nil)
  179. return nil, err
  180. }
  181. textSectionData, err := textSection.Data()
  182. if err != nil {
  183. log("failed to read text section", err)
  184. return nil, err
  185. }
  186. textSectionLen := uint64(len(textSectionData) - 1)
  187. exe, err := link.OpenExecutable(path)
  188. if err != nil {
  189. log("failed to open executable", err)
  190. return nil, err
  191. }
  192. // 检测 gRPC 版本
  193. var grpcMajorVersion, grpcMinorVersion int
  194. for _, dep := range bi.Deps {
  195. if strings.Contains(dep.Path, "grpc") {
  196. klog.Infoln("Found gRPC dependency:", dep.Path, "version:", dep.Version)
  197. // 解析版本号
  198. version := dep.Version
  199. if version != "" {
  200. // 移除可能的 "v" 前缀
  201. version = strings.TrimPrefix(version, "v")
  202. parts := strings.Split(version, ".")
  203. if len(parts) >= 2 {
  204. major, err := strconv.Atoi(parts[0])
  205. if err != nil {
  206. klog.WithError(err).Warnf("Error parsing major version from %s", parts[0])
  207. continue
  208. }
  209. minor, err := strconv.Atoi(parts[1])
  210. if err != nil {
  211. klog.WithError(err).Warnf("Error parsing minor version from %s", parts[1])
  212. continue
  213. }
  214. klog.Infof("Detected gRPC version: %d.%d for PID %d", major, minor, pid)
  215. grpcMajorVersion = major
  216. grpcMinorVersion = minor
  217. // // 根据版本选择相应的探针策略
  218. // if major == 1 && minor >= 69 {
  219. // klog.Infof("Using modern gRPC handler for version %d.%d", major, minor)
  220. // } else {
  221. // klog.Infof("Using legacy gRPC handler for version %d.%d", major, minor)
  222. // }
  223. }
  224. }
  225. }
  226. }
  227. offset, ok := tracer.GetOffset(tracer.NewID("std", "runtime", "g", "goid"), path)
  228. bucketsOff, ok2 := tracer.GetOffset(tracer.NewID("std", "runtime", "hmap", "buckets"), path)
  229. if ok && ok2 {
  230. realVersion := strings.Replace(bi.GoVersion, "go", "", 1)
  231. parts := strings.Split(realVersion, ".")
  232. var major, minor, revision int
  233. if len(parts) >= 2 {
  234. major, err = strconv.Atoi(parts[0])
  235. if err != nil {
  236. log("Error converting major version:", err)
  237. return nil, err
  238. }
  239. minor, err = strconv.Atoi(parts[1])
  240. if err != nil {
  241. log("Error converting minor version:", err)
  242. return nil, err
  243. }
  244. if len(parts) >= 3 {
  245. revision, err = strconv.Atoi(parts[2])
  246. if err != nil {
  247. log("Error converting revision version:", err)
  248. }
  249. }
  250. goVersion := ((major & 0xFF) << 16) + ((minor & 0xFF) << 8) + min(revision, 255)
  251. info := EbpfProcInfo{}
  252. info.Version = uint32(goVersion)
  253. info.Offsets[OFFSET_IDX_GOID_RUNTIME_G] = uint16(offset)
  254. info.NetTCPConnItab = uint64(0)
  255. info.CryptoTLSConnItab = uint64(0)
  256. info.CredentialsSyscallConnItab = uint64(0)
  257. info.InstanceId = instanceID
  258. info.AppId = appID
  259. info.CodeType = codeType
  260. if grpcMajorVersion >= 1 && grpcMinorVersion >= 60 {
  261. info.IsNewFramePos = 1
  262. } else {
  263. info.IsNewFramePos = 0
  264. }
  265. // go
  266. info.BucketsPtrPos = bucketsOff
  267. fields := map[*uint64]tracer.ID{
  268. &info.MethodPtrPos: tracer.NewID("std", "net/http", "Request", "Method"),
  269. &info.UrlPtrPos: tracer.NewID("std", "net/http", "Request", "URL"),
  270. &info.PathPtrPos: tracer.NewID("std", "net/url", "URL", "Path"),
  271. &info.StatusCodePos: tracer.NewID("std", "net/http", "response", "status"),
  272. &info.RequestHostPos: tracer.NewID("std", "net/http", "Request", "Host"),
  273. &info.ProtoPos: tracer.NewID("std", "net/http", "Request", "Proto"),
  274. &info.CtxPtrPos: tracer.NewID("std", "net/http", "Request", "ctx"),
  275. &info.HeadersPtrPos: tracer.NewID("std", "net/http", "Request", "Header"),
  276. &info.HttpClientNextidPos: tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "http2Client", "nextID"),
  277. &info.StreamMethodPtrPos: tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "Stream", "method"),
  278. &info.StreamCtxPos: tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "Stream", "ctx"),
  279. &info.IoWriterBufPtrPos: tracer.NewID("std", "bufio", "Writer", "buf"),
  280. &info.IoWriterNPos: tracer.NewID("std", "bufio", "Writer", "n"),
  281. }
  282. for field, id := range fields {
  283. off, ok := tracer.GetOffset(id, path)
  284. if !ok {
  285. klog.Warnf("failed to get offset for ID: %v", id)
  286. }
  287. *field = off
  288. }
  289. // 获取内存地址
  290. if appInfo.GoProcCache.StartAddr == 0 && appInfo.GoProcCache.EndAddr == 0 {
  291. allocDetails, allocErr := tracer.Allocate(int(pid))
  292. if allocErr != nil {
  293. return nil, allocErr
  294. }
  295. if allocDetails != nil {
  296. //info.StartAddr = allocDetails.StartAddr
  297. //info.EndAddr = allocDetails.EndAddr
  298. appInfo.GoProcCache.StartAddr = allocDetails.StartAddr
  299. appInfo.GoProcCache.EndAddr = allocDetails.EndAddr
  300. }
  301. }
  302. info.StartAddr = appInfo.GoProcCache.StartAddr
  303. info.EndAddr = appInfo.GoProcCache.EndAddr
  304. klog.Debugln("Major:", major)
  305. klog.Debugln("Minor:", minor)
  306. klog.Debugln("Revision:", revision)
  307. klog.Debugln("goVersion", goVersion)
  308. klog.WithField("pid", pid).Debugln("info.StartAddr", info.StartAddr)
  309. klog.WithField("pid", pid).Debugln("info.EndAddr", info.EndAddr)
  310. _, err = tracer.UpdateProcInfoToMap(t.collection, pid, info)
  311. if err != nil {
  312. klog.Error("failed to update program info", err)
  313. return nil, err
  314. }
  315. appInfo.EBPFProcInfo = &info
  316. }
  317. }
  318. var links []link.Link
  319. for _, s := range symbols {
  320. if elf.ST_TYPE(s.Info) != elf.STT_FUNC || s.Size == 0 {
  321. continue
  322. }
  323. switch s.Name {
  324. case goTlsWriteSymbol, goTlsReadSymbol:
  325. case goExecute, goNewproc1, goRunqget, goServeHTTP, goTransport, goHeaderWriteSubset, goGrpcHttp2OperateHeader, goGrpcServerHandleStream, goGrpcServerWritestatus, goGrpcClientConnInvoke, goGrpcClientLoopyHeaderHandler, goGrpcHttp2ClientNewStream:
  326. default:
  327. continue
  328. }
  329. address := s.Value
  330. for _, p := range ef.Progs {
  331. if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
  332. continue
  333. }
  334. if p.Vaddr <= s.Value && s.Value < (p.Vaddr+p.Memsz) {
  335. address = s.Value - p.Vaddr + p.Off
  336. break
  337. }
  338. }
  339. //fmt.Println("s.Name-----:", s.Name)
  340. switch s.Name {
  341. case goExecute:
  342. l, err := exe.Uprobe(s.Name, t.uprobes["runtime_execute"], &link.UprobeOptions{Address: address})
  343. if err != nil {
  344. log("failed to attach write_enter uprobe", err)
  345. klog.Infoln("runtime.execute no")
  346. return nil, err
  347. } else {
  348. klog.Infoln("runtime.execute ok")
  349. }
  350. links = append(links, l)
  351. case goNewproc1:
  352. l, err := exe.Uprobe(s.Name, t.uprobes["enter_runtime_newproc1"], &link.UprobeOptions{Address: address})
  353. if err != nil {
  354. log("failed to attach newproc1 uprobe", err)
  355. return nil, err
  356. }
  357. links = append(links, l)
  358. sStart := s.Value - textSection.Addr
  359. sEnd := sStart + s.Size
  360. if sEnd > textSectionLen {
  361. continue
  362. }
  363. sBytes := textSectionData[sStart:sEnd]
  364. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  365. if len(returnOffsets) == 0 {
  366. log("failed to attach enter_runtime_newproc1 uprobe", fmt.Errorf("no return offsets found"))
  367. return nil, err
  368. }
  369. for _, offset := range returnOffsets {
  370. l, err := exe.Uprobe(s.Name, t.uprobes["exit_runtime_newproc1"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  371. if err != nil {
  372. log("failed to attach exit_runtime_newproc1 uprobe", err)
  373. return nil, err
  374. }
  375. links = append(links, l)
  376. }
  377. case goRunqget:
  378. l, err := exe.Uprobe(s.Name, t.uprobes["enter_runtime_runqget"], &link.UprobeOptions{Address: address})
  379. if err != nil {
  380. log("failed to attach goRunqget uprobe", err)
  381. return nil, err
  382. }
  383. links = append(links, l)
  384. //sStart := s.Value - textSection.Addr
  385. //sEnd := sStart + s.Size
  386. //if sEnd > textSectionLen {
  387. // continue
  388. //}
  389. //sBytes := textSectionData[sStart:sEnd]
  390. //returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  391. //if len(returnOffsets) == 0 {
  392. // log("failed to attach enter_runtime_newproc1 uprobe", fmt.Errorf("no return offsets found"))
  393. // return nil
  394. //}
  395. //for _, offset := range returnOffsets {
  396. // l, err := exe.Uprobe(s.Name, t.uprobes["exit_runtime_newproc1"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  397. // if err != nil {
  398. // log("failed to attach exit_runtime_newproc1 uprobe", err)
  399. // return nil
  400. // }
  401. // links = append(links, l)
  402. //}
  403. case goGrpcClientConnInvoke:
  404. // 根据 gRPC 版本选择相应的探针
  405. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_ClientConn_Invoke"], &link.UprobeOptions{Address: address})
  406. if err != nil {
  407. klog.WithError(err).Errorf("failed to attach uprobe_ClientConn_Invoke uprobe")
  408. continue
  409. }
  410. klog.Infoln("uprobe_ClientConn_Invoke ok")
  411. links = append(links, l)
  412. sStart := s.Value - textSection.Addr
  413. sEnd := sStart + s.Size
  414. if sEnd > textSectionLen {
  415. continue
  416. }
  417. sBytes := textSectionData[sStart:sEnd]
  418. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  419. if len(returnOffsets) == 0 {
  420. err = fmt.Errorf("failed to attach uprobe_ClientConn_Invoke no return offsets found")
  421. klog.Errorln(err)
  422. return nil, err
  423. }
  424. for _, offset := range returnOffsets {
  425. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_ClientConn_Invoke_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  426. if err != nil {
  427. klog.WithError(err).Errorln(fmt.Errorf("failed to attach uprobe_ClientConn_Invoke_Returns uprobe"))
  428. return nil, err
  429. }
  430. links = append(links, l)
  431. }
  432. case goGrpcClientLoopyHeaderHandler:
  433. // 根据 gRPC 版本选择相应的探针
  434. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_LoopyWriter_HeaderHandler"], &link.UprobeOptions{Address: address})
  435. if err != nil {
  436. klog.WithError(err).Errorf("failed to attach uprobe_LoopyWriter_HeaderHandler uprobe")
  437. continue
  438. }
  439. klog.Infoln("uprobe_LoopyWriter_HeaderHandler ok")
  440. links = append(links, l)
  441. case goGrpcHttp2ClientNewStream:
  442. // 根据 gRPC 版本选择相应的探针
  443. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Client_NewStream"], &link.UprobeOptions{Address: address})
  444. if err != nil {
  445. klog.WithError(err).Errorf("failed to attach uprobe_http2Client_NewStream uprobe")
  446. continue
  447. }
  448. klog.Infoln("uprobe_http2Client_NewStream ok")
  449. links = append(links, l)
  450. case goGrpcHttp2OperateHeader:
  451. // 根据 gRPC 版本选择相应的探针
  452. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Server_operateHeader"], &link.UprobeOptions{Address: address})
  453. if err != nil {
  454. klog.WithError(err).Errorf("failed to attach uprobe_http2Server_operateHeader uprobe")
  455. continue
  456. }
  457. klog.Infoln("uprobe_http2Server_operateHeader ok")
  458. links = append(links, l)
  459. // case goGrpcServerWritestatus:
  460. // // 根据 gRPC 版本选择相应的 WriteStatus 探针
  461. // l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Server_WriteStatus"], &link.UprobeOptions{Address: address})
  462. // if err != nil {
  463. // klog.WithError(err).Errorf("failed to attach uprobe_http2Server_WriteStatus uprobe")
  464. // continue
  465. // }
  466. // links = append(links, l)
  467. case goGrpcServerHandleStream:
  468. // 根据 gRPC 版本选择相应的探针
  469. probeName := t.selectGRPCServerProbe(grpcMajorVersion, grpcMinorVersion)
  470. l, err := exe.Uprobe(s.Name, t.uprobes[probeName], &link.UprobeOptions{Address: address})
  471. if err != nil {
  472. klog.WithError(err).Errorf("failed to attach %s uprobe", probeName)
  473. continue
  474. }
  475. klog.Infof("%s ok (gRPC v%d.%d)", probeName, grpcMajorVersion, grpcMinorVersion)
  476. links = append(links, l)
  477. sStart := s.Value - textSection.Addr
  478. sEnd := sStart + s.Size
  479. klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----111111")
  480. if sEnd > textSectionLen {
  481. continue
  482. }
  483. klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----2222")
  484. sBytes := textSectionData[sStart:sEnd]
  485. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  486. if len(returnOffsets) == 0 {
  487. err = fmt.Errorf("failed to attach uprobe_server_handleStream2 no return offsets found")
  488. klog.Errorln(err)
  489. return nil, err
  490. }
  491. for _, offset := range returnOffsets {
  492. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_server_handleStream_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  493. if err != nil {
  494. klog.WithError(err).Errorln(fmt.Errorf("failed to attach exit_runtime_newproc1 uprobe"))
  495. return nil, err
  496. }
  497. klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----")
  498. links = append(links, l)
  499. }
  500. case goServeHTTP:
  501. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_HandlerFunc_ServeHTTP"], &link.UprobeOptions{Address: address})
  502. if err != nil {
  503. klog.WithError(err).Errorln("failed to attach uprobe_HandlerFunc_ServeHTTP uprobe")
  504. continue
  505. }
  506. klog.Infoln("net/http.serverHandler.ServeHTTP ok")
  507. links = append(links, l)
  508. sStart := s.Value - textSection.Addr
  509. sEnd := sStart + s.Size
  510. if sEnd > textSectionLen {
  511. continue
  512. }
  513. sBytes := textSectionData[sStart:sEnd]
  514. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  515. if len(returnOffsets) == 0 {
  516. err = fmt.Errorf("failed to attach uprobe_HandlerFunc_ServeHTTP no return offsets found")
  517. klog.Errorln(err)
  518. return nil, err
  519. }
  520. for _, offset := range returnOffsets {
  521. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_HandlerFunc_ServeHTTP_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  522. if err != nil {
  523. klog.WithError(err).Errorln(fmt.Errorf("failed to attach exit_runtime_newproc1 uprobe"))
  524. return nil, err
  525. }
  526. links = append(links, l)
  527. }
  528. case goTransport:
  529. if t.DisableE2ETracing() {
  530. continue
  531. }
  532. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_Transport_roundTrip"], &link.UprobeOptions{Address: address})
  533. if err != nil {
  534. klog.WithError(err).Errorln(fmt.Errorf("failed to attach write_enter uprobe"))
  535. continue
  536. } else {
  537. }
  538. klog.Infoln("net/http.uprobe_Transport_roundTrip ok")
  539. links = append(links, l)
  540. sStart := s.Value - textSection.Addr
  541. sEnd := sStart + s.Size
  542. if sEnd > textSectionLen {
  543. continue
  544. }
  545. sBytes := textSectionData[sStart:sEnd]
  546. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  547. if len(returnOffsets) == 0 {
  548. err = fmt.Errorf("failed to attach uprobe_Transport_roundTrip uprobe no return offsets found")
  549. klog.Errorln(err)
  550. return nil, err
  551. }
  552. for _, offset := range returnOffsets {
  553. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_Transport_roundTrip_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  554. if err != nil {
  555. klog.WithError(err).Errorln("failed to attach exit_runtime_newproc1 uprobe")
  556. return nil, err
  557. }
  558. links = append(links, l)
  559. }
  560. case goHeaderWriteSubset:
  561. if t.DisableE2ETracing() {
  562. continue
  563. }
  564. l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_writeSubset"], &link.UprobeOptions{Address: address})
  565. if err != nil {
  566. klog.WithError(err).Errorln("failed to attach uprobe_writeSubset uprobe")
  567. continue
  568. }
  569. klog.Infoln("net/http.Header.writeSubset ok")
  570. links = append(links, l)
  571. case goTlsWriteSymbol:
  572. klog.Infoln("fucktls goTlsWriteSymbol crypto/tls uprobes attached")
  573. l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_write_enter"], &link.UprobeOptions{Address: address})
  574. if err != nil {
  575. klog.WithError(err).Errorln("failed to attach write_enter uprobe")
  576. return nil, err
  577. }
  578. links = append(links, l)
  579. case goTlsReadSymbol:
  580. klog.Infoln("fucktls goTlsReadSymbol crypto/tls uprobes attached")
  581. l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_read_enter"], &link.UprobeOptions{Address: address})
  582. if err != nil {
  583. klog.WithError(err).Errorln("failed to attach read_enter uprobe")
  584. return nil, err
  585. }
  586. links = append(links, l)
  587. sStart := s.Value - textSection.Addr
  588. sEnd := sStart + s.Size
  589. if sEnd > textSectionLen {
  590. continue
  591. }
  592. sBytes := textSectionData[sStart:sEnd]
  593. returnOffsets := getReturnOffsets(ef.Machine, sBytes)
  594. if len(returnOffsets) == 0 {
  595. err = fmt.Errorf("failed to attach read_exit uprobe no return offsets found")
  596. klog.Errorln(err)
  597. return nil, err
  598. }
  599. for _, offset := range returnOffsets {
  600. l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_read_exit"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
  601. if err != nil {
  602. klog.WithError(err).Errorln("failed to attach read_exit uprobe")
  603. return nil, err
  604. }
  605. links = append(links, l)
  606. }
  607. }
  608. }
  609. if len(links) == 0 {
  610. return nil, err
  611. }
  612. klog.Infoln("crypto/tls uprobes attached")
  613. return links, nil
  614. }
  615. func getSslLibPathAndVersion(pid uint32) (string, string) {
  616. f, err := os.Open(proc.Path(pid, "maps"))
  617. if err != nil {
  618. return "", ""
  619. }
  620. defer f.Close()
  621. scanner := bufio.NewScanner(f)
  622. scanner.Split(bufio.ScanLines)
  623. var libsslPath, libcryptoPath string
  624. for scanner.Scan() {
  625. parts := strings.Fields(scanner.Text())
  626. if len(parts) <= 5 {
  627. continue
  628. }
  629. libPath := parts[5]
  630. switch {
  631. case libsslPath == "" && strings.Contains(libPath, "libssl.so"):
  632. fullPath := proc.Path(pid, "root", libPath)
  633. if _, err = os.Stat(fullPath); err == nil {
  634. libsslPath = fullPath
  635. }
  636. case libcryptoPath == "" && strings.Contains(libPath, "libcrypto.so"):
  637. fullPath := proc.Path(pid, "root", libPath)
  638. if _, err = os.Stat(fullPath); err == nil {
  639. libcryptoPath = fullPath
  640. }
  641. default:
  642. continue
  643. }
  644. if libsslPath != "" && libcryptoPath != "" {
  645. break
  646. }
  647. }
  648. if libsslPath == "" || libcryptoPath == "" {
  649. return "", ""
  650. }
  651. ef, err := elf.Open(libcryptoPath)
  652. if err != nil {
  653. return "", ""
  654. }
  655. defer ef.Close()
  656. rodataSection := ef.Section(".rodata")
  657. if rodataSection == nil {
  658. return "", ""
  659. }
  660. rodataSectionData, err := rodataSection.Data()
  661. if err != nil {
  662. return "", ""
  663. }
  664. var version string
  665. for _, b := range bytes.Split(rodataSectionData, []byte("\x00")) {
  666. if len(b) == 0 {
  667. continue
  668. }
  669. s := string(b)
  670. if !strings.HasPrefix(s, "OpenSSL") {
  671. continue
  672. }
  673. if m := opensslVersionRe.FindStringSubmatch(s); len(m) > 1 {
  674. version = m[1]
  675. }
  676. }
  677. return libsslPath, "v" + version
  678. }
  679. // selectGRPCServerProbe 根据 gRPC 版本选择服务端探针
  680. func (t *Tracer) selectGRPCServerProbe(major, minor int) string {
  681. // 根据 gRPC 版本选择相应的探针
  682. if major == 1 && minor >= 69 {
  683. // 现代版本 (>= 1.69.0) 使用新的探针
  684. klog.Infof("Selecting modern gRPC server probe for version %d.%d", major, minor)
  685. return "uprobe_server_handleStream2"
  686. } else {
  687. // 传统版本 (< 1.69.0) 使用旧的探针
  688. klog.Infof("Selecting legacy gRPC server probe for version %d.%d", major, minor)
  689. return "uprobe_server_handleStream"
  690. }
  691. }
  692. func getReturnOffsets(machine elf.Machine, instructions []byte) []int {
  693. var res []int
  694. switch machine {
  695. case elf.EM_X86_64:
  696. for i := 0; i < len(instructions); {
  697. ins, err := x86asm.Decode(instructions[i:], 64)
  698. if err == nil && ins.Op == x86asm.RET {
  699. res = append(res, i)
  700. }
  701. i += ins.Len
  702. }
  703. case elf.EM_AARCH64:
  704. for i := 0; i < len(instructions); {
  705. ins, err := arm64asm.Decode(instructions[i:])
  706. if err == nil && ins.Op == arm64asm.RET {
  707. res = append(res, i)
  708. }
  709. i += 4
  710. }
  711. }
  712. return res
  713. }
  714. func min(a, b int) int {
  715. if a < b {
  716. return a
  717. }
  718. return b
  719. }