tls.go 24 KB

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