[하루한줄] CVE-2021-1969: Information leak in Qualcomm npu driver

URL

GHSL-2021-1031: Information leak in Qualcomm npu driver - CVE-2021-1969

Target

MSM Linux(Support Qualcomm chip)

테스트된 버전

  • Samsung Galaxy A71: SM-A715F/DS
    • AP: A715FXXU3ATJ2
    • CP: A715FXXU3ATI5
    • Kernel version 4.14.117-19828683
    • build ID QP1A.190711.020.A715FXXU3ATJ2

Explain

퀄컴의 Neural Processing Unit, NPU를 지원하는 드라이버에서 커널 주소를 유출할 수 있는 Information disclosure 취약점의 세부 정보가 공개되었습니다.

아래 코드는 취약점이 발생하는 npu_receive_event 함수의 일부입니다. MSM_NPU_RECEIVE_EVENT IOCTL이 호출되면 msm_npu_event 구조체가 유저랜드로 복사됩니다.

static int npu_receive_event(struct npu_client *client, unsigned long arg)
{
    ...
	if (list_empty(&client->evt_list)) {
        ...
	} else {
		kevt = list_first_entry(&client->evt_list, struct npu_kevent, list);
		list_del(&kevt->list);
		npu_process_kevent(kevt);
	  /// copy to userland
		ret = copy_to_user(argp, &kevt->evt, sizeof(struct msm_npu_event));
...

유저랜드로 복사되는 msm_npu_event 구조체는 아래 코드에서 각각의 필드가 초기화됩니다.

kevt.evt.type = **MSM_NPU_EVENT_TYPE_EXEC_V2_DONE;**
kevt.evt.u.exec_v2_done.network_hdl = exe_rsp_pkt->network_hdl;
kevt.evt.u.exec_v2_done.exec_result = exe_rsp_pkt->header.status;
kevt.evt.u.exec_v2_done.stats_buf_size = stats_size;
kevt.reserved[0] = (uint64_t)network->stats_buf;
kevt.reserved[1] = (uint64_t)network->stats_buf_u;
if (npu_queue_event(network->client, &kevt))

이 중 msm_npu_event_execute_v2_done 구조체는 20 bytes 크기이며 아래 msm_npu-event 구조체의 union 필드 u에 정의되어 있습니다.

struct msm_npu_event {
	uint32_t type;
	union {
		struct msm_npu_event_execute_done exec_done;
		struct msm_npu_event_execute_v2_done exec_v2_done;
		struct msm_npu_event_ssr ssr;
		uint8_t data[128];
	} u;
	uint32_t reserved[4];
};

msm_npu_event_execute_v2_done 를 초기화하면 u의 나머지 108 bytes (data[128] - sizeof(msm_npu_event_execute_v2_done)) 및 32 bytes 크기의 reserved 필드는 초기화되지 않은 상태로 존재합니다. 따라서 npu_receive_event 함수에서 userland로 복사할 때 sizeof(struct msm_npu_event)로 전체 msm_npu_event 크기만큼 복사하면서 초기화되지 않은 커널 데이터도 같이 복사되고, 이는 커널 주소 유출로 이어질 수 있습니다.