SysRq Context 제약조건

Linux 커널에서 SysRq(System Request) 기능은 시스템이 비정상적인 상태에 빠졌을 때, 특정한 명령을 통해 커널의 동작을 조작하거나 시스템을 복구할 수 있도록 돕는 강력한 진단 도구다. SysRq 키를 이용하면 커널 디버깅, 로그 출력, 프로세스 종료, 재부팅 등 다양한 작업을 수행할 수 있지만, 핸들러가 실행되는 컨텍스트가 일반적인 커널 코드와 달라서 사용 시 몇 가지 중요한 제약 조건이 따른다. 이 글에서는 SysRq의 동작 원리, 실행 컨텍스트의 제약 조건, 예제 코드, 안정적인 사용을 위한 고려사항을 알아본다.

SysRq란?

SysRq는 키보드의 특별한 키(보통 Alt + PrintScreen)와 조합해 커널 내부에 정의된 특정 작업을 직접 실행할 수 있는 기능이다. 커널이 응답하지 않거나 디버깅이 필요한 상황에서 쓸 수 있는 백도어 같은 역할을 한다.

사용 예

  • Alt + SysRq + t : 현재 커널의 태스크 목록 출력
  • Alt + SysRq + m : 메모리 정보 출력
  • Alt + SysRq + c : 커널 크래시 (강제 panic)

SysRq 작동 흐름

키보드로 직접 입력하면 키보드 인터럽트 핸들러를 거쳐, /proc/sysrq-trigger에 쓰면 write 시스템 콜 경로를 거쳐 결국 같은 __handle_sysrq() 함수로 들어간다.

Key Pressed
    |
    v
Interrupt (IRQ) 또는 /proc/sysrq-trigger write()
    |
    v
handle_sysrq(key)
    |
    v
등록된 sysrq_key_op.handler() 호출

SysRq Context란?

SysRq 핸들러는 트리거 경로(키보드 인터럽트 vs. /proc/sysrq-trigger)에 따라 인터럽트 컨텍스트 또는 프로세스 컨텍스트에서 호출될 수 있다. 다만 어느 경로든 락 보호와 최악의 경우(패닉 직전 등)까지 고려해 동작해야 하므로, 두 경우 모두 슬립·블로킹이 금지된 원자적(atomic) 코드처럼 다뤄야 한다. 실제로 커널의 OOM kill 핸들러(sysrq_handle_moom)도 무거운 작업은 직접 하지 않고 schedule_work()로 워크큐에 위임한다.

예: 인터럽트 컨텍스트에서 호출되는 경우

irq_handler() {
    ...
    if (is_sysrq_key(scancode)) {
        handle_sysrq(scancode);
    }
    ...
}

SysRq Context의 제약 조건

SysRq는 제한된 컨텍스트에서 실행되므로 다음 제약 조건을 지켜야 한다.

슬립(sleep) 금지

sleep, schedule(), msleep() 등 스케줄러가 개입할 수 있는 함수는 호출해서는 안 된다.

잘못된 코드 예

void sysrq_custom_handler(u8 key) {
    msleep(100);  // 금지
}

락(lock) 사용 제한

  • spinlock은 사용 가능하지만, 블로킹이 필요한 mutex/semaphore는 사용 불가
  • mutex_lock()이나 down() 같은 함수는 호출 시 데드락이나 커널 패닉으로 이어질 수 있다

허용되는 예

spin_lock(&lock);
... // 작업 수행
spin_unlock(&lock);

금지되는 예

mutex_lock(&my_mutex);  // 금지

메모리 할당 제약

  • GFP_KERNEL은 내부적으로 슬립할 수 있으므로 사용 금지
  • 대신 GFP_ATOMIC을 사용해야 안전하다
void *ptr = kmalloc(1024, GFP_ATOMIC); // OK

프린트 및 로깅 주의

printk() 사용은 가능하지만, 지나치게 많은 라인을 한 번에 출력하면 콘솔 락 경합이나 링버퍼 오버플로로 시스템이 잠깐 멈춘 것처럼 보일 수 있다.

  • 가능: printk(KERN_INFO "SysRq triggered\n");
  • 위험: 반복문 안에서 대량의 라인을 연속 출력

재진입 가능성 고려

SysRq 핸들러는 실행 중에 다시 호출될 가능성을 배제할 수 없으므로, 전역 상태에 의존한다면 재진입에 안전(reentrant-safe)하게 작성해야 한다.

SysRq 핸들러 구현 예제

커스텀 SysRq 키 핸들러 등록

#include <linux/sysrq.h>
#include <linux/spinlock.h>

static void my_sysrq_handler(u8 key)
{
    printk(KERN_INFO "Custom SysRq handler: key = %d\n", key);
}

static struct sysrq_key_op my_sysrq_op = {
    .handler = my_sysrq_handler,
    .help_msg = "x    - Custom handler",
    .action_msg = "Custom SysRq action triggered",
    .enable_mask = SYSRQ_ENABLE_ALWAYS,
};

static int __init my_sysrq_init(void)
{
    register_sysrq_key('x', &my_sysrq_op);
    return 0;
}

static void __exit my_sysrq_exit(void)
{
    unregister_sysrq_key('x', &my_sysrq_op);
}

module_init(my_sysrq_init);
module_exit(my_sysrq_exit);

MODULE_LICENSE("GPL");

빌드 및 실행

make
sudo insmod my_sysrq.ko

사용

Alt + SysRq + x

SysRq 커널 설정

SysRq 기능을 사용하려면 커널 설정에서 해당 옵션이 활성화돼 있어야 한다.

커널 설정 확인

zcat /proc/config.gz | grep CONFIG_MAGIC_SYSRQ

CONFIG_MAGIC_SYSRQ=y이면 SysRq 기능이 커널에 포함돼 있다는 뜻이다.

런타임에서 SysRq 제어

# 전체 기능 활성화
echo 1 > /proc/sys/kernel/sysrq

# 특정 기능만 허용 (예: 16 = sync 명령만 허용)
echo 16 > /proc/sys/kernel/sysrq

SysRq 기능 테이블

기능설명
bImmediate reboot즉시 재부팅
oPower-off시스템 전원 종료
tShow task info태스크 정보 출력
mShow memory info메모리 정보 출력
cTrigger crash (panic)강제 커널 패닉
x사용자 정의 (위 예제 참조)커스텀 SysRq 핸들러 실행

문제 상황 예시: 커널 패닉 발생

원인: SysRq 핸들러 안에서 msleep()이나 mutex_lock()을 호출.

해결: 슬립·블로킹 함수 호출을 제거하고, GFP_ATOMIC, spin_lock() 등 non-blocking 자원만 사용한다.

결론

SysRq는 리눅스 커널 내부에서 강력한 진단·디버깅 도구로 쓰이지만, 핸들러가 실행되는 컨텍스트는 일반적인 사용자 공간이나 커널 스레드와 다르다. 슬립, 블로킹, 과도한 로그 출력은 모두 SysRq 컨텍스트에서 금지되며, 이를 위반하면 커널 패닉이나 시스템 정지가 발생할 수 있다. 안전한 SysRq 핸들러를 만들려면 atomic 컨텍스트에 맞춘 프로그래밍이 필요하며, spinlock, GFP_ATOMIC, printk() 같은 도구를 올바르게 써야 한다.

참고 사이트

답글 남기기