[bug] apply_reg_state may crash on entering and exiting stack frames on Aarch64
Los mantenedores suelen responder en 4 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 8/100
- Tipo de issue
- Error
- Claridad
- Necesita aclaración
- Estado de actividad
- Estancado
- Stack tecnológico
- c
- Área
- reverse-engineering
Línea de trabajo
The crash is in apply_reg_state in src/dwarf/Gparser.c, where the return-address slot is dereferenced via dwarf_get on c->loc[rs->ret_addr_column]. Start by reading how find_reg_state and the CFA computation feed that location, and check the aarch64 signal-frame handling in the libunwind source. Done would mean the cursor walks past the sigreturn frame without reading an unmapped address, which the reporter could not reproduce in a minimal case.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Environment
- libunwind version: master (2024-07-23 14:17 e3f88e8e)
- architecture: Aarch64 - ARMv8 Processor rev 1 (v8l)
- OS: Nvidia Orin Drive system - Ubuntu 20.04.5 LTS
- crossing-compiled using
clang 8.0.1-9fromx86_64-pc-linux-gnuplatform - here's my
config.h: I disabledlibgccmode and enabledUNW_LOCAL_ONLY. libunwind_config.zip
Description
- In
src/dwarf/Gparser.c,apply_reg_statecallsdwarf_get (c, c->loc[rs->ret_addr_column], &ip);. - But in some rare cases
c->loc[rs->ret_addr_column]may be wrong and point to unmapped memory, like0x18or0xd555...555d - Then it can crash on dereferencing the pointer.
Reproduction Steps
Background: I want to use cpu-profiler in gperftools 2.15 to collect CPU performance data, but it almost always crashes at apply_reg_state.
During my tests, libunwind often fails to get a correct "next CFA / next IP" in its apply_reg_state, especially for the below function (see the snapshot below - sorry I can not provide a minimized reproducer):
mallocis a customized wrapper which callsjemallocand and replaces the default one inglibclibunwindgets wrong CFA / IP ifSIGPERFhits0xa163194,0xa163198,0xa16319cand0xa163250- once a
CFAis wrong, it often reports more wrong IPs on furtherunw_step, or just reports a same IP and then stops with some errors.
- once a
- sometimes
libunwindfails on triggering SIGPERF at a few other functions- their IP can be something like
0xffff993160ac - usually the
mallocfunction are called fromoperator new ()at an address of0xffff9f3eab4c - sorry but I don't know how to dump ASM code of such sections
- their IP can be something like
- FYI, during the test above,
0xffff9f58f7c0is the IP of asigreturnframe
I've noticed that all the IPs of my customized malloc share a same keypoint - their LR, SP and stack values do not "match".
But I know little about DWARF, and although I spent tens of hours on src/dwarf/ I still failed when tried to understand what find_reg_state does.
My tests and logs
I compiled libunwind by myself, so that I may add syscall(SYS_write) to log something and debug it. Here is the crashing scene:
[gperf] ==== start get stack trace ====
[step] input: child-cfa=0xfffde41c31d0 , ip=0x4cc0c7c , ip.is_signal_frame=0
- cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c3dd0) + 16
> 0xfffde41c31d8 [30] = 0xfffde41c3b58
- [30]: where[]=CFAREL ; 0xfffde41c3dd8 == (new-cfa=0xfffde41c3de0) + -8, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c3dd8
[step] input: child-cfa=0xfffde41c3de0 , ip=0x4cc05c8 , ip.is_signal_frame=0
- cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c3e10) + 16
> 0xfffde41c31d8 [30] = 0xfffde41c3dd8
- [30]: where[]=CFAREL ; 0xfffde41c3e18 == (new-cfa=0xfffde41c3e20) + -8, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c3e18
[step] input: child-cfa=0xfffde41c3e20 , ip=0x4cbf50c , ip.is_signal_frame=0
- cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c4740) + 16
> 0xfffde41c31d8 [30] = 0xfffde41c3e18
- [30]: where[]=CFAREL ; 0xfffde41c4748 == (new-cfa=0xfffde41c4750) + -8, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c4748
[step] input: child-cfa=0xfffde41c4750 , ip=0x4cbc494 , ip.is_signal_frame=0
- cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0xfffde41c4790) + 16
> 0xfffde41c31d8 [30] = 0xfffde41c4748
- [30]: where[]=CFAREL ; 0xfffde41c4798 == (new-cfa=0xfffde41c47a0) + -8, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c4798
[step] input: child-cfa=0xfffde41c47a0 , ip=0xffff9f58f7c0 , ip.is_signal_frame=1
[step] input: child-cfa=0xfffde41c5a00 , ip=0xa16319c , ip.is_signal_frame=0
- cfa @ regnum := reg.val=31 , regnum=31 , ret=0 , (cfa=0xfffde41c5a00) + 0
> 0xfffde41c31d8 [30] = 0xfffde41c49c8
- [30]: where[]=1 ; 0xfffde41c49c8 == (new-cfa=0xfffde41c5a00) + 0, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c49c8
[step] input: child-cfa=0xfffde41c5a00 , ip=0xffff9f3eab4c , ip.is_signal_frame=0
- cfa @ sp := (c->cfa=0xfffde41c5a00) + 32
> 0xfffde41c31d8 [30] = 0xfffde41c49c8
- [30]: where[]=CFAREL ; 0xfffde41c5a08 == (new-cfa=0xfffde41c5a20) + -24, cfa_type=3
<< ip . operator& () = loc[30] = 0xfffde41c5a08
[step] input: child-cfa=0xfffde41c5a20 , ip=0xa144544 , ip.is_signal_frame=0
- cfa @ regnum := reg.val=29 , regnum=29 , ret=0 , (cfa=0x8) + 16
> 0xfffde41c31d8 [30] = 0xfffde41c5a08
- [30]: where[]=CFAREL ; 0x10 == (new-cfa=0x18) + -8, cfa_type=3
<< ip . operator& () = loc[30] = 0x10
*** SIGSEGV received at time=1722648362 on cpu 2 ***
PC: @ 0x4cc6c38 (unknown) apply_reg_state
@ 0x9f5b404 208 absl::lts_20230125::WriteFailureInfo()
@ 0x9f5b118 64 absl::lts_20230125::AbslFailureSignalHandler()
@ 0xffff9f58f7c0 5952 (unknown)
@ 0x4cc65f4 2048 _ULaarch64_dwarf_step
@ 0x4cc5b78 384 _ULaarch64_step
@ 0x4cc0ce8 3088 GetStackTraceWithContext_libunwind()
@ 0x4cc05c8 64 GetStackTraceWithContext()
@ 0x4cbf50c 2352 CpuProfiler::prof_handler()
@ 0x4cbc494 80 ProfileHandler::SignalHandler()
@ 0xffff9f58f7c0 4704 (unknown)
@ 0xffff9f3eab4c 64 operator new()
@ 0xa02acb4 48 google::protobuf::Arena::CreateMaybeMessage<>()
@ 0x5b644ec 64 google::protobuf::internal::RepeatedPtrFieldBase::MergeFromInnerLoop<>()
Explain:
[step] inputabove is logged inunw_stepand just next tounw_is_signal_frame(cursor)cfa @ ...is logged insrc/dwarf/Gparser.c#apply_reg_state[30]: whereis in theswitch(reg.where[i]))ofapply_reg_state
- Lenguaje dominante
- C
- Estrellas
- 1.3k
- Forks
- 353
- Merge medio
- 3 d 19 h
- PR fusionados (30 d)
- 11
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de libunwind/libunwind
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 4 días
-
build fails on muslAbiertobug
Dificultad 3/5 1-2 días Aptitud para principiantes 55/100
Los mantenedores suelen responder en 4 días
-
v1.8.3 not taggedAbiertobug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 55/100
libunwind/libunwind#1076 · 1 comentario ·
Los mantenedores suelen responder en 4 días
-
Port libunwind to linux-muslAbierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Los mantenedores suelen responder en 4 días
-
New release?Abiertoenhancement
Dificultad 5/5 Más de una semana Aptitud para principiantes 12/100
libunwind/libunwind#1030 · 7 comentarios ·
Los mantenedores suelen responder en 4 días
Todos los issues de libunwind/libunwind
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 70/100
ly05010419/MacNativeGames#1340 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
Los mantenedores suelen responder en 1 día
-
area:stdlib bug found-by:cold-read kind:bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 83/100
InauguralSystems/EigenScript#2197 ·
Los mantenedores suelen responder en 1 día
-
Hide the cursorAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 63/100
seedds/nxnative#675 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
Los mantenedores suelen responder en 2 días