LKRG (Linux Kernel Runtime Guard)

LKRG(Linux Kernel Runtime Guard)는 Openwall 프로젝트에서 개발한 커널 모듈(Kernel Module)로, 런타임에 커널과 프로세스(Process)의 무결성(Integrity)을 검증합니다. 커널 코드/모듈 텍스트 해시(Hash) 검증, 프로세스 자격증명(cred) 변조 탐지, SELinux 우회 탐지, 커널 핵심 객체(IDT/GDT/MSR) 보호를 수행하여 루트킷과 권한 상승 공격을 탐지합니다.

ℹ️

선행 지식: 이 문서는 커널 보안 개요커널 모듈에 대한 기본 이해를 전제합니다. 커널 하드닝 기법이 궁금하다면 커널 하드닝 페이지(Page)를 먼저 참고하세요.

💡

일상 비유: LKRG는 건물의 실시간(Real-time) CCTV 모니터링과 비슷합니다. 건물의 벽(커널 코드), 출입 카드 권한(프로세스 자격증명), 보안 규칙(SELinux 정책)이 누군가에 의해 변조되지 않았는지 주기적으로 확인하고, 이상을 감지하면 즉시 경보를 울립니다.

핵심 요약

보호 계층검증 대상탐지 방식대응 옵션
코드 무결성커널 텍스트, 모듈 텍스트SHA-256 해시 비교로그 / 패닉
자격증명 감시struct cred (uid/gid/cap)참조 카운터 + 해시프로세스 종료
SELinux 보호selinux_enforcing 플래그값 변조 감시복원 / 패닉
객체 보호IDT, GDT, MSR, syscall table주기적 스냅샷 비교로그 / 패닉
모듈 감시모듈 로드/언로드 이벤트notifier + 해시 갱신실시간 업데이트
  • Openwall 프로젝트에서 개발 및 유지보수 (주 개발자: Adam "pi3" Zabrocki)
  • GPLv2 라이선스, DKMS를 통한 간편 설치 지원
  • 커널 5.x ~ 6.x 광범위 지원, x86_64 및 ARM64 아키텍처
  • 런타임 감지 전용 — 사전 예방이 아닌 사후 탐지(detection, not prevention) 도구
  • sysctl lkrg.* 인터페이스로 모든 동작 파라미터 조정 가능

LKRG 개요

LKRG는 2018년 Openwall(John the Ripper 개발사)이 공개한 오픈소스 커널 모듈입니다. 전통적인 호스트 기반 침입 탐지 시스템(HIDS)이 파일 시스템 수준에서 동작하는 것과 달리, LKRG는 커널 메모리 내부에서 직접 무결성을 검증합니다.

설계 철학

원칙설명
Detection over Prevention공격을 차단하기보다 변조를 탐지하여 알림. 오탐(false positive) 최소화
Out-of-tree 모듈메인라인 커널 수정 없이 로드 가능. DKMS로 커널 업그레이드 시 자동 빌드
최소 성능 영향이벤트 기반 + 주기적 검사 혼합으로 CPU 오버헤드(Overhead) 최소화
계층적 보호코드, 데이터, 자격증명, 보안 정책을 다층적으로 검증

LKRG의 역사

LKRG 아키텍처

LKRG는 내부적으로 세 가지 핵심 컴포넌트로 구성됩니다:

  1. CI (Code Integrity) — 커널과 모듈의 코드(.text) 영역 해시를 관리하는 엔진. 초기화 시 기준 해시를 생성하고, 모듈 로드/언로드 이벤트에 동적으로 대응합니다.
  2. PCFI (Process Credentials and Flow Integrity) — 프로세스 자격증명(struct cred)의 무결성을 검증하는 엔진. kprobe/kretprobe를 통해 합법적 변경을 추적하고, 비정상적 변경을 탐지합니다.
  3. SI (System Integrity) — IDT, GDT, MSR, syscall table 등 CPU 특수 구조의 무결성을 검증하는 엔진. per-CPU 단위로 검사를 수행합니다.
/* LKRG 내부 데이터베이스 — 기준값 저장 구조 (단순화) */
struct p_lkrg_global_db {
    /* CI: Code Integrity */
    char            kernel_hash[32];    /* 커널 .text SHA-256 */
    struct list_head module_list;       /* 모듈별 해시 리스트 */
    unsigned int    module_count;       /* 활성 모듈 수 */

    /* SI: System Integrity */
    char            idt_hash[32];       /* IDT 해시 */
    u64             msr_lstar;          /* MSR_LSTAR 기준값 */
    char            syscall_table_hash[32]; /* syscall table 해시 */

    /* PCFI: 프로세스 자격증명 */
    unsigned int    task_count;         /* 추적 중인 태스크 수 */

    /* SELinux 상태 */
    int             selinux_enforcing;  /* SELinux enforcing 기준값 */

    /* 타이머 */
    struct timer_list timer;            /* 주기적 검사 타이머 */
    unsigned long   interval;           /* 검사 간격 (jiffies) */
};
LKRG 보호 범위 커널 공간 커널 텍스트 (.text) 모듈 텍스트 (.text) IDT / GDT / MSR syscall table 프로세스 공간 struct cred (uid/gid) capabilities SELinux context namespace 정보 LKRG 커널 모듈 로그 기록 (dmesg) 프로세스 종료 (kill) 커널 패닉
IMA와의 차이: IMA(Integrity Measurement Architecture)는 파일 시스템 수준에서 바이너리 무결성을 검증하고, LKRG는 커널 메모리 내부에서 런타임 무결성을 검증합니다. 두 도구는 상호 보완적입니다. IMA에 대해서는 IMA/EVM 페이지를 참조하세요.

코드 무결성 검증

LKRG의 핵심 기능은 커널 코드 영역의 무결성을 런타임에 검증하는 것입니다. 커널이 부팅된 후 .text 섹션은 읽기 전용(Read-Only)이어야 하므로, 해시값이 변하면 코드 변조(code patching)가 발생한 것입니다.

커널 텍스트 해시 검증

LKRG는 초기화 시 커널의 _stext부터 _etext까지의 전체 코드 영역에 대해 SHA-256 해시를 계산합니다. 이후 주기적으로 또는 이벤트 트리거 시 해시를 재계산하여 기준값과 비교합니다.

/* LKRG 내부 구조 — 커널 텍스트 해시 검증 (단순화) */
struct p_text_pgs {
    unsigned long  p_addr;       /* 텍스트 시작 주소 */
    unsigned long  p_size;       /* 텍스트 크기 */
    char           p_hash[32];  /* SHA-256 해시 */
};

/* 해시 계산 흐름 */
static int p_check_integrity(void) {
    char current_hash[32];

    /* 1. 현재 커널 텍스트의 SHA-256 계산 */
    p_hash_from_text(_stext, _etext - _stext, current_hash);

    /* 2. 초기화 시 저장한 기준 해시와 비교 */
    if (memcmp(current_hash, p_db.kernel_hash, 32) != 0) {
        /* 변조 탐지! */
        p_print_log(P_LOG_ALERT,
            "Kernel .text integrity violation detected!");
        return P_LKRG_INTEGRITY_FAIL;
    }
    return P_LKRG_INTEGRITY_OK;
}

모듈 텍스트 해시 검증

커널에 로드된 각 모듈의 .text 섹션도 개별적으로 해시를 계산합니다. 모듈이 로드/언로드될 때 module_notifier를 통해 해시 데이터베이스를 갱신합니다.

/* 모듈 로드 시 해시 데이터베이스 갱신 */
static int p_module_notifier_callback(
    struct notifier_block *nb,
    unsigned long action, void *data)
{
    struct module *mod = data;

    switch (action) {
    case MODULE_STATE_LIVE:
        /* 모듈이 활성화되면 텍스트 해시 계산 및 저장 */
        p_add_module_hash(mod);
        break;
    case MODULE_STATE_GOING:
        /* 모듈이 제거되면 해시 데이터베이스에서 삭제 */
        p_del_module_hash(mod);
        break;
    }
    return NOTIFY_OK;
}
코드 무결성 검증 흐름 LKRG 초기화 기준 해시 계산 커널 .text SHA-256 모듈 .text SHA-256 주기적 타이머 + 이벤트 훅 해시 비교 현재 vs 기준 일치 (정상) 불일치 (변조!) dmesg 경고 + 설정에 따라 panic 또는 log module_notifier MODULE_STATE_LIVE →해시 추가 MODULE_STATE_GOING→해시 삭제
주의: 커널의 alternative patching(부팅 시 CPU 기능에 맞게 코드를 대체하는 메커니즘)이나 ftrace 사용 시, 정상적인 코드 변경이 발생합니다. LKRG는 이런 합법적 변경을 구분하기 위해 초기화를 alternative patching 완료 후에 수행합니다.

해시 알고리즘과 성능

LKRG는 내부적으로 커널 crypto API를 사용하여 SHA-256(또는 빌드 구성에 따라 다른 알고리즘) 해시를 계산합니다. 커널 텍스트 영역의 크기는 일반적으로 10~30MB이며, SHA-256 해시 계산은 최신 CPU에서 수 밀리초 내에 완료됩니다.

영역일반적 크기해시 계산 시간 (참고값)
커널 .text10~30 MB~5ms
모듈 .text (개당)수 KB~수 MB< 1ms
IDT (전체)4 KB< 0.01ms
syscall table~3 KB (x86_64)< 0.01ms

모듈 텍스트 변조 탐지 사례

실제로 일부 루트킷은 기존 커널 모듈의 코드를 직접 수정하는 방식을 사용합니다. 예를 들어, 네트워크 모듈의 패킷(Packet) 필터링 함수를 NOP으로 패치(Patch)하여 방화벽(Firewall)을 우회하거나, 파일시스템(Filesystem) 모듈을 변조하여 특정 파일을 숨깁니다. LKRG는 각 모듈의 .text 해시를 개별 추적하므로, 어떤 모듈이 변조되었는지까지 식별할 수 있습니다.

프로세스 자격증명 모니터링

권한 상승(privilege escalation) 공격은 일반적으로 프로세스의 struct cred를 직접 변조하여 uid를 0(root)으로 바꾸거나 capabilities를 추가합니다. LKRG는 이러한 비정상적 자격증명 변경을 탐지합니다.

struct cred 보호 메커니즘

LKRG는 각 프로세스(task_struct)에 대해 자격증명의 해시값을 유지합니다. 정상적인 자격증명 변경(예: setuid(), execve())은 커널의 공식 경로를 통해 이루어지며, LKRG는 이 경로에 kprobe/kretprobe 훅을 설치하여 합법적 변경을 추적합니다.

/* struct cred — 프로세스 자격증명 구조체 (include/linux/cred.h) */
struct cred {
    atomic_t    usage;
    kuid_t      uid;        /* 실제 UID */
    kgid_t      gid;        /* 실제 GID */
    kuid_t      suid;       /* 저장된 set-UID */
    kgid_t      sgid;       /* 저장된 set-GID */
    kuid_t      euid;       /* 유효 UID */
    kgid_t      egid;       /* 유효 GID */
    kuid_t      fsuid;      /* 파일시스템 UID */
    kgid_t      fsgid;      /* 파일시스템 GID */
    kernel_cap_t cap_inheritable;
    kernel_cap_t cap_permitted;
    kernel_cap_t cap_effective;
    kernel_cap_t cap_bset;
    kernel_cap_t cap_ambient;
    /* ... */
};

감시 대상 필드

필드공격 시나리오LKRG 탐지 방식
uid / euiduid를 0으로 직접 변조 (DirtyCOW류)해시 비교 + setuid kretprobe
cap_effectiveCAP_SYS_ADMIN 등 추가capability 해시 검증
securebitsSECBIT_NOROOT 비활성화securebits 필드 해시
user_ns네임스페이스(Namespace) 탈출namespace 포인터 검증
프로세스 자격증명 감시 메커니즘 정상 경로 (kretprobe 추적) setuid() execve() commit_creds() cap_bprm_* LKRG 해시 갱신 비정상 경로 (변조 탐지) cred 직접 메모리 쓰기 커널 익스플로잇으로 덮기 해시 불일치 → 탐지! LKRG 자격증명 검증 엔진 task_struct 순회 → cred 해시 검증 → 정상/비정상 판별 정상 → 통과 변조 → kill / log / panic
DirtyCOW 사례: CVE-2016-5195(DirtyCOW)는 COW(Copy-on-Write) 경합(Contention) 조건을 악용하여 읽기 전용 파일을 수정하거나 프로세스 자격증명을 변조했습니다. LKRG의 자격증명 모니터링은 이러한 커널 수준 권한 상승을 사후 탐지할 수 있습니다.

자격증명 검증: usage 카운터

LKRG는 struct cred의 해시뿐만 아니라 usage 참조 카운터도 감시합니다. 정상적인 참조 카운터 변동은 커널의 공식 함수(get_cred(), put_cred())를 통해 이루어집니다. 비정상적으로 큰 값이나 음수 값은 UAF(Use-After-Free) 공격의 징후일 수 있습니다.

/* cred 참조 카운터 검증 */
static int p_validate_cred_usage(struct cred *cred) {
    int usage = atomic_read(&cred->usage);

    /* 비정상적 참조 카운터 검사 */
    if (usage <= 0 || usage > P_CRED_USAGE_MAX) {
        p_print_log(P_LOG_ALERT,
            "Suspicious cred usage count: %d", usage);
        return P_LKRG_INTEGRITY_FAIL;
    }
    return P_LKRG_INTEGRITY_OK;
}

namespace 탈출 탐지

컨테이너(Container) 환경에서 공격자가 네임스페이스를 탈출하면 호스트 시스템의 전체 권한을 획득할 수 있습니다. LKRG는 프로세스의 nsproxy 포인터와 user_ns를 추적하여, 공식 경로를 거치지 않은 네임스페이스 변경을 탐지합니다.

SELinux 우회 탐지

공격자가 커널 취약점(Vulnerability)을 이용하여 selinux_enforcing 변수를 0(permissive)으로 변경하면 SELinux의 모든 접근 제어(Access Control)가 무력화됩니다. LKRG는 이 변수의 변조를 감시합니다.

감시 대상

변수/구조체(Struct)위치공격 시나리오
selinux_enforcingsecurity/selinux/enforcing → permissive 변조
selinux_enabledsecurity/selinux/SELinux 전체 비활성화
selinux_statesecurity/selinux/상태 구조체 변조
/* LKRG SELinux 보호 — 개념적 흐름 */
static void p_check_selinux(void) {
    int current_enforcing;

    /* 현재 selinux_enforcing 값 읽기 */
    current_enforcing = p_read_selinux_enforcing();

    /* 초기화 시 저장한 기준값과 비교 */
    if (current_enforcing != p_db.selinux_enforcing) {
        p_print_log(P_LOG_ALERT,
            "SELinux enforcing mode was changed! "
            "Expected %d, found %d",
            p_db.selinux_enforcing, current_enforcing);
        /* 정책에 따라 복원 또는 패닉 */
        p_trigger_response();
    }
}
커널 6.x 변경사항: 최신 커널에서 selinux_enforcing은 글로벌 변수 대신 struct selinux_state 내부로 이동했습니다. LKRG는 커널 버전에 따라 적절한 심볼을 탐색합니다.

SELinux 우회 공격 시나리오

실제 공격에서 SELinux 우회는 다음과 같은 패턴으로 수행됩니다:

  1. 커널 취약점을 통한 임의 쓰기(arbitrary write) 획득
  2. selinux_enforcing 변수의 커널 가상 주소(Virtual Address) 계산 (KASLR 우회 필요)
  3. 해당 주소에 0 값을 기록하여 permissive 모드로 전환
  4. SELinux 정책에 의해 차단되던 작업 수행 (파일 접근, 프로세스 실행 등)

LKRG는 이 시나리오의 3단계에서 변조를 탐지합니다. 다만, LKRG의 검사 주기 사이에 변조가 일어나면 탐지가 지연(Latency)될 수 있으므로 lkrg.interval을 짧게 설정하는 것이 중요합니다.

AppArmor 환경

Ubuntu 등 AppArmor를 사용하는 환경에서는 SELinux 관련 검사가 적용되지 않습니다. LKRG는 SELinux가 활성화된 시스템에서만 해당 보호를 수행하며, AppArmor의 상태 변조 감시는 별도로 구현되어 있지 않습니다.

커널 객체 보호

루트킷은 커널의 핵심 데이터 구조를 변조하여 동작합니다. LKRG는 다음 객체들의 무결성을 주기적으로 검증합니다.

보호 대상 객체

객체설명변조 시 영향
IDT인터럽트(Interrupt) 디스크립터 테이블인터럽트 핸들러(Handler) 하이재킹
GDT글로벌 디스크립터 테이블세그먼트 보호 우회
MSR모델 특정 레지스터 (LSTAR 등)시스템 콜(System Call) 진입점(Entry Point) 변조
syscall tablesys_call_table[]시스템 콜 후킹
IDTE countIDT 엔트리 수숨겨진 인터럽트 핸들러
/* IDT 무결성 검증 (x86_64) */
static void p_check_idt(void) {
    struct desc_ptr idtr;
    char hash[32];

    /* 현재 IDT 기저 주소/크기 획득 */
    store_idt(&idtr);

    /* IDT 전체 내용의 해시 계산 */
    p_hash_memory((void *)idtr.address, idtr.size + 1, hash);

    /* 기준 해시와 비교 */
    if (memcmp(hash, p_db.idt_hash, 32))
        p_integrity_alert("IDT modified");
}

/* MSR LSTAR (시스템 콜 진입점) 검증 */
static void p_check_msr_lstar(void) {
    u64 lstar = native_read_msr(MSR_LSTAR);

    if (lstar != p_db.msr_lstar) {
        p_print_log(P_LOG_ALERT,
            "MSR_LSTAR changed: 0x%llx -> 0x%llx",
            p_db.msr_lstar, lstar);
    }
}

시스템 콜 테이블 보호

전통적인 루트킷의 대표적 기법은 sys_call_table[]의 엔트리를 변조하여 시스템 콜을 가로채는 것입니다. 예를 들어 sys_getdents64를 교체하면 파일 목록을 조작하여 루트킷 파일을 숨길 수 있습니다.

/* 시스템 콜 테이블 무결성 검증 (단순화) */
static void p_check_syscall_table(void) {
    char hash[32];
    unsigned long *table = (unsigned long *)p_db.syscall_table_addr;
    size_t size = __NR_syscalls * sizeof(unsigned long);

    /* 현재 syscall table 해시 계산 */
    p_hash_memory(table, size, hash);

    /* 기준 해시와 비교 */
    if (memcmp(hash, p_db.syscall_table_hash, 32)) {
        p_print_log(P_LOG_ALERT,
            "sys_call_table has been modified!");
        /* 변조된 엔트리 식별 */
        for (int i = 0; i < __NR_syscalls; i++) {
            if (table[i] != p_db.syscall_table_copy[i])
                p_print_log(P_LOG_ALERT,
                    "  syscall #%d: 0x%lx -> 0x%lx",
                    i, p_db.syscall_table_copy[i], table[i]);
        }
    }
}

per-CPU 검증

IDT, GDT, MSR은 각 CPU마다 독립적으로 존재할 수 있습니다. LKRG는 smp_call_function_many()를 사용하여 모든 CPU에서 동시에 검증을 수행합니다. 이는 단일 CPU만 변조하는 정교한 공격도 탐지할 수 있게 합니다.

커널 객체 보호 맵 CPU 특수 구조 IDT GDT MSR LSTAR CR4 syscall table 커널 메모리 데이터 커널 .text 해시 모듈 .text 해시 DB SELinux 상태 LKRG 검증기 스냅샷 비교 엔진 타이머 + kprobe 트리거 해시/값 일치 → 정상

훅 메커니즘

LKRG는 두 가지 메커니즘으로 무결성 검사를 트리거합니다: 이벤트 기반 훅타이머(Timer) 기반 주기적 검사.

이벤트 기반 훅 (kprobe/kretprobe)

LKRG는 자격증명 변경과 관련된 커널 함수에 kprobe/kretprobe를 설치합니다. 이를 통해 합법적인 자격증명 변경을 실시간으로 추적하고 해시를 갱신합니다.

훅 대상 함수유형목적
commit_creds()kretprobe자격증명 변경 추적
override_creds()kretprobe임시 자격증명 변경 추적
revert_creds()kretprobe자격증명 복원 추적
do_init_module()kretprobe모듈 로드 완료 후 해시 갱신
security_bprm_committing_creds()kprobeexecve 시 cred 커밋 전 검사
cap_task_prctl()kretprobeprctl 통한 capability 변경 추적

UMH (User Mode Helper) 감시

커널은 call_usermodehelper()를 통해 사용자 공간(User Space) 프로그램을 실행할 수 있습니다. 공격자가 이 메커니즘을 악용하면 커널 권한으로 임의의 바이너리를 실행할 수 있습니다. LKRG는 UMH 호출을 감시하여 비정상적인 사용자 공간 프로그램 실행을 탐지합니다.

/* UMH 감시 훅 (단순화) */
static int p_umh_notifier(
    struct notifier_block *nb,
    unsigned long action, void *data)
{
    struct subprocess_info *info = data;

    /* UMH 실행 로깅 */
    p_print_log(P_LOG_INFO,
        "UMH: path=%s argv[0]=%s",
        info->path,
        info->argv ? info->argv[0] : "(null)");

    return NOTIFY_OK;
}

타이머 기반 주기적 검사

kprobe 훅으로 캡처되지 않는 직접 메모리 변조를 탐지하기 위해, LKRG는 커널 타이머를 사용한 주기적 전체 검사를 수행합니다. 이 이중 메커니즘(이벤트 + 타이머)이 LKRG의 핵심 설계입니다.

/* LKRG 주기적 검사 — 타이머 콜백 (단순화) */
static void p_offload_work(struct work_struct *work) {
    /* 1. 커널 텍스트 무결성 검사 */
    p_check_kernel_integrity();

    /* 2. 모듈 텍스트 무결성 검사 */
    p_check_modules_integrity();

    /* 3. 커널 객체 (IDT/GDT/MSR) 검사 */
    p_check_critical_objects();

    /* 4. SELinux 상태 검사 */
    p_check_selinux();

    /* 5. 전체 프로세스 자격증명 순회 검사 */
    p_check_all_tasks_creds();

    /* 다음 검사 스케줄 */
    mod_timer(&p_timer, jiffies + p_interval);
}
검사 트리거 흐름 이벤트 트리거 commit_creds() 호출 module load/unload execve() / prctl() 타이머 트리거 주기: lkrg.interval (기본 15초) LKRG 검증 엔진 1. 코드 무결성 해시 2. 모듈 무결성 해시 3. IDT/GDT/MSR 검사 4. SELinux 상태 검사 5. cred 전수 검사 6. syscall table 검사 정상 다음 검사 대기 변조 탐지 대응 실행 log kill/panic

탐지 및 대응

LKRG는 무결성 위반을 탐지했을 때 설정에 따라 다른 수준의 대응을 수행합니다.

대응 정책

정책 레벨sysctl 값동작적용 환경
Log only0dmesg에 경고 로그만 기록테스트/평가 환경
Kill process1변조된 자격증명의 프로세스 종료프로덕션 (기본값)
Panic2커널 패닉(Kernel Panic)으로 시스템 정지고보안 환경

로그 메시지 형식

# dmesg에서 LKRG 관련 로그 확인
dmesg | grep -i lkrg

# 탐지 시 출력 예시
[  123.456789] [p_lkrg] ALERT: Kernel .text integrity violation!
[  123.456790] [p_lkrg] ALERT: Process credentials violation!
              PID=1234 COMM=exploit UID=0->0 EUID=1000->0
[  123.456791] [p_lkrg] ALERT: SELinux enforcing mode changed! 1->0
[  123.456792] [p_lkrg] ALERT: IDT has been modified!
SIEM 연동: LKRG 로그는 dmesgprintk를 통해 출력되므로, rsyslogjournald를 통해 SIEM(Security Information and Event Management) 시스템에 전달할 수 있습니다. [p_lkrg] ALERT 패턴으로 필터링하세요.
# rsyslog 규칙 예시: LKRG 경고를 별도 파일에 기록
# /etc/rsyslog.d/lkrg.conf
:msg, contains, "[p_lkrg] ALERT" /var/log/lkrg-alerts.log
& stop

# journalctl로 LKRG 로그만 필터링
journalctl -k --grep="p_lkrg" --since="1 hour ago"

설치

설치 전 요구사항

요구사항최소 조건확인 명령
커널 버전5.4 이상 권장uname -r
커널 헤더현재 커널과 일치하는 헤더 패키지ls /lib/modules/$(uname -r)/build
CONFIG_KPROBESy (필수)grep KPROBES /boot/config-$(uname -r)
CONFIG_KALLSYMSy (필수)grep KALLSYMS /boot/config-$(uname -r)
CONFIG_MODULESy (필수)grep "^CONFIG_MODULES=" /boot/config-$(uname -r)
컴파일러GCC 또는 Clanggcc --version
makeGNU Makemake --version
# 사전 점검 스크립트
echo "=== LKRG 설치 전 점검 ==="
echo "커널 버전: $(uname -r)"
echo "아키텍처: $(uname -m)"

# 필수 커널 설정 확인
for opt in KPROBES KALLSYMS MODULES JUMP_LABEL; do
    val=$(grep "CONFIG_${opt}=" /boot/config-$(uname -r) 2>/dev/null)
    if [ -z "$val" ]; then
        echo "[WARN] CONFIG_${opt} 미확인"
    else
        echo "[OK]   ${val}"
    fi
done

# 커널 헤더 확인
if [ -d "/lib/modules/$(uname -r)/build" ]; then
    echo "[OK]   커널 헤더 존재"
else
    echo "[FAIL] 커널 헤더 없음 — 설치 필요"
fi

DKMS를 통한 설치 (권장)

DKMS(Dynamic Kernel Module Support)를 사용하면 커널 업그레이드 시 자동으로 LKRG 모듈을 재빌드합니다.

# 의존성 설치 (Debian/Ubuntu)
sudo apt install dkms linux-headers-$(uname -r) build-essential

# LKRG 소스 다운로드
git clone https://github.com/lkrg-org/lkrg.git
cd lkrg

# DKMS 등록 및 빌드
sudo make dkms-install

# 모듈 로드
sudo modprobe lkrg

# 부팅 시 자동 로드 설정
echo "lkrg" | sudo tee /etc/modules-load.d/lkrg.conf

소스 빌드 (수동)

# 소스에서 직접 빌드
git clone https://github.com/lkrg-org/lkrg.git
cd lkrg
make -j$(nproc)

# 수동 로드
sudo insmod output/lkrg.ko

# 언로드 (비활성화)
sudo rmmod lkrg

배포판별 패키지

배포판패키지설치 명령
Whonixlkrg-dkmssudo apt install lkrg-dkms
Arch Linux (AUR)lkrg-dkmsyay -S lkrg-dkms
Fedora (COPR)lkrgsudo dnf copr enable <repo> && sudo dnf install lkrg
Debian소스 빌드위 DKMS 절차 참조
Secure Boot 환경: Secure Boot가 활성화된 시스템에서는 out-of-tree 모듈에 서명이 필요합니다. Secure Boot 연동 섹션을 참조하세요.

sysctl 설정

LKRG는 sysctl 인터페이스를 통해 런타임 설정을 변경할 수 있습니다. 모든 파라미터는 lkrg. 접두사를 사용합니다.

주요 파라미터

파라미터기본값범위설명
lkrg.profile_validate30~4전체 검증 프로파일 (0=비활성, 4=최대)
lkrg.profile_enforce20~4대응 정책 프로파일 (0=log only, 4=panic)
lkrg.interval155~1800주기적 검사 간격 (초)
lkrg.triggerN/A쓰기 전용즉시 전체 검사 실행
lkrg.log_level10~4로그 상세도 (0=최소, 4=디버그)
lkrg.block_modules00~1새 모듈 로드 차단
lkrg.hide00~1LKRG 모듈을 모듈 목록에서 숨김
lkrg.msr_validate10~1MSR 검증 활성화
lkrg.pcfi_validate20~3프로세스 자격증명 검증 강도
lkrg.pcfi_enforce10~3자격증명 위반 대응 강도

프로파일 설정 예시

# 현재 설정 확인
sysctl -a | grep lkrg

# 프로덕션 서버: 높은 검증 + 프로세스 종료 대응
sudo sysctl -w lkrg.profile_validate=3
sudo sysctl -w lkrg.profile_enforce=2
sudo sysctl -w lkrg.interval=10

# 고보안 환경: 최대 검증 + 모듈 차단 + 패닉
sudo sysctl -w lkrg.profile_validate=4
sudo sysctl -w lkrg.profile_enforce=4
sudo sysctl -w lkrg.block_modules=1

# 테스트 환경: 로그만 기록
sudo sysctl -w lkrg.profile_validate=2
sudo sysctl -w lkrg.profile_enforce=0
sudo sysctl -w lkrg.log_level=4

# 영구 설정 (/etc/sysctl.d/lkrg.conf)
echo "lkrg.profile_validate=3" | sudo tee /etc/sysctl.d/lkrg.conf
echo "lkrg.profile_enforce=2" | sudo tee -a /etc/sysctl.d/lkrg.conf
echo "lkrg.interval=15" | sudo tee -a /etc/sysctl.d/lkrg.conf

# 즉시 전체 검사 실행 (수동 트리거)
sudo sysctl -w lkrg.trigger=1

프로파일 상세 설명

lkrg.profile_validatelkrg.profile_enforce는 여러 개별 파라미터를 한 번에 설정하는 매크로(Macro) 역할을 합니다.

profile_validate 값코드 검증cred 검증타이머 검사MSR 검증
0 (비활성)꺼짐꺼짐꺼짐꺼짐
1 (최소)이벤트 시이벤트 시꺼짐꺼짐
2 (경량)이벤트 + 타이머이벤트 시활성꺼짐
3 (표준, 기본)이벤트 + 타이머이벤트 + 타이머활성활성
4 (최대)이벤트 + 짧은 타이머이벤트 + 타이머 + 전수활성활성
lkrg.hide 주의: lkrg.hide=1을 설정하면 LKRG가 lsmod 출력에서 사라지며, sysctl lkrg.* 인터페이스도 접근이 제한됩니다. 이 기능은 공격자가 LKRG의 존재를 탐지하기 어렵게 하지만, 관리 편의성이 떨어지므로 숨기기 전에 모든 설정을 완료하세요.
운영 팁: 처음 배포 시에는 profile_validate=3, profile_enforce=0(log only)으로 시작하세요. 1~2주간 오탐이 없음을 확인한 후 profile_enforce를 2(프로세스 종료)로 올리세요. 고보안 환경에서만 4(패닉)를 사용하세요.

LKRG vs IMA 비교

LKRG와 IMA(Integrity Measurement Architecture)는 모두 시스템 무결성을 검증하는 도구이지만, 동작 계층, 검증 시점, 대응 방식이 근본적으로 다릅니다. 두 도구의 차이를 이해하면 적절한 방어 전략을 수립할 수 있습니다.

특성LKRGIMA
검증 대상커널 메모리 (코드, 데이터, 객체)파일 시스템 (바이너리, 라이브러리)
동작 계층커널 런타임 메모리VFS (파일 open/mmap)
구현 방식Out-of-tree 커널 모듈In-tree LSM (메인라인)
해시 기준부팅 시 스냅샷사전 서명된 해시 (x509)
변조 대응log / kill / panic실행 거부 (appraise)
루트킷 탐지커널 수준 루트킷 탐지 가능파일 수준 변조 탐지
성능 영향주기적 CPU 스파이크파일 I/O 시 지연
TPM 연동미지원TPM PCR 확장 지원

함께 사용하는 방법

# IMA + LKRG 병용 구성 예시

# 1. IMA 활성화 (커널 cmdline)
# ima_policy=tcb ima_appraise=enforce

# 2. IMA 정책: 실행 파일과 라이브러리 무결성 강제
# /etc/ima/ima-policy
# dont_appraise fsmagic=0x9fa0
# dont_appraise fsmagic=0x62656572
# appraise func=BPRM_CHECK
# appraise func=MODULE_CHECK
# measure func=BPRM_CHECK
# measure func=MODULE_CHECK

# 3. LKRG: 커널 런타임 보호
sudo modprobe lkrg
sudo sysctl -w lkrg.profile_validate=3
sudo sysctl -w lkrg.profile_enforce=2

# 결과:
# - IMA가 변조된 바이너리/모듈의 실행을 차단 (사전 예방)
# - LKRG가 커널 메모리 내부의 변조를 탐지 (사후 탐지)
# - 두 계층이 서로 다른 공격 벡터를 커버하여 보안 강화
상호 보완: LKRG와 IMA를 함께 사용하면 커널 메모리와 파일 시스템 양쪽 모두에서 무결성을 검증할 수 있습니다. IMA가 악성 바이너리의 실행을 차단하고, LKRG가 이미 실행 중인 커널 내부의 변조를 탐지하는 이중 방어 체계를 구축할 수 있습니다.

제한사항

LKRG는 강력한 런타임 감시 도구이지만, 설계상 다음과 같은 한계가 있습니다.

근본적 제한

제한원인영향
TOCTOU 취약성검사 시점과 사용 시점의 차이짧은 시간 내 변조 후 복원 시 탐지 불가
동일 권한 실행커널 모듈로서 ring 0 실행공격자가 ring 0 접근 시 LKRG도 무력화 가능
데이터만 변조코드가 아닌 데이터 구조 공격함수 포인터 변조 등 일부만 탐지
DMA 공격하드웨어 DMA를 통한 메모리 접근CPU를 거치지 않는 변조 탐지 불가
커널 업데이트커널 버전 변경 시 재빌드 필요DKMS로 자동화 가능하나 호환성 문제 가능

알려진 우회 벡터

LKRG 우회 벡터와 방어 알려진 우회 벡터 1. TOCTOU: 검사 사이 변조 → 복원 2. LKRG 모듈 자체 변조/언로드 3. 커널 데이터 전용 공격 (non-code) 4. DMA/물리 메모리 직접 접근 5. kprobe 해제 후 공격 방어 강화 방법 검사 간격 최소화 (lkrg.interval=5) lkrg.hide=1 + block_modules=1 kCFI/FineIBT + LKRG 병용 IOMMU + Secure Boot + Lockdown LSM 커널 하드닝 전면 적용

바이패스 기법 분석

보안 연구자들은 LKRG의 한계를 분석하여 다양한 우회 기법을 제시했습니다. 이 분석은 방어 강화에 참고됩니다.

학술 연구 결과

우회 기법원리LKRG 대응
Race condition 공격타이머 검사 사이에 변조 → 복원검사 간격 단축, 이벤트 기반 훅 강화
LKRG 코드 변조LKRG 모듈 자체의 검사 루틴 NOP 패치lkrg.hide=1, 모듈 서명 검증(Signature Verification)
kretprobe 해제LKRG의 kprobe 훅을 해제 후 공격타이머 기반 백업 검사로 이중 탐지
데이터 전용 공격 (DOP)코드 변조 없이 데이터만 변조cred 해시 + 주기적 전수 검사
ROP/JOP 체인기존 코드 재사용으로 코드 변조 회피kCFI/FineIBT 병용 권장
Openwall의 입장: LKRG 개발자들은 "LKRG는 완벽한 보호가 아닌, 공격 비용을 높이는(raise the bar) 도구"라고 명시합니다. 정교한 공격자가 충분한 시간과 커널 접근 권한을 갖고 있다면 우회 가능하지만, 대부분의 실전 공격(commodity exploits)에 효과적입니다.

실전 공격 시나리오별 LKRG 효과

공격 유형예시 CVELKRG 탐지 여부설명
cred 직접 변조CVE-2016-5195 (DirtyCOW)탐지 가능uid/euid 변경 감지
syscall 테이블 후킹전통적 루트킷탐지 가능테이블 해시 불일치
커널 코드 패치인라인 후킹탐지 가능.text 해시 불일치
IDT 후킹인터럽트 하이재킹탐지 가능IDT 엔트리 비교
SELinux 비활성화다수의 Android 루트킷탐지 가능enforcing 플래그 감시
DOP (Data-Only)함수 포인터만 변조부분 탐지코드 해시는 정상, cred만 감시
ROP/JOP 체인기존 가젯 재사용제한적코드 변조 없으므로 해시 정상
DMA 공격Thunderbolt/FireWire DMA탐지 불가CPU 우회 직접 메모리 접근(DMA)

방어 강화 권장 조합

# 권장 방어 계층 구성
# 1단계: 커널 하드닝 (컴파일 시)
CONFIG_RANDOMIZE_BASE=y       # KASLR
CONFIG_CFI_CLANG=y            # kCFI
CONFIG_SHADOW_CALL_STACK=y    # SCS (ARM64)
CONFIG_SECURITY_LOCKDOWN_LSM=y

# 2단계: 부팅 시 보안
# Secure Boot + 모듈 서명 + Lockdown 활성화
lockdown=integrity             # 커널 cmdline

# 3단계: LKRG 런타임 보호
sudo modprobe lkrg
sudo sysctl -w lkrg.profile_validate=4
sudo sysctl -w lkrg.block_modules=1
sudo sysctl -w lkrg.hide=1

# 4단계: 파일 시스템 보호 (IMA)
# ima_policy=tcb ima_appraise=enforce

성능 영향

LKRG의 주요 성능 비용은 주기적 전체 검사와 이벤트 기반 kretprobe 오버헤드에서 발생합니다.

오버헤드 벤치마크

워크로드LKRG 비활성LKRG 활성 (기본)오버헤드
커널 빌드 (make -j8)100%~100.5%< 1%
파일 I/O (fio 4K)100%~100.2%< 0.5%
네트워크 (iperf3)100%~100.1%< 0.2%
프로세스 집중 (fork bomb 제한)100%~102%~2%
execve 집중100%~103%~3%
타이머 스파이크 (검사 순간)0ms10~50ms순간 지연
워크로드별 성능 오버헤드 워크로드 유형 오버헤드 (%) 0% 1% 2% 3% 4% 커널 빌드 파일 I/O 네트워크 프로세스 execve 스파이크 순간 지연

성능 튜닝 가이드

환경권장 intervalpcfi_validateprofile_validate예상 오버헤드
고성능 DB 서버6012< 0.1%
웹 서버1523< 0.5%
CI/CD 빌드 서버3012< 1%
보안 게이트웨이5341~3%
컨테이너 호스트30231~2%
성능 최적화 팁:
  • lkrg.interval을 늘리면 타이머 스파이크 빈도 감소 (보안 트레이드오프 있음)
  • lkrg.pcfi_validate=1로 낮추면 자격증명 검사 빈도 감소
  • execve 집중 워크로드(컨테이너 환경)에서는 오버헤드가 상대적으로 커질 수 있음
  • 프로세스 수가 많은 서버(수천 개)에서는 cred 전수 검사 시간이 길어지므로, 간격을 넓히거나 pcfi_validate를 낮추세요

perf를 이용한 오버헤드 측정

# LKRG 관련 CPU 사용량 측정
sudo perf top -g -p $(pgrep -f lkrg || echo 0)

# LKRG 타이머 콜백 실행 시간 측정
sudo perf probe -a 'p_offload_work'
sudo perf stat -e 'probe:p_offload_work' -- sleep 60

# kretprobe 오버헤드 측정 (commit_creds 호출 빈도)
sudo perf stat -e 'probe:commit_creds' -- sleep 60

# 전체 시스템 영향 비교 (LKRG 로드 전/후)
# 로드 전
sudo rmmod lkrg 2>/dev/null
sysbench cpu --threads=8 run
sysbench threads --threads=64 run

# 로드 후
sudo modprobe lkrg
sysbench cpu --threads=8 run
sysbench threads --threads=64 run

커널 호환성

LKRG는 out-of-tree 모듈이므로 커널 내부 API 변경에 민감합니다.

지원 버전

커널 버전LKRG 지원비고
5.4 LTS지원Debian 11, Ubuntu 20.04
5.10 LTS지원Debian 11 backports
5.15 LTS지원Ubuntu 22.04
6.1 LTS지원Debian 12
6.6 LTS지원최신 LTS
6.8~6.12지원 (최신)최신 안정 릴리스
< 5.4제한적이전 버전은 테스트 부족

호환성 이슈

아키텍처별 지원

아키텍처지원 상태비고
x86_64완전 지원 (주요 개발 대상)IDT/GDT/MSR/LSTAR 전체 검증
ARM64 (AArch64)지원코드 무결성 + cred 검증, 일부 CPU 객체 검사 제한
x86 (32비트)제한적이전 버전에서 지원, 최근 테스트 부족
기타미지원RISC-V, PowerPC, MIPS 등은 미지원

커널 설정 충돌

# LKRG와 충돌 가능한 커널 설정

# CONFIG_DEBUG_SET_MODULE_RONX가 비활성화된 경우
# 모듈 텍스트가 쓰기 가능하여 해시 변경 가능 → 오탐 발생
# 해결: CONFIG_STRICT_MODULE_RWX=y 권장

# CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y + lockdown=confidentiality
# kprobe 등록이 차단될 수 있음
# 해결: lockdown=integrity 모드 사용

# CONFIG_TRIM_UNUSED_KSYMS=y
# 심볼 제거로 LKRG가 필요한 심볼을 찾지 못할 수 있음
# 해결: 해당 옵션 비활성화

대안 비교

LKRG 외에도 호스트 무결성 검증을 위한 다양한 도구가 있습니다.

도구검증 계층방식장점단점
LKRG커널 메모리런타임 해시커널 루트킷 탐지ring 0 우회 가능
IMA/EVM파일 시스템파일 해시/서명메인라인, TPM 연동런타임 메모리 미검증
AIDE파일 시스템데이터베이스 비교간단한 설정실시간 아님, 메모리 미검증
Samhain파일 + 커널주기적 스캔/proc 기반 커널 검사LKRG 수준 깊이 부족
Tripwire파일 시스템데이터베이스 비교상용/오픈소스 둘 다실시간 아님
OSSEC파일 + 로그에이전트 기반종합 HIDS커널 수준 탐지 제한
무결성 검증 도구 비교 — 보호 계층별 보호 계층 하드웨어 TPM, Secure Boot, IOMMU 커널 메모리 LKRG Samhain* VFS / 파일 IMA/EVM AIDE Tripwire 사용자 공간 OSSEC Auditd * Samhain의 커널 검사는 /proc 기반으로 LKRG 대비 제한적 LKRG 고유 영역 (커널 메모리 직접 검증)

배포 가이드

프로덕션 배포 절차

  1. 사전 테스트: 스테이징 환경에서 최소 1주간 lkrg.profile_enforce=0(log only)으로 운영하여 오탐 확인
  2. 점진적 강화: 오탐이 없으면 profile_enforce를 단계적으로 올림
  3. 모니터링 연동: LKRG 로그를 SIEM에 전달하고 경보 규칙 설정
  4. 커널 업그레이드 계획: DKMS로 자동 빌드되지만, 주요 커널 버전 업그레이드 전 LKRG 호환성 확인

Ansible 배포 예시

---
# ansible playbook: LKRG 배포
- name: Deploy LKRG
  hosts: production_servers
  become: yes
  tasks:
    - name: 의존성 설치
      apt:
        name:
          - dkms
          - linux-headers-{{ ansible_kernel }}
          - build-essential
          - git
        state: present

    - name: LKRG 소스 클론
      git:
        repo: https://github.com/lkrg-org/lkrg.git
        dest: /usr/src/lkrg
        version: main

    - name: DKMS 설치
      command: make dkms-install
      args:
        chdir: /usr/src/lkrg

    - name: 모듈 로드
      modprobe:
        name: lkrg
        state: present

    - name: 부팅 시 자동 로드
      copy:
        content: "lkrg\n"
        dest: /etc/modules-load.d/lkrg.conf

    - name: sysctl 설정
      sysctl:
        name: "{{ item.key }}"
        value: "{{ item.value }}"
        sysctl_file: /etc/sysctl.d/lkrg.conf
      loop:
        - { key: "lkrg.profile_validate", value: "3" }
        - { key: "lkrg.profile_enforce", value: "2" }
        - { key: "lkrg.interval", value: "15" }

컨테이너 환경 배포

Docker/Kubernetes 환경에서 LKRG를 사용하려면 호스트 커널에 모듈을 로드해야 합니다. 컨테이너는 호스트와 커널을 공유하므로, LKRG 하나로 전체 컨테이너의 커널 수준 보안을 강화할 수 있습니다.

# 호스트에서 LKRG 로드 (컨테이너 전체에 적용)
sudo modprobe lkrg

# 컨테이너에서 새 프로세스 실행 시 cred 검증 활성화
sudo sysctl -w lkrg.pcfi_validate=3

# 주의: 컨테이너 빈번한 생성/삭제 시 execve 오버헤드 고려
sudo sysctl -w lkrg.interval=30  # 검사 간격 넓히기
가상화(Virtualization) 환경 제한: VM(가상 머신) 내부에서 LKRG를 실행할 때, 하이퍼바이저(Hypervisor) 수준의 공격(VM escape)은 탐지할 수 없습니다. LKRG는 게스트 커널 내부의 변조만 감시합니다. 호스트 보호를 위해서는 호스트에도 별도로 LKRG를 설치하세요.

모니터링 연동 (Prometheus + AlertManager)

# LKRG 경고를 Prometheus alertable metric으로 변환
# 커스텀 exporter 스크립트 예시

#!/bin/bash
# /usr/local/bin/lkrg-exporter.sh
LKRG_ALERTS=$(dmesg | grep -c "\[p_lkrg\] ALERT" 2>/dev/null || echo 0)
echo "# HELP lkrg_alerts_total Total LKRG alert count"
echo "# TYPE lkrg_alerts_total counter"
echo "lkrg_alerts_total ${LKRG_ALERTS}"

Secure Boot 연동

Secure Boot가 활성화된 시스템에서는 서명되지 않은 out-of-tree 커널 모듈의 로드가 차단됩니다. LKRG를 사용하려면 MOK(Machine Owner Key)로 모듈에 서명해야 합니다.

MOK 키 생성 및 모듈 서명

# 1. MOK 키 페어 생성
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv \
    -outform DER -out MOK.der -nodes -days 36500 \
    -subj "/CN=LKRG Module Signing Key/"

# 2. MOK 등록 (재부팅 시 비밀번호 입력 필요)
sudo mokutil --import MOK.der

# 3. 재부팅 후 MOK Manager에서 Enroll MOK 선택
sudo reboot

# 4. LKRG 모듈 서명
sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
    sha256 MOK.priv MOK.der \
    /lib/modules/$(uname -r)/updates/dkms/lkrg.ko

# 5. 서명 확인
modinfo lkrg | grep sig

# 6. 서명된 모듈 로드
sudo modprobe lkrg

DKMS 자동 서명 설정

# /etc/dkms/framework.conf에 추가
sign_tool="/usr/lib/linux-kbuild-$(uname -r | cut -d. -f1-2)/scripts/sign-file"
mok_signing_key="/root/MOK.priv"
mok_certificate="/root/MOK.der"

# 이후 DKMS 빌드 시 자동 서명됨
sudo dkms install lkrg/$(cat /usr/src/lkrg/VERSION)

키 보안 관리

# MOK 프라이빗 키 보호
sudo chmod 400 /root/MOK.priv
sudo chown root:root /root/MOK.priv

# 키 파일 무결성 보호 (immutable 속성)
sudo chattr +i /root/MOK.priv

# 키 접근 감사 (audit 규칙)
sudo auditctl -w /root/MOK.priv -p rwa -k mok_key_access

# 키가 유출되었을 때: MOK 키 교체 절차
# 1. 새 키 페어 생성
# 2. 기존 MOK 키 삭제
sudo mokutil --delete /root/MOK.der
# 3. 새 MOK 키 등록
sudo mokutil --import /root/MOK_new.der
# 4. 재부팅하여 MOK Manager에서 확인
# 5. 모든 모듈을 새 키로 재서명
보안 주의: MOK 프라이빗 키(MOK.priv)는 반드시 root만 읽을 수 있도록 권한을 설정하고, 가능하면 별도 암호화(Encryption)된 저장소에 보관하세요. 키가 유출되면 공격자가 악성 모듈에 서명하여 Secure Boot를 우회할 수 있습니다. 자세한 내용은 Secure Boot 페이지를 참조하세요.

Lockdown LSM과의 연동

커널 Lockdown LSM이 integrity 모드로 활성화된 경우, LKRG의 kprobe 등록은 허용되지만 /dev/mem 등을 통한 커널 메모리 직접 접근은 차단됩니다. confidentiality 모드에서는 kprobe 자체가 차단될 수 있으므로, LKRG 사용 시 lockdown=integrity를 권장합니다.

트러블슈팅

자주 발생하는 문제

증상원인해결 방법
insmod: ERROR: could not insert moduleSecure Boot 모듈 서명 누락MOK으로 모듈 서명 후 재시도
Unknown symbol in module커널 헤더 버전 불일치apt install linux-headers-$(uname -r) 후 재빌드
빈번한 ALERT 로그오탐 (ftrace, livepatch, eBPF 등)lkrg.profile_validate 조정, 최신 LKRG 업데이트
부팅 시 커널 패닉lkrg.profile_enforce=4 + 초기화 경합GRUB에서 lkrg.profile_enforce=0으로 부팅 후 조정
성능 저하짧은 검사 간격lkrg.interval 증가, lkrg.pcfi_validate 축소
모듈 로드 실패 (6.x)커널 API 변경최신 LKRG git 버전 사용

디버깅(Debugging) 절차

# 1. LKRG 모듈 상태 확인
lsmod | grep lkrg
modinfo lkrg

# 2. 현재 sysctl 설정 확인
sysctl -a 2>/dev/null | grep lkrg

# 3. LKRG 로그 확인 (커널 메시지)
dmesg | grep -i lkrg | tail -20

# 4. 디버그 모드로 로드 (상세 로그)
sudo rmmod lkrg 2>/dev/null
sudo sysctl -w lkrg.log_level=4 2>/dev/null || true
sudo modprobe lkrg
dmesg | tail -50

# 5. LKRG 빌드 로그 확인 (DKMS)
cat /var/lib/dkms/lkrg/*/build/make.log

# 6. 커널 설정 확인 (필수 옵션)
grep -E "(KPROBES|MODULES|KALLSYMS|JUMP_LABEL)" /boot/config-$(uname -r)
# CONFIG_KPROBES=y 필수
# CONFIG_MODULES=y 필수
# CONFIG_KALLSYMS=y 권장

livepatch 호환성 처리

kpatchlivepatch를 사용하는 환경에서는 커널 코드가 런타임에 정상적으로 변경됩니다. LKRG는 이를 코드 변조로 탐지할 수 있으므로 다음 절차를 따르세요:

# 1. livepatch 적용 전: LKRG를 log-only 모드로 전환
sudo sysctl -w lkrg.profile_enforce=0

# 2. livepatch 적용
sudo kpatch load livepatch-module.ko

# 3. LKRG 기준 해시 갱신 (수동 트리거)
sudo sysctl -w lkrg.trigger=1

# 4. 오탐이 없는지 확인
dmesg | grep -i lkrg | tail -5

# 5. 대응 정책 복원
sudo sysctl -w lkrg.profile_enforce=2
자동화: livepatch를 자주 적용하는 환경에서는 위 절차를 스크립트로 자동화하세요. lkrg.trigger=1을 쓰면 LKRG가 현재 상태를 새 기준으로 채택하므로, livepatch 직후 즉시 실행하면 됩니다. livepatch 페이지도 참조하세요.

LKRG 완전 제거

# 모듈 언로드
sudo rmmod lkrg

# DKMS에서 제거
sudo dkms remove lkrg/$(cat /usr/src/lkrg/VERSION) --all

# 부팅 자동 로드 해제
sudo rm -f /etc/modules-load.d/lkrg.conf

# sysctl 설정 제거
sudo rm -f /etc/sysctl.d/lkrg.conf

# 소스 정리
sudo rm -rf /usr/src/lkrg

LKRG 로그 분석 가이드

LKRG 로그 메시지는 심각도에 따라 분류됩니다. 실제 운영 환경에서 로그를 해석하는 방법을 알아봅니다.

로그 패턴심각도의미대응
[p_lkrg] Loading LKRGINFOLKRG 모듈 로드 시작정상, 대응 불필요
[p_lkrg] LKRG initialized successfullyINFO초기화 완료, 기준 해시 설정됨정상, 대응 불필요
[p_lkrg] New module registeredINFO새 모듈 로드, 해시 DB 갱신정상, 의도된 모듈인지 확인
[p_lkrg] ALERT: .text integrityALERT커널/모듈 코드 변조 탐지즉시 조사 — 루트킷 가능성
[p_lkrg] ALERT: credentialsALERT프로세스 자격증명 변조즉시 조사 — 권한 상승 공격
[p_lkrg] ALERT: SELinuxALERTSELinux enforcing 변조즉시 조사 — 정책 우회 시도
[p_lkrg] ALERT: IDT/MSRALERTCPU 특수 구조 변조즉시 조사 — 인터럽트 하이재킹
# 실시간 LKRG 로그 모니터링
sudo dmesg -wH | grep --color=always "p_lkrg"

# 최근 24시간 LKRG ALERT 로그 (systemd 환경)
journalctl -k --since "24 hours ago" --grep="p_lkrg.*ALERT"

# LKRG ALERT 발생 시 자동 알림 스크립트
#!/bin/bash
# /usr/local/bin/lkrg-monitor.sh
while true; do
    dmesg -c | grep "\[p_lkrg\] ALERT" | while read -r line; do
        echo "LKRG ALERT on $(hostname): $line" | \
            mail -s "LKRG Security Alert" admin@example.com
        logger -p security.crit "LKRG: $line"
    done
    sleep 5
done

인시던트 대응 절차

LKRG가 ALERT를 발생시키면 다음 절차를 따르세요:

  1. 격리(Isolation): 네트워크에서 즉시 분리 (공격 확산 방지)
  2. 증거 수집: dmesg, /var/log/kern.log, 메모리 덤프(Dump) 수집
  3. 프로세스 확인: ps auxf, /proc/[pid]/exe, /proc/[pid]/maps 검사
  4. 모듈 확인: lsmod로 비정상 모듈 확인, cat /proc/modules 비교
  5. 포렌식: 디스크 이미지 생성 후 오프라인 분석
  6. 복구: 깨끗한 이미지에서 시스템 재구축
ALERT = 변조 확정이 아닙니다: LKRG ALERT는 기준값과의 불일치를 의미합니다. ftrace 활성화, livepatch 적용, 또는 커널 디버깅 도구 사용 시에도 발생할 수 있습니다. 로그의 컨텍스트를 반드시 확인하세요.

내부 아키텍처

LKRG의 내부 구현을 더 깊이 분석합니다. 초기화 시퀀스(Sequence), 데이터베이스 구조, 동기화 메커니즘, 메모리 관리를 살펴봅니다.

초기화 시퀀스

LKRG 모듈이 로드될 때 수행하는 초기화 과정은 순서가 중요합니다. 특히 alternative patching이 완료된 후에 해시를 계산해야 오탐을 방지할 수 있습니다.

/* LKRG 모듈 초기화 — module_init() (단순화) */
static int __init p_lkrg_init(void)
{
    int ret;

    p_print_log(P_LOG_INFO, "Loading LKRG...");

    /* 1단계: 심볼 해석 — kallsyms로 필요한 커널 심볼 검색 */
    ret = p_resolve_symbols();
    /* _stext, _etext, sys_call_table, selinux_enforcing 등 */

    /* 2단계: CPU 정보 수집 — per-CPU IDT/GDT/MSR 읽기 */
    smp_call_function_many(cpu_online_mask,
                           p_collect_cpu_info, NULL, 1);

    /* 3단계: 커널 텍스트 기준 해시 계산 */
    p_hash_from_text(_stext, _etext - _stext, p_db.kernel_hash);

    /* 4단계: 모듈 텍스트 해시 데이터베이스 구축 */
    p_init_module_hash_db();

    /* 5단계: 전체 프로세스 자격증명 스냅샷 */
    p_init_task_cred_db();

    /* 6단계: SELinux 기준값 저장 */
    p_init_selinux_state();

    /* 7단계: kprobe/kretprobe 등록 */
    ret = p_register_hooks();

    /* 8단계: module_notifier 등록 */
    register_module_notifier(&p_module_nb);

    /* 9단계: 주기적 검사 타이머 시작 */
    mod_timer(&p_timer, jiffies + p_interval);

    /* 10단계: sysctl 인터페이스 등록 */
    p_register_sysctl();

    p_print_log(P_LOG_INFO,
        "LKRG initialized successfully");
    return 0;
}
LKRG 초기화 시퀀스 1. 심볼 해석 kallsyms_lookup 2. CPU 정보 수집 per-CPU IDT/GDT/MSR 3. 커널 텍스트 해시 SHA-256 기준값 4. 모듈 해시 DB 각 모듈별 해시 5. cred 스냅샷 전체 task 순회 6. SELinux 기준값 enforcing 값 저장 7. kprobe 등록 commit_creds 등 8. 모듈 notifier load/unload 감시 9. 타이머 시작 주기적 검사 개시 10. sysctl 등록 런타임 설정 인터페이스 LKRG 활성 — 런타임 보호 시작 이벤트 훅 + 타이머 이중 감시 작동 중요: 3~5단계의 기준 해시는 alternative patching, SMP 초기화 완료 후에 계산되어야 함 (초기화 순서가 보안에 직접 영향)

내부 데이터베이스 구조

LKRG는 기준값을 저장하는 내부 데이터베이스를 유지합니다. 이 데이터베이스는 모듈의 전역 변수로 존재하며, 초기화 시 채워지고 런타임에 갱신됩니다.

/* LKRG 내부 데이터베이스 — 상세 구조 (단순화) */
struct p_lkrg_global_db {

    /* === CI (Code Integrity) 데이터베이스 === */
    struct {
        char            hash[32];           /* 커널 .text SHA-256 */
        unsigned long   stext_addr;         /* _stext 주소 */
        unsigned long   etext_addr;         /* _etext 주소 */
        size_t          text_size;          /* 텍스트 영역 크기 */
    } kernel_ci;

    /* 모듈별 해시 데이터베이스 */
    struct p_module_hash_entry {
        struct list_head  list;
        char              name[MODULE_NAME_LEN];
        char              hash[32];
        unsigned long     text_addr;
        size_t            text_size;
    } *module_list;
    unsigned int        module_count;

    /* === SI (System Integrity) 데이터베이스 === */
    struct p_cpu_snapshot {
        char            idt_hash[32];
        char            gdt_hash[32];
        u64             msr_lstar;
        u64             msr_cstar;        /* compat 시스템 콜 */
        unsigned long   cr0;
        unsigned long   cr4;
    } per_cpu_db[NR_CPUS];

    char                syscall_table_hash[32];
    unsigned long       syscall_table_addr;

    /* === PCFI (Process Credentials) 데이터베이스 === */
    struct {
        spinlock_t      lock;
        unsigned int    task_count;
        /* per-task: pid, cred 해시, nsproxy 해시 */
    } pcfi;

    /* === SELinux 기준값 === */
    int                 selinux_enforcing;
    unsigned long       selinux_enforcing_addr;

    /* === 타이머/설정 === */
    struct timer_list   timer;
    unsigned long       interval;             /* jiffies 단위 */
    struct work_struct  work;                 /* 검사 작업 */
};

동기화와 락킹

LKRG는 다중 CPU 환경에서 안전하게 동작해야 합니다. 특히 기준 해시 갱신과 검증이 동시에 발생하면 안 됩니다.

보호 대상동기화 메커니즘용도
모듈 해시 DBmutex모듈 추가/삭제 시 DB 갱신 직렬화
cred 해시 테이블spinlock프로세스 생성/소멸 시 빠른 갱신
전체 검사mutex + preempt_disable타이머 검사와 이벤트 검사 직렬화
per-CPU 객체smp_call_function모든 CPU에서 동시 스냅샷
sysctl 변수atomic / READ_ONCE런타임 설정 변경의 원자성

메모리 보호

LKRG 자체의 코드와 데이터를 공격자로부터 보호하는 것은 근본적 한계가 있지만, 다음 기법으로 방어를 강화합니다.

/* LKRG 자기 보호 기법 */

/* 1. 모듈 자체를 ro+x로 설정 (커널이 자동 처리) */
/* CONFIG_STRICT_MODULE_RWX=y 필요 */

/* 2. lkrg.hide=1: 모듈 리스트에서 제거 */
static void p_hide_module(void) {
    /* modules 리스트에서 자신을 제거 */
    list_del(&THIS_MODULE->list);
    /* kobject 제거 → /sys/module/lkrg 사라짐 */
    kobject_del(&THIS_MODULE->mkobj.kobj);
    /* lsmod, /proc/modules에서 보이지 않음 */
}

/* 3. sysctl 잠금: hide 후 sysctl 접근 차단 */
static void p_lock_sysctl(void) {
    /* sysctl 테이블의 mode를 0으로 변경 */
    /* → 외부에서 설정 변경 불가 */
}

모듈 로딩 제어

LKRG의 lkrg.block_modules 기능은 새로운 커널 모듈의 로드를 차단합니다. 이는 공격자가 악성 커널 모듈을 로드하는 것을 방지하는 강력한 방어 수단입니다.

모듈 차단 메커니즘

/* LKRG 모듈 로드 차단 구현 (단순화) */
static int p_module_notifier_callback(
    struct notifier_block *nb,
    unsigned long action, void *data)
{
    struct module *mod = data;

    switch (action) {
    case MODULE_STATE_COMING:
        /* block_modules=1이면 새 모듈 로드 차단 */
        if (p_block_modules) {
            p_print_log(P_LOG_ALERT,
                "Module load blocked: %s", mod->name);
            return NOTIFY_BAD;  /* 모듈 로드 거부 */
        }
        break;

    case MODULE_STATE_LIVE:
        /* 모듈 활성화: 텍스트 해시 계산 및 DB 추가 */
        p_add_module_hash(mod);
        p_print_log(P_LOG_INFO,
            "New module registered: %s (hash updated)",
            mod->name);
        break;

    case MODULE_STATE_GOING:
        /* 모듈 제거: DB에서 해시 삭제 */
        p_del_module_hash(mod);
        break;
    }
    return NOTIFY_OK;
}

모듈 차단과 커널 서명 검증 비교

방어 수단차단 방식장점단점
LKRG block_modules모든 새 모듈 로드 차단가장 강력한 차단정당한 모듈도 차단됨
CONFIG_MODULE_SIG_FORCE서명 없는 모듈 거부서명된 모듈은 허용서명 키 관리 필요
Lockdown LSM커널 수정 동작 제한메인라인 통합모듈 로드 자체는 허용
IMA MODULE_CHECK해시/서명 미일치 모듈 거부파일 무결성 검증정책 설정 복잡
# 모듈 차단 운영 가이드

# 1. 필요한 모든 모듈이 로드된 후 차단 활성화
# (부팅 시 모든 드라이버 로드 완료 확인)
lsmod | wc -l  # 현재 로드된 모듈 수 확인

# 2. 차단 활성화
sudo sysctl -w lkrg.block_modules=1

# 3. 차단 확인 (새 모듈 로드 시도)
sudo modprobe dummy 2>&1
# 결과: modprobe: ERROR: could not insert 'dummy'
# dmesg: [p_lkrg] ALERT: Module load blocked: dummy

# 4. 임시 해제 (유지보수 시)
sudo sysctl -w lkrg.block_modules=0
sudo modprobe needed_module
sudo sysctl -w lkrg.block_modules=1
# → LKRG가 자동으로 새 모듈의 해시를 DB에 추가

런타임 이벤트 흐름

LKRG의 런타임 동작을 이벤트 유형별로 상세히 분석합니다. 각 이벤트에서 어떤 검증이 수행되고 어떤 경로로 탐지/대응이 이루어지는지 살펴봅니다.

execve 이벤트 흐름

프로세스가 execve()를 실행하면 자격증명이 변경될 수 있습니다(setuid 바이너리 등). LKRG는 이 과정을 kretprobe로 추적합니다.

/* execve 시 LKRG 검증 흐름 (단순화) */

/* kprobe: security_bprm_committing_creds() 진입 */
static int p_bprm_committing_pre(
    struct kprobe *p, struct pt_regs *regs)
{
    struct task_struct *task = current;

    /* 1. 현재 cred 해시 저장 (변경 전) */
    p_save_pre_cred_hash(task);

    return 0;
}

/* kretprobe: commit_creds() 반환 후 */
static int p_commit_creds_post(
    struct kretprobe_instance *ri,
    struct pt_regs *regs)
{
    struct task_struct *task = current;

    /* 2. 새 cred 해시 계산 */
    char new_hash[32];
    p_calc_cred_hash(task->cred, new_hash);

    /* 3. DB의 cred 해시를 새 값으로 갱신 */
    p_update_task_cred_hash(task->pid, new_hash);

    /* 이 경로를 통한 변경은 합법적 */
    return 0;
}

/* 주기적 타이머 검사에서 */
static void p_check_task_cred(struct task_struct *task)
{
    char current_hash[32];

    /* 현재 cred의 해시를 계산 */
    p_calc_cred_hash(task->cred, current_hash);

    /* DB에 저장된 해시와 비교 */
    if (memcmp(current_hash, p_db_get_hash(task->pid), 32)) {
        /* kretprobe를 거치지 않은 변경 → 변조! */
        p_print_log(P_LOG_ALERT,
            "Credentials violation! PID=%d COMM=%s",
            task->pid, task->comm);
        p_trigger_response(task);
    }
}

모듈 로드/언로드 이벤트 흐름

이벤트notifier 상태LKRG 동작해시 DB 변경
모듈 로드 시작MODULE_STATE_COMINGblock_modules 검사없음
모듈 활성화MODULE_STATE_LIVE.text 해시 계산추가
모듈 제거 시작MODULE_STATE_GOING해시 DB에서 삭제삭제
타이머 검사-모든 모듈 해시 재검증변경 없음 (비교만)

오탐(False Positive) 발생 시나리오

LKRG가 오탐을 발생시킬 수 있는 합법적 커널 동작을 이해하는 것이 중요합니다.

시나리오원인LKRG 반응해결 방법
Livepatch 적용커널 .text가 정상적으로 변경코드 무결성 ALERTlkrg.trigger=1로 기준 갱신
ftrace 활성화함수 프롤로그에 NOP→call 패치코드 무결성 ALERT (가능)최신 LKRG는 ftrace 호환
eBPF trampolineBPF 프로그램이 커널 코드에 연결가끔 ALERT 발생profile_validate 조정
CPU 핫플러그CPU 온/오프라인 시 per-CPU 변경IDT/GDT 불일치 가능LKRG가 핫플러그 감지 처리
커널 디버거(kgdb)브레이크포인트 삽입 시 코드 변경코드 무결성 ALERT디버깅 시 LKRG 비활성화
💡

오탐 최소화: 프로덕션 환경에서 오탐을 줄이려면 (1) LKRG를 최신 버전으로 유지하고, (2) ftrace/eBPF 활용이 많은 환경에서는 profile_validate=2로 설정하며, (3) livepatch 적용 직후 lkrg.trigger=1로 기준값을 갱신하세요.

LKRG와 컨테이너/가상화(Virtualization) 환경

현대 인프라에서 LKRG를 효과적으로 활용하기 위해 컨테이너와 가상화 환경에서의 동작 특성을 이해해야 합니다.

Docker/Kubernetes 환경

컨테이너는 호스트 커널을 공유하므로, 호스트에 LKRG를 설치하면 모든 컨테이너의 커널 수준 보안을 강화할 수 있습니다. 단, 컨테이너 내부의 프로세스 수가 많으면 cred 검사 오버헤드가 증가합니다.

LKRG 컨테이너 환경 보호 구조 컨테이너 계층 (사용자 공간) Container A PID ns, NET ns, ... cred: uid=0(root) Container B PID ns, NET ns, ... cred: uid=1000 Container C PID ns, NET ns, ... cred: uid=0(root) Compromised! 커널 익스플로잇 cred 변조 시도 호스트 프로세스 dockerd, kubelet 호스트 커널 (공유) LKRG 커널 모듈 모든 컨테이너 + 호스트의 cred/코드 검증 Container D 변조 탐지! 커널 .text 무결성 모든 cred 검증 ns 탈출 탐지
환경LKRG 설치 위치보호 범위주의사항
Docker (단일 호스트)호스트 커널모든 컨테이너 + 호스트컨테이너 수에 비례하는 cred 검사 비용
Kubernetes (노드)각 노드 커널해당 노드의 모든 PodDaemonSet으로 배포 자동화
VM (KVM/QEMU)게스트 커널해당 VM 내부만VM escape 공격은 탐지 불가
중첩 가상화각 계층별해당 커널 범위하이퍼바이저 수준은 미보호

Kubernetes DaemonSet 배포

# LKRG를 Kubernetes DaemonSet으로 배포
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: lkrg
  namespace: kube-system
  labels:
    app: lkrg
spec:
  selector:
    matchLabels:
      app: lkrg
  template:
    metadata:
      labels:
        app: lkrg
    spec:
      hostPID: true
      hostNetwork: true
      containers:
      - name: lkrg-loader
        image: alpine:latest
        securityContext:
          privileged: true
        command:
          - /bin/sh
          - -c
          - |
            # LKRG 모듈 로드
            modprobe lkrg 2>/dev/null || insmod /opt/lkrg/lkrg.ko
            # sysctl 설정
            sysctl -w lkrg.profile_validate=3
            sysctl -w lkrg.profile_enforce=2
            sysctl -w lkrg.interval=15
            # 모니터링 루프
            while true; do
              dmesg -c | grep "p_lkrg.*ALERT" >> /var/log/lkrg-alerts.log
              sleep 10
            done
        volumeMounts:
          - name: modules
            mountPath: /lib/modules
            readOnly: true
          - name: lkrg-module
            mountPath: /opt/lkrg
      volumes:
        - name: modules
          hostPath:
            path: /lib/modules
        - name: lkrg-module
          hostPath:
            path: /opt/lkrg

탐지와 대응

LKRG의 탐지-대응 파이프라인을 세부적으로 분석하고, 프로덕션 환경에서의 운영 전략을 정리합니다.

대응 동작 상세

위반 유형enforce=0 (Log)enforce=1 (Kill)enforce=2 (Panic)
커널 .text 변조ALERT 로그만ALERT 로그만 (프로세스 특정 불가)즉시 커널 패닉
모듈 .text 변조ALERT + 모듈명 로그ALERT 로그만즉시 커널 패닉
cred 변조ALERT + PID/COMM 로그해당 프로세스 SIGKILL즉시 커널 패닉
SELinux 변조ALERT 로그ALERT 로그 (복원 시도)즉시 커널 패닉
IDT/MSR 변조ALERT 로그ALERT 로그만즉시 커널 패닉
syscall table 변조ALERT + 엔트리 번호ALERT 로그만즉시 커널 패닉

SIEM/SOAR 연동 상세

# 1. rsyslog: LKRG 경고를 원격 SIEM으로 전송
# /etc/rsyslog.d/50-lkrg.conf
if $msg contains '[p_lkrg] ALERT' then {
    action(type="omfwd"
           target="siem.example.com"
           port="514"
           protocol="tcp"
           template="RSYSLOG_SyslogProtocol23Format")
    action(type="omfile"
           file="/var/log/lkrg-alerts.log"
           template="RSYSLOG_TraditionalFileFormat")
    stop
}

# 2. Elastic Stack 연동 (Filebeat)
# /etc/filebeat/modules.d/lkrg.yml
- module: system
  syslog:
    enabled: true
    var.paths: ["/var/log/lkrg-alerts.log"]

# 3. Prometheus/Alertmanager 경보 규칙
# /etc/prometheus/rules/lkrg.rules.yml
groups:
  - name: lkrg
    rules:
      - alert: LKRGIntegrityViolation
        expr: lkrg_alerts_total > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "LKRG detected integrity violation on {{ $labels.instance }}"
          description: "Kernel integrity violation detected. Immediate investigation required."

자동화된 인시던트 대응 스크립트

#!/bin/bash
# /usr/local/bin/lkrg-incident-response.sh
# LKRG ALERT 발생 시 자동 수행하는 포렌식 스크립트

INCIDENT_DIR="/var/log/lkrg-incidents/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$INCIDENT_DIR"

echo "=== LKRG 인시던트 대응 시작: $(date) ===" | tee "$INCIDENT_DIR/summary.txt"

# 1. 커널 로그 수집
dmesg > "$INCIDENT_DIR/dmesg.log"
journalctl -k --since "1 hour ago" > "$INCIDENT_DIR/journal_kernel.log"

# 2. 프로세스 스냅샷
ps auxf > "$INCIDENT_DIR/ps_tree.txt"
cat /proc/modules > "$INCIDENT_DIR/modules.txt"
lsmod > "$INCIDENT_DIR/lsmod.txt"

# 3. 네트워크 연결 상태
ss -tupan > "$INCIDENT_DIR/network_connections.txt"

# 4. 열린 파일/소켓
lsof -n > "$INCIDENT_DIR/open_files.txt" 2>/dev/null

# 5. LKRG 관련 로그 추출
grep -i "p_lkrg" "$INCIDENT_DIR/dmesg.log" > "$INCIDENT_DIR/lkrg_alerts.txt"

# 6. 의심 프로세스 정보 수집
for pid in $(grep "PID=" "$INCIDENT_DIR/lkrg_alerts.txt" | \
             grep -oP 'PID=\K[0-9]+'); do
    echo "--- PID $pid ---" >> "$INCIDENT_DIR/suspect_procs.txt"
    ls -la /proc/$pid/exe >> "$INCIDENT_DIR/suspect_procs.txt" 2>/dev/null
    cat /proc/$pid/cmdline >> "$INCIDENT_DIR/suspect_procs.txt" 2>/dev/null
    cat /proc/$pid/maps >> "$INCIDENT_DIR/suspect_procs_maps.txt" 2>/dev/null
    echo "" >> "$INCIDENT_DIR/suspect_procs.txt"
done

# 7. 아카이브 생성
tar czf "${INCIDENT_DIR}.tar.gz" -C "$(dirname $INCIDENT_DIR)" \
    "$(basename $INCIDENT_DIR)"

echo "=== 수집 완료: ${INCIDENT_DIR}.tar.gz ===" | tee -a "$INCIDENT_DIR/summary.txt"

# 8. 알림 발송
echo "LKRG ALERT on $(hostname) at $(date)" | \
    mail -s "[CRITICAL] LKRG Integrity Violation" security@example.com \
    -A "${INCIDENT_DIR}.tar.gz"

성능 최적화

LKRG의 오버헤드를 워크로드 특성에 맞게 미세 조정하는 방법을 분석합니다.

오버헤드 분석 도구

# 1. LKRG 타이머 실행 빈도와 시간 측정
# ftrace로 LKRG 워크 함수 추적
echo 1 > /sys/kernel/debug/tracing/events/workqueue/workqueue_execute_start/enable
cat /sys/kernel/debug/tracing/trace_pipe | grep "p_offload"

# 2. kprobe 오버헤드 측정
# commit_creds 호출 빈도 (높을수록 LKRG 오버헤드 증가)
perf stat -e 'probe:commit_creds' -a -- sleep 60

# 3. LKRG 관련 CPU 시간
# /proc/timer_stats (구형 커널)
# BPF 기반 측정 (최신 커널)
bpftrace -e 'kprobe:p_offload_work { @start = nsecs; }
             kretprobe:p_offload_work { @latency = hist(nsecs - @start); }'

# 4. 프로세스 수 대비 검사 시간 상관관계
echo "프로세스 수: $(ps aux | wc -l)"
echo "LKRG 검사 간격: $(sysctl -n lkrg.interval 2>/dev/null || echo 'N/A')초"

워크로드별 최적화 전략

시나리오병목조치트레이드오프
대규모 컨테이너cred 전수 검사pcfi_validate=1, interval=60cred 변조 탐지 지연
빈번한 execvekretprobe 오버헤드pcfi_validate=1이벤트 기반 cred 추적 약화
모듈 빈번 로드해시 계산block_modules=0, interval=30악성 모듈 탐지 지연
실시간 시스템타이머 스파이크interval=300, profile_validate=1전체적 보호 약화
고보안 환경CPU 사용량interval=5, profile_validate=43~5% 오버헤드 수용

NUMA 환경 고려사항

대규모 NUMA(Non-Uniform Memory Access) 서버에서 LKRG의 smp_call_function_many()는 모든 CPU에서 동시에 검사를 수행합니다. 이는 IPI(Inter-Processor Interrupt) 오버헤드를 유발할 수 있습니다.

# NUMA 토폴로지 확인
numactl --hardware

# CPU 수에 따른 LKRG 설정 권장
# 8 CPU 이하: 기본 설정 유지
# 16~64 CPU: interval=15, profile_validate=3
# 64+ CPU: interval=30, profile_validate=2 (IPI 최소화)
CPU_COUNT=$(nproc)
if [ $CPU_COUNT -gt 64 ]; then
    sysctl -w lkrg.interval=30
    sysctl -w lkrg.profile_validate=2
elif [ $CPU_COUNT -gt 16 ]; then
    sysctl -w lkrg.interval=15
    sysctl -w lkrg.profile_validate=3
fi

보안 도구 전체 비교 종합

LKRG를 포함한 Linux 커널 보안 도구들의 역할과 상호 관계를 종합적으로 분석합니다.

도구보호 시점보호 계층메인라인LKRG와의 관계
LKRG런타임(사후 탐지)커널 메모리아니오-
IMA/EVM파일 접근 시(사전 예방)VFS/파일상호 보완 (다른 계층)
dm-verity블록 읽기 시블록 디바이스상호 보완 (읽기 전용 파일시스템)
Secure Boot부팅 시펌웨어/부트로더/커널상호 보완 (부팅 체인 보호)
Lockdown LSM런타임(사전 예방)커널 인터페이스상호 보완 (접근 차단)
kCFI/FineIBT런타임(사전 예방)제어 흐름상호 보완 (ROP/JOP 방어)
KASLR부팅 시메모리 레이아웃상호 보완 (주소 예측 방지)
AIDE/Tripwire주기적 스캔파일 시스템아니오상호 보완 (파일 변조 탐지)

최적의 보안 스택 구성

# 프로덕션 서버 권장 보안 스택

# === 1단계: 빌드 시 (커널 설정) ===
# KASLR + kCFI + SCS + Lockdown + MODULE_SIG
CONFIG_RANDOMIZE_BASE=y
CONFIG_CFI_CLANG=y
CONFIG_SHADOW_CALL_STACK=y          # ARM64
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y

# === 2단계: 부팅 시 ===
# Secure Boot + Lockdown integrity + IMA
# 커널 cmdline:
# lockdown=integrity ima_policy=tcb ima_appraise=enforce

# === 3단계: 런타임 ===
# LKRG 로드 + 설정
modprobe lkrg
sysctl -w lkrg.profile_validate=3
sysctl -w lkrg.profile_enforce=2
sysctl -w lkrg.interval=15
sysctl -w lkrg.block_modules=1     # 모든 필요 모듈 로드 후

# === 4단계: 모니터링 ===
# LKRG ALERT → SIEM → 자동 대응
# IMA audit → 컴플라이언스 보고
# auditd → 행위 기반 탐지
ℹ️

방어 심층(Defense in Depth): 단일 보안 도구만으로는 모든 공격을 방어할 수 없습니다. LKRG(커널 메모리 런타임 검증) + IMA(파일 무결성) + Secure Boot(부팅 체인) + kCFI(제어 흐름) + Lockdown(접근 차단)을 조합하면 각 계층에서 서로 다른 공격 벡터(Attack Vector)를 방어하는 심층 방어 체계를 구축할 수 있습니다.

외부 참고 자료