ecapture icon indicating copy to clipboard operation
ecapture copied to clipboard

ecapture runngin crashed: segmentation violation

Open xxxxxliil opened this issue 1 year ago • 6 comments

Describe the bug 最近的两个版本,0.8.4 和 0.8.5 在 arch 中运行都会出现一样的 SIGSEGV: segmentation violation 不一定总是在 Module.run() 出现问题,在 https server starting...You can update the configuration file via the HTTP interface.BPF bytecode file is matched. bpfFileName=user/bytecode/openssl_3_0_0_kern_core.o 但是最常出现的就是前两个输出后立刻 segmentation violation

To Reproduce Steps to reproduce the behavior:

  1. download ecapture from releases page
  2. # ./ecapture [any command]
  3. starting
  4. See error

Expected behavior 正常捕获内容

Screenshots https://fars.ee/b9La V.log https://fars.ee/gU9L V2.log https://fars.ee/_SWJ v3.log V3.log

Linux Server/Android (please complete the following information):

  • Env:
---------------------------------------
eCapture Makefile Environment:
---------------------------------------
PARALLEL                 4
----------------[ from args ]---------------
CROSS_ARCH               
ANDROID                  0
DEBUG                    0
SNAPSHOT_VERSION         
---------------------------------------
HOST_ARCH                x86_64
UNAME_R                  6.10.6-zen1-1-zen
CLANG_VERSION            18
GO_VERSION               1.23
---------------------------------------
CMD_CLANG                clang
CMD_GIT                  git
CMD_GO                   go
CMD_INSTALL              install
CMD_LLC                  llc
CMD_MD5                  md5sum
CMD_PKGCONFIG            pkg-config
CMD_STRIP                llvm-strip
CMD_CC_PREFIX            
CMD_TAR                  tar
CMD_RPMBUILD             rpmbuild
CMD_RPM_SETUP_TREE       rpmdev-setuptree
---------------------------------------
VERSION_NUM              0.8.5-20240819-35cc757
LAST_GIT_TAG             0.8.5-20240819-35cc757
BPF_NOCORE_TAG           6_10_6-zen1-1-zen.0_8_5-20240819-35cc757
KERN_RELEASE             6.10.6-zen1-1-zen
KERN_BUILD_PATH          /lib/modules/6.10.6-zen1-1-zen/build
KERN_SRC_PATH            /lib/modules/6.10.6-zen1-1-zen/build
TARGET_ARCH              x86_64
GOARCH                   amd64
LINUX_ARCH               x86
LIBPCAP_ARCH             x86_64-pc-linux-gnu
AUTOGENCMD               test -f kern/bpf/x86/vmlinux.h || bpftool btf dump file /sys/kernel/btf/vmlinux format c > kern/bpf/x86/vmlinux.h
PACKAGE_VERSION          0.0.0
OUT_DEB_FILE             ./bin/ecapture_v0.0.0_linux_amd64.deb
--------------------------------------

  • OS: arch
  • Arch: amd64/x86-64
  • Kernel Version: in Env
  • Version: linux_amd64:v0.8.5:6.5.0-1025-azure

Additional context 在 #581 提及过一次

xxxxxliil avatar Aug 25 '24 03:08 xxxxxliil

你在目标机器上自己编译一次,会有问题吗?

cfc4n avatar Aug 25 '24 03:08 cfc4n

你在目标机器上自己编译一次,会有问题吗?

正常使用

xxxxxliil avatar Aug 25 '24 03:08 xxxxxliil

OK, 就像#581 里提到的,我需要一个准确的重现办法,你知道这个问题的关键因素吗?

cfc4n avatar Aug 25 '24 03:08 cfc4n

OK, 就像#581 里提到的,我需要一个准确的重现办法,你知道这个问题的关键因素吗?

目前不知道,因为当前分发的文件里没有 debug 符号,看 syscall 也什么都看不出。不过理论上应该开个 arch 容器或者 vm 就能有一样的复现环境了

xxxxxliil avatar Aug 25 '24 03:08 xxxxxliil

在类 Arch 发行版上可以复现,容器下运行没有问题

Zheaoli avatar Aug 25 '24 15:08 Zheaoli

因为二进制是动态加载的。。得花点时间排查下了。。

Zheaoli avatar Aug 25 '24 16:08 Zheaoli

下载了 0.7.3、0.7.7、0.8.0、0.8.2、0.8.1 这五个历史版本,发现从 0.8.1 开始使用任何子命令都会崩溃,同时尝试在 fedora 40 编译 a2cb6ef 也会崩溃

2024-09-01T21:29:26+08:00 INF AppName="eCapture(旁观者)"
2024-09-01T21:29:26+08:00 INF HomePage=https://ecapture.cc
2024-09-01T21:29:26+08:00 INF Repository=https://github.com/gojue/ecapture
2024-09-01T21:29:26+08:00 INF Author="CFC4N <[email protected]>"
2024-09-01T21:29:26+08:00 INF Description="Capturing SSL/TLS plaintext without a CA certificate using eBPF. Supported on Linux/Android kernels for amd64/arm64."
2024-09-01T21:29:26+08:00 INF Version=linux_amd64:0.8.5-20240829-a2cb6ef:[CORE]
2024-09-01T21:29:26+08:00 INF Listen=localhost:28256
2024-09-01T21:29:26+08:00 INF eCapture running logs logger=
2024-09-01T21:29:26+08:00 INF the file handler that receives the captured event eventCollector=
2024-09-01T21:29:26+08:00 WRN ========== module starting. ==========
2024-09-01T21:29:26+08:00 INF listen=localhost:28256
2024-09-01T21:29:26+08:00 INF https server starting...You can update the configuration file via the HTTP interface.
2024-09-01T21:29:26+08:00 INF Kernel Info=6.10.7 Pid=407846
2024-09-01T21:29:26+08:00 INF BTF bytecode mode: CORE. btfMode=0
2024-09-01T21:29:26+08:00 INF master key keylogger has been set. eBPFProgramType=KeyLog keylogger=ecapture_openssl_key.og
2024-09-01T21:29:26+08:00 INF module initialization. isReload=false moduleName=EBPFProbeOPENSSL
2024-09-01T21:29:26+08:00 INF Module.Run()
2024-09-01T21:29:26+08:00 INF OpenSSL/BoringSSL version found sslVersion="openssl 3.3.1"
2024-09-01T21:29:26+08:00 INF HOOK type:Openssl elf ElfType=2 binrayPath=/lib64/libssl.so.3 masterHookFuncs=["SSL_get_wbio","SSL_in_before","SSL_do_handshake"]
2024-09-01T21:29:26+08:00 INF target all process.
2024-09-01T21:29:26+08:00 INF target all users.
2024-09-01T21:29:26+08:00 INF setupManagers eBPFProgramType=KeyLog
2024-09-01T21:29:26+08:00 INF BPF bytecode file is matched. bpfFileName=user/bytecode/openssl_3_2_0_kern_core.o
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.

Thread 4 "ecapture" received signal SIGFPE, Arithmetic exception.
[Switching to LWP 407852]
0x00007fffb0178641 in __libc_early_init () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007fffb0178641 in __libc_early_init () from /usr/lib/libc.so.6
#1  0x0000000000c25ed7 in dl_open_worker_begin ()
#2  0x0000000000c13e20 in _dl_catch_exception ()
#3  0x0000000000c24f8f in dl_open_worker ()
#4  0x0000000000c13e20 in _dl_catch_exception ()
#5  0x0000000000c25332 in _dl_open ()
#6  0x0000000000c184ba in do_dlopen ()
#7  0x0000000000c13e20 in _dl_catch_exception ()
#8  0x0000000000c13ec9 in _dl_catch_error ()
#9  0x0000000000c1874e in __libc_dlopen_mode ()
#10 0x0000000000c2296d in module_load ()
#11 0x0000000000c22d55 in __nss_module_get_function ()
#12 0x0000000000bc7553 in getaddrinfo ()
#13 0x0000000000b5d0c7 in _cgo_97ab22c4dc7b_C2func_getaddrinfo (v=0xc00005e5a8) at cgo-gcc-prolog:60
#14 0x0000000000473364 in runtime.asmcgocall.abi0 ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

如果 go 的编译阶段在 arch 上进行则运行正常,如果在 fedora 进行则会崩溃

xxxxxliil avatar Sep 01 '24 13:09 xxxxxliil

近期我抽空测试一下。 总是卡在vm安装arch系统这里,很繁琐。

cfc4n avatar Sep 01 '24 13:09 cfc4n

近期我抽空测试一下。 总是卡在vm安装arch系统这里,很繁琐。

不用特地安装 arch,相似的测试环境选 manjaro 即可。如果必须必须选 arch,启动 archiso 就是一个干净的测试环境

xxxxxliil avatar Sep 01 '24 13:09 xxxxxliil

目前看起来是因为提前预编译的二进制文件,在 cast 地址的时候因为不对齐出现了 segement fault

我的建议是这个问题不太好解决,因为需要要求客户锁依赖。最好的方式是通过容器运行,保证二进制的一致性

Zheaoli avatar Sep 01 '24 15:09 Zheaoli

我的建议是这个问题不太好解决,因为需要要求客户锁依赖。最好的方式是通过容器运行,保证二进制的一致性

但是只有从 0.8.1 开始才会出问题,会是哪个 commit 引入的问题呢?

xxxxxliil avatar Sep 01 '24 15:09 xxxxxliil

但是只有从 0.8.1 开始才会出问题,会是哪个 commit 引入的问题呢?

哦?那我来 bisect 一下

Zheaoli avatar Sep 01 '24 16:09 Zheaoli

我的建议是这个问题不太好解决,因为需要要求客户锁依赖。最好的方式是通过容器运行,保证二进制的一致性

但是只有从 0.8.1 开始才会出问题,会是哪个 commit 引入的问题呢?

我还没有重现,我的猜测应该是启用CGO引入libpcap类库后,编译环境的C类库跟运行的环境有差异。

编译构建的环境,期望是可以兼容更多内核的。 如果问题是这里的话,那确实不太好解决。

cfc4n avatar Sep 01 '24 16:09 cfc4n

我的建议是这个问题不太好解决,因为需要要求客户锁依赖。最好的方式是通过容器运行,保证二进制的一致性

但是只有从 0.8.1 开始才会出问题,会是哪个 commit 引入的问题呢?

我还没有重现,我的猜测应该是启用CGO引入libpcap类库后,编译环境的C类库跟运行的环境有差异。

编译构建的环境,期望是可以兼容更多内核的。 如果问题是这里的话,那确实不太好解决。

说到这个,我编译时注意到 glibc 提示 libpcap 使用的一些与解析相关的函数仍然需要动态链接 glibc

/usr/bin/ld: /tmp/go-link-3232308904/000004.o: in function `_cgo_04fbb8f65a5f_C2func_getaddrinfo':
/tmp/go-build/cgo-gcc-prolog:60:(.text+0x33): 警告:Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /home/u/ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametoaddr':
/mnt/lib/libpcap/./nametoaddr.c:181:(.text+0x5): 警告:Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /home/u/ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametonetaddr':
/mnt/lib/libpcap/./nametoaddr.c:270:(.text+0xba): 警告:Using 'getnetbyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /home/u/ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametoproto':
/mnt/lib/libpcap/./nametoaddr.c:527:(.text+0x3fc): 警告:Using 'getprotobyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

https://stackoverflow.com/questions/57476533/why-is-statically-linking-glibc-discouraged

xxxxxliil avatar Sep 01 '24 16:09 xxxxxliil

我的建议是这个问题不太好解决,因为需要要求客户锁依赖。最好的方式是通过容器运行,保证二进制的一致性

但是只有从 0.8.1 开始才会出问题,会是哪个 commit 引入的问题呢?

我还没有重现,我的猜测应该是启用CGO引入libpcap类库后,编译环境的C类库跟运行的环境有差异。

编译构建的环境,期望是可以兼容更多内核的。 如果问题是这里的话,那确实不太好解决。

Bisect 下来是 https://github.com/gojue/ecapture/commit/938fcffb95e23015af8643ae046c0e912de0a438 这个 commit 引入的破坏

11a498a3835969de86a8002ab2f70b31b217b034 这个则没问题

@xxxxxliil 可以确认下

Zheaoli avatar Sep 01 '24 17:09 Zheaoli

https://github.com/gojue/ecapture/commit/938fcffb95e23015af8643ae046c0e912de0a438#diff-eb154bbd601602eeae895e7af6a12b88cbdb7d585a2d32216c398f68cabcdff5R188-R197

目前二分代码测出来是和 HTTPServer 有关,我猜是两个 goroutine 同时初始化 CGO 然后 G 了,我看来看下汇编看看

Zheaoli avatar Sep 02 '24 10:09 Zheaoli

查出来问题了。。和 glibc 版本有关

在 #541 中我们引入了 Gin 来作为 HTTP Server 支持 Conf 通过 HTTP 变更。https://github.com/gojue/ecapture/commit/938fcffb95e23015af8643ae046c0e912de0a438#diff-eb154bbd601602eeae895e7af6a12b88cbdb7d585a2d32216c398f68cabcdff5R189-R196

而我们默认给的地址是 localhost ,这就会触发 net/http Dial 时的 DNSReslove ,同时我们在编译参数中使用了 -linkmode=external -extldflags -static 这会导致我们依赖的 getaddrinfo 函数会绑定特定的 glibc 版本

而目前 Ubuntu 常见的 glibc 版本是 2.35 而 Arch Linux 是 2.40 ,结构有所变化,导致编译产物会 SIGSEGV

目前看下来最好的解决方案是我们彻底不支持域名 address 的绑定,我觉得这样也能接受?@cfc4n

BTW Go 的 Resolver 是老问题了,FYI https://github.com/golang/go/issues/30310

Zheaoli avatar Sep 02 '24 12:09 Zheaoli

以及构建时使用 -tags 'linux netgo' 也能处理,但是不确定是否有其余副作用

@cfc4n on your call(XD

Zheaoli avatar Sep 02 '24 12:09 Zheaoli

确实,这个结论比较合理,能很好地解释了报错堆栈里的_cgo_97ab22c4dc7b_C2func_getaddrinfo 等信息。 感谢您的定位。

至于修复方式,我觉得是可以启用-tags netgo参数的。 另外,我也看到go的官方issue里提到过,使用 // go:debug netdns等方式 ,都可以尝试。 也包括你提到的不支持域名 address的绑定 ,这个决策也可行,本身就应该是来自本机的对应网卡。

另外,报错信息中还有一个关键信息warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available. ,这里只是warning的提醒,没有影响运行,问题原因是Fedora上发行的libc缺少libthread_db 符号的调试信息

其次,这个问题跟#581 不是同一个问题,我将继续关注 #581 里提到的异常。

cfc4n avatar Sep 02 '24 13:09 cfc4n

还有,在编译时,能够看到libpcap类库也引用了getaddrinfo,理论来说,也会出现异常崩溃。只是当前并没有触发libpcap内涉及DNS解析的逻辑。 如果想完全避免这类问题,要么就是跟对不同libc版本进行构建,要么就是弃用libpcap的bpf filter特性。

我需要仔细斟酌一下。

/usr/bin/ld: /ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametoaddrinfo':
/ecapture/lib/libpcap/./nametoaddr.c:207: warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametoaddr':
/ecapture/lib/libpcap/./nametoaddr.c:181: warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametonetaddr':
/ecapture/lib/libpcap/./nametoaddr.c:270: warning: Using 'getnetbyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /ecapture/lib/libpcap//libpcap.a(nametoaddr.o): in function `pcap_nametoproto':
/ecapture/lib/libpcap/./nametoaddr.c:527: warning: Using 'getprotobyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

cfc4n avatar Sep 02 '24 13:09 cfc4n

理论来说,也会出现异常崩溃。只是当前并没有触发libpcap内涉及DNS解析的逻辑。 如果想完全避免这类问题,要么就是跟对不同libc版本进行构建,要么就是弃用libpcap的bpf filter特性。

是的, 这是一个隐藏但是没炸的雷,我的建议是我们彻底放弃二进制的分发,统一交给容器处理

Zheaoli avatar Sep 02 '24 13:09 Zheaoli

不要禁用localhost的支持,禁用后,无法用一套配置同时运行在纯v4和纯v6的环境了,必须区分出127.0.0.1::1 了,很不方便

ayanamist avatar Sep 02 '24 14:09 ayanamist

不要禁用localhost的支持,禁用后,无法用一套配置同时运行在纯v4和纯v6的环境了,必须区分出127.0.0.1::1 了,很不方便

确实,所以还是老老实实 netgo 吧

Zheaoli avatar Sep 02 '24 14:09 Zheaoli

我们可以尝试使用 musl 作为静态链接时的 libc 吗?

xxxxxliil avatar Sep 03 '24 00:09 xxxxxliil

底层类库变更,稳定性风险更大,暂时不考虑。

cfc4n avatar Sep 03 '24 01:09 cfc4n

我们可以尝试使用 musl 作为静态链接时的 libc 吗?

MUSL 就算了。。。坑一抹多。。。

Zheaoli avatar Sep 03 '24 06:09 Zheaoli

确实,这个结论比较合理,能很好地解释了报错堆栈里的_cgo_97ab22c4dc7b_C2func_getaddrinfo 等信息。 感谢您的定位。

至于修复方式,我觉得是可以启用-tags netgo参数的。 另外,我也看到go的官方issue里提到过,使用 // go:debug netdns等方式 ,都可以尝试。 也包括你提到的不支持域名 address的绑定 ,这个决策也可行,本身就应该是来自本机的对应网卡。

另外,报错信息中还有一个关键信息warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available. ,这里只是warning的提醒,没有影响运行,问题原因是Fedora上发行的libc缺少libthread_db 符号的调试信息

其次,这个问题跟#581 不是同一个问题,我将继续关注 #581 里提到的异常。

#581 使用 0.8.6 之后已解决问题

xxxxxliil avatar Sep 13 '24 11:09 xxxxxliil