[커널 17차] 70주차

2022.01.01 23:42

ㅇㅇㅇ 조회 수:202

SDEI 관련 (arch/arm64/kernel/entry.S)

- vector table에서 CONFIG_UNMAP_KERNEL_AT_EL0가 설정된 경우 X30를 저장하지 않고 덮어쓰는 부분이 있음
- mrs x30, tpidrro_el0
- 그런데 커널 코드에서 x30을 저장하는 부분은 tramp_vector 부분임
- msr tpidrro_el0, x30 (tramp_ventry)
- 그런데 tramp_ventry는 SDEI (software delegate exception interface)를 통해서 접근하는 것으로 보인다
- __sdei_asm_entry_trampoline 부분
- 그런데 SDEI는 OS/Hypervisor와 Secure firmware 간의 exception 통신을 위한 인터페이스인 것으로 보임
- https://developer.arm.com/architectures/system-architectures/software-standards/sdei
- 따라서 tramp_ventry는 인터럽트 발생 후 EL3 펌웨어가 인터럽트를 가로채서 SDEI를 통해 trampoline 관련 처리를 모두 하고 커널로 돌아가서 통상적인 벡터 처리를 하고 다시 리턴할 때는 다시 SDEI를 통해 trampoline 처리 후 EL0로 돌아가는 것으로 보인다

 

copy_from_user() 코드 분석
- fixup code에서는 특별히 처리하는 것은 없고 그저 dst addr에서 src addr까지 1B를 copy하는 테스트를 수행한다
- 그리고 copy되지 않고 남은 데이터 바이트 수를 리턴한다
- user_ldp, user_stp, user_ldst 등의 매크로로 sttr, ldtr 등의 명령어와 함께 exception table entry 생성을 수행한다

 

demand loading 실행시 do_mem_abort() —> do_page_fault() 순서대로 수행하고
- __do_page_fault() 내에서 페이지 테이블을 demand loading하고 생성한다
- 이후 return 0으로 exception 발생한 코드를 다시 재수행한다
- 만약 에러가 발생한 경우에는 no_context로 이동하여 __do_kernel_fault() —> fixup_exception() —> search_exception_tables() 순서대로 실행되어
- exception table entry를 찾아서 regs->pc를 fixup code로 변경하고 fixup을 수행한다

 

trap_init()
- 커널의 bug break hook, fault break hook, kasan break hook 코드를 kernel break hook에 연결한다. 이 때 함수 register_kernel_break_hook()를 사용한다
- 그리고 debug fault code 중 hardware single-step, aarch64 breakpoint fault 처리 함수를 등록한다. 이는 함수 debug_traps_init()를 이용해서 실행된다

 

register_kernel_break_hook()
- 전역 변수 list head 포인터 kernel_break_hook가 존재해서 kernel의 break hook 코드들을 여기에 list head로 달아준다
- break hook 코드는 구조체 break_hook으로 정의되어 관리되며 다음과 같다

 

struct break_hook {
    struct list_head node;
    int (*fn)(struct pt_regs *regs, unsigned int esr);
    u16 imm;
    u16 mask; /* These bits are ignored when comparing with imm */
};

 

- 여기서 node를 통해 break_hook이 연결되어 관리되며 특히 kernel break hook은 kernel_break_hook list head 전역 변수가 관리한다.
- 함수 fn에 필요한 함수를 달아준다
- bug break hook에는 함수 bug_handler(), fault break hook에는 함수 reserved_fault_handler(), kanas break hook에는 함수 kasan_handler()가 달리게 된다
- 함수를 등록할 때 spin lock과 rcu를 이용한다

 

debug_traps_init()
- 함수 hook_debug_fault_code()를 이용해서 hardware single-step, aarch64 breakpoint fault 처리 함수를 등록한다
- 전역 변수 fault_info 구조체 배열 debug_fault_info[]의 1번 6번 엔트리에 hardware single-step, aarch64 breakpoint fault 처리 함수와 code signal, name을 등록한다
- 각각 single_step_handler, brk_handler 함수가 등록된다

 

Hooking 함수 사용
- 실제 사용하는 경우 함수 call_break_hook()에 의해서 사용된다. 그리고 call_break_hook()은 brk_handler()에서 호출된다

 

brk_handler()
- call_break_hook()에서 kernel_break_hook list를 돌면서 esr 입력 조건에 맞는 hook 함수를 골라서 실행한다
- 결과적으로는 BRK immediate에서 immediate에 따라 hook 함수를 고르게 된다
- 함수 esr_to_debug_fault_info()에서 debug_fault_info[] 배열에서 esr에 따른 offset을 계산해서 호출하게 된다
- 그리고 esr_to_debug_fault_info() 함수는 do_debug_exception() 함수에서 호출된다
- 함수 do_debug_exception()는 el1_dbg(), el0_dbg() 함수에서 호출된다
- 함수 el1_dbg(), el0_dbg()는 el1h_64_sync_handler()에서 호출된다
- 하드웨어 ESR_EL1에는 EC에 111100이 들어간다 (BRK 명령어에 의한 exception 발생) —> debug_fault_info[] 배열의 6번 인덱스가 된다
- BRK 명령어가 아니라 software step exception 발생하면 EC에 110010/110011이 들어간다. breakpoint, watchpoint 등도 고유한 EC 값이 주어진다
- el1h_64_sync_handler()에서 breakpoint, software step, watchpoint, BRK 모두 el1_dbg()을 호출하게 된다
- hardware breakpoint 및 watchpoint 등은 breakpoint_handler(), watchpoint_handler() 함수에서 처리되며 이들은 arch/arm64/kernel/hw_breakpoint.c 파일에 존재한다
- 이들은 함수 arch_hw_breakpoint_init()에서 등록된다

 

arm64 DEBUG 관련 내용
- https://developer.arm.com/documentation/102120/0100/Introduction-to-debug

 

ESR_EL1 레지스터
- https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/ESR-EL1--Exception-Syndrome-Register--EL1-

 

BRK 명령어
- https://developer.arm.com/documentation/ddi0602/2021-12/Base-Instructions/BRK--Breakpoint-instruction-

XE Login