[하루한줄] CVE-2022-0435: 리눅스 커널의 원격 Stack Buffer Overflow 취약점

URL

CVE-2022-0435: A Remote Stack Overflow in The Linux Kernel

Target

  • Linux Kernel 4.8 ~ 5.17-rc3

Explain

지난 11월 공개된 TIPC 취약점 [하루한줄] CVE-2021-43267: Remote Linux Kernel Heap Overflow | TIPC Module Allows Arbitrary Code Execution 에 이어 TIPC 모듈의 기능 중 모니터링 프레임워크에서 원격에서 Stack Buffer Overflow를 트리거할 수 있는 취약점의 세부 정보가 공개되었습니다.

TIPC의 모니터링 프레임워크는 동일한 도메인의 인접 노드를 모니터링하기 위해 tipc_peer 구조체에서 참조하는 tipc_mon_domain 구조체를 사용합니다. 구조체 필드는 아래와 같으며 memeber 수와 같은 TIPC 토폴로지를 정의하는 데 사용되는 도메인 레코드를 나타냅니다.

#define MAX_MON_DOMAIN       64

struct tipc_mon_domain {
        u16 len;
        u16 gen;
        u16 ack_gen;
        u16 member_cnt;
        u64 up_map;
        u32 members[MAX_MON_DOMAIN];
 };

해당 구조체의 members 필드는 최대 MAX_MON_DOMAIN , 64개의 도메인 멤버를 추적할 수 있도록 정의되어 있습니다.

TIPC에서 노드 간 메시지는 헤더 필드 LINK_PROTOCOL (TIPC message user)와 STATE_MSG(message type)를 통해 나뉘는데, STATE_MSG 내에 도메인 레코드가 포함된 경우 피어의 도메인 레코드를 업데이트하는 tipc_mon_rcv 함수에 취약점이 존재합니다.

void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
    struct tipc_mon_state *state, int bearer_id)
{
    ...
    struct tipc_mon_domain *arrv_dom = data;
    struct tipc_mon_domain dom_bef;                                   
    ...

    // new_member_cnt에 대한 최대값 검사가 존재하지 않음          
    if (dlen < dom_rec_len(arrv_dom, 0))                              
        return;
    if (dlen != dom_rec_len(arrv_dom, new_member_cnt))                
        return;
    if (dlen < new_dlen || arrv_dlen != new_dlen)                     
        return;
    ...

    /* Cache current domain record for later use */
    dom_bef.member_cnt = 0;
    dom = peer->domain;
    if (dom)                                                          
        memcpy(&dom_bef, dom, dom->len);                              

    /* Transform and store received domain record */
    if (!dom || (dom->len < new_dlen)) {
        kfree(dom);
        dom = kmalloc(new_dlen, GFP_ATOMIC);                          
        peer->domain = dom;                                           
        if (!dom)
            goto exit;
    }
    ...

tipc_mon_domain 구조체를 지역 변수로 할당한 뒤 헤더의 정의된 STATE_MSG 길이인 dlen이 충분히 큰지 등을 검사하는 루틴이 존재합니다.그러나 해당 검사 과정에서 new_member_cnt의 최대 크기로 정의되어 있는 #define MAX_MON_DOMAIN 64보다 작은지 확인하는 검사가 존재하지 않습니다.

dom = {
        len = 1072,
        gen = 3,
        ack_gen = 3,
        member_cnt = 264;
        up_map = 0xffffffffffffffff;
        u32 members[264] = 0x1337...
    };

따라서 해커가 위와 같이 임의의 member_cntMembers[] 필드가 있는 tipc_mon_domain를 보내면 memcpy(&dom_bef, dom, dom->len); 에서 스택에 272 bytes 크기로 할당한 tipc_mon_domain 구조체에 len 필드 값인 1072 bytes를 복사하게되고 stack buffer overflow가 트리거됩니다.

취약점은 new_member_cnt에 대한 최대 크기 검사를 추가하는 것으로 패치되었습니다.

/* Sanity check received domain record */
+       if (new_member_cnt > MAX_MON_DOMAIN)                                                
+               return;
        if (dlen < dom_rec_len(arrv_dom, 0))
                return;
        if (dlen != dom_rec_len(arrv_dom, new_member_cnt))


본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.