리눅스 커널(Linux Kernel) 관련 일을 하다 보니 가끔씩 보안 패치를 보내기도 하는데요, 메일링 리스트에 패치를 보낼 때마다 리뷰어(Reviewer)며 메인테이너(Maintainer)며 기타 구경꾼들까지 달려들어서 코드를 검토해주는 바람에 거절되는 경우도 많이 있습니다. 특히 최근에는 AMD사의 펌웨어 TPM(fTPM) 관련 패치가 수십 번의 핑퐁 끝에 거절당해서 트라우마까지 생겼거든요. ㅠㅠ 그런데 그런 일보다 더 황당한 일이 있었네요. @0@a..
미네소타 대학에서 논문(On the Feasibility of Stealthily Introducing Vulnerabilities in Open-Source Software via Hypocrite Commits)을 쓰기 위해 보안 취약점이 들어있는 패치를 여러 번에 걸쳐서 메일링 리스트에 보냈고, 그중에 일부는 이미 안정 버전(Stable)에까지 반영이 되어서 급히 제거했다고 합니다. 리눅스 커널은 이미 IoT 장비부터 서버, 우주선에까지 사용되고 있기 때문에 파급효과가 엄청난데... 아무리 논문 욕심이 있었다고 해도 선을 넘은 것 같네요. 메일링 리스트를 보면 너무 길고 양이 많기 때문에, 전체 이야기에 관심이 있다면 ZDNet 기사(Greg Kroah-Hartman bans University of Minnesota from Linux development for deliberately buggy patches)를 보시는 것이 좋을 것 같습니다. ^^;;;
과연 얼마나 정교하게 패치를 보냈길래 제대로 검증이 되지 않았나 몇 개를 살펴봤는데요, 꽤나 별 것 아닌 것처럼 보냈습니다. 성공적으로 병합(Merge)된 패치(https://lore.kernel.org/lkml/20210407000913.2207831-1-pakki001@umn.edu/)를 하나 보면 아래와 같습니다.
From: Aditya Pakki <pakki001@umn.edu>
To: pakki001@umn.edu
Cc: Santosh Shilimkar <santosh.shilimkar@oracle.com>,
"David S. Miller" <davem@davemloft.net>,
Jakub Kicinski <kuba@kernel.org>,
netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
rds-devel@oss.oracle.com, linux-kernel@vger.kernel.org
Subject: [PATCH] net/rds: Avoid potential use after free in rds_send_remove_from_sock
Date: Tue, 6 Apr 2021 19:09:12 -0500
Message-ID: <20210407000913.2207831-1-pakki001@umn.edu> (raw)
In case of rs failure in rds_send_remove_from_sock(), the 'rm' resource
is freed and later under spinlock, causing potential use-after-free.
Set the free pointer to NULL to avoid undefined behavior.
Signed-off-by: Aditya Pakki <pakki001@umn.edu>
---
net/rds/message.c | 1 +
net/rds/send.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/rds/message.c b/net/rds/message.c
index 071a261fdaab..90ebcfe5fe3b 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -180,6 +180,7 @@ void rds_message_put(struct rds_message *rm)
rds_message_purge(rm);
kfree(rm);
+ rm = NULL;
}
}
EXPORT_SYMBOL_GPL(rds_message_put);
diff --git a/net/rds/send.c b/net/rds/send.c
index 985d0b7713ac..fe5264b9d4b3 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -665,7 +665,7 @@ static void rds_send_remove_from_sock(struct list_head *messages, int status)
unlock_and_drop:
spin_unlock_irqrestore(&rm->m_rs_lock, flags);
rds_message_put(rm);
- if (was_on_sock)
+ if (was_on_sock && rm)
rds_message_put(rm);
}
--
2.25.1
위의 내용을 보면 기존 소스가 메모리 해제 후 재사용(Use After Free, UAF) 문제가 있어서 이를 수정한다는 내용입니다. 그런데 실제 패치에 추가된 내용을 보시면, rds_message_put() 함수에서 rm = NULL;을 추가해서 rm이라는 변수에 NULL을 넣고 난 다음, rds_send_remove_from_sock() 함수에서 if 문에 rm 변수가 NULL이 아닌 것을 검사하게 만들었습니다. 사실 rm이라는 변수는 rds_send_remove_from_sock() 함수에 있는 지역변수인데요, 이 지역변수를 다른 함수에서 넘겨받아 값을 NULL로 바꿨지만 사실 눈속임에 불과합니다. 즉 쓸모없는 수정이라는 말입니다.
조금 어려운 이야기인데... 다른 함수에서 rm에 NULL을 넣으려면 rm 자체가 일단 싱글 포인터(Single Pointer)이기 때문에 더블 포인터(Double Pointer)로 rm 변수의 주소 값을 넘겨야 하거든요(포인터는 항상 어렵습니다 ㅠㅠ). 리눅스 커널 개발자들은 위에서 보시는 것처럼 패치 형태로 전달하는데요, 패치는 수정된 코드의 위아래 일부분만 보여주기 때문에 자칫 잘못하면 실수를 할 수 있습니다. 이런 부분을 노리고 리뷰가 얼마나 잘되는지를 판단하려고 저런 패치를 보냈다고 생각하니, 의도가 얼마나 불순했는지를 알 수 있습니다. 그래도 이런 패치는 양반입니다. 아무런 영향을 미치지 않으니까요.
그럼 이제 문제의 패치를 보겠습니다. 실제로 보안 문제를 일으키는 패치인데요, 심지어 가명으로 만든 계정으로 보낸 걸로 추측됩니다. 왜냐하면 제임스 본드(James Bond)거든요. ^^;;; 쿨럭..;;; 다행히도 이 패치(https://lore.kernel.org/lkml/20200821070537.30317-1-jameslouisebond@gmail.com/)는 거절되었습니다.
From: James Bond <jameslouisebond@gmail.com>
To: jameslouisebond@gmail.com
Cc: Miquel Raynal <miquel.raynal@bootlin.com>,
Richard Weinberger <richard@nod.at>,
Vignesh Raghavendra <vigneshr@ti.com>,
Arnd Bergmann <arnd@arndb.de>, Ryan Jackson <rjackson@lnxi.com>,
David Woodhouse <dwmw2@infradead.org>,
linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org
Subject: [PATCH] mtd: ck804xrom: fix missing pci device put in error paths
Date: Fri, 21 Aug 2020 02:05:36 -0500
Message-ID: <20200821070537.30317-1-jameslouisebond@gmail.com> (raw)
pci_dev_get increases the refcount of "pdev".
In the error paths, pci_dev_put should be called
to handle the "pdev" and decrease the corresponding refcount.
Fixes: 90afffc8bd79 ("[MTD] [MAPS] Support for BIOS flash chips on the nvidia ck804 southbridge")
Signed-off-by: James Bond <jameslouisebond@gmail.com>
---
drivers/mtd/maps/ck804xrom.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 460494212f6a..16af8b5ee653 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -195,6 +195,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
if (!window->virt) {
printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
window->phys, window->size);
+ pci_dev_put(pdev);
goto out;
}
@@ -222,6 +223,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
if (!map) {
printk(KERN_ERR MOD_NAME ": kmalloc failed");
+ pci_dev_put(pdev);
goto out;
}
memset(map, 0, sizeof(*map));
@@ -295,6 +297,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
if (mtd_device_register(map->mtd, NULL, 0)) {
map_destroy(map->mtd);
map->mtd = NULL;
+ pci_dev_put(pdev);
goto out;
}
--
2.17.1
위의 패치를 보시면 매번 goto out 예외 처리 루틴으로 넘어가기 전에 pci_dev_put(pdev)를 호출하는 부분을 추가했습니다. 위의 패치 코드만 보면 추가된 부분이 필요할 것같은 느낌이 듭니다. 하지만, 실제로 goto out 부분을 보면 아래처럼 ck804xrom_cleanup(window)를 부르고 그 내부에서 pci_dev_put(pdev)를 다시 호출합니다. 따라서, 제임스 본드(ㅡ_ㅡ;;;)가 보낸 패치를 넣게 되면 pci_dev_put(pdev)를 두 번 호출하게 되고, 보안 취약점 중에 하나인 중복 해제(Double Free) 버그가 생깁니다. 쉽게 말씀드리면, 같은 메모리를 두 번이나 해제해서 malloc/free에 사용하는 힙(Heap) 영역이 꼬이고, 악의적인 사용자가 이를 이용하면 다양한 문제가 발생합니다.
out:
/* Free any left over map structures */
kfree(map);
/* See if I have any map structures */
if (list_empty(&window->maps)) {
ck804xrom_cleanup(window);
return -ENODEV;
}
return 0;
}
이런 류의 패치 시도가 다양하게 있었던 것 같은데... 정말 대단한 집념인 것 같습니다. 그 와중에 해명(https://lore.kernel.org/linux-nfs/YH%2FfM%2FTsbmcZzwnX@kroah.com/)을 하기는 했는데, 자기는 정적 분석 도구(Static Analysis Tool)가 알려주는 대로 수정해서 패치를 보냈다고 하더라구요. 이미 아시는 분도 계시겠지만, 정적 분석 도구가 저런 리포트를 만들어냈다고 보기는 좀 어려울 것 같고, 다분히 사람이 악의적인 의도를 가지고 만들었다고 판단하는 게 옳을 것 같네요. ^^;;;
정말 세상에 별일이 다 있네요. 제가 쓰는 소프트웨어에 더 주의를 기울여야겠습니다.
그럼 즐거운 밤 되세요 >ㅁ<)/~
'프로그래밍(Programming) > 리눅스(Linux)' 카테고리의 다른 글
리눅스 커널 다시 컴파일 후 그래픽 모드 전환 오류 해결 방법 (0) | 2021.03.28 |
---|---|
리눅스 커널 모듈(Linux kernel module) 설치 시 모듈 사이즈 줄이기 (0) | 2021.03.26 |
오라클 버추어박스(Oracle Virtualbox) 빌드하기 (2) | 2021.01.14 |
데비안(Debian) 리눅스에서 파이썬 pip 도구 설치하기 (0) | 2021.01.12 |
i3wm 윈도우 매니저에서 배경 이미지 설정하기 (0) | 2021.01.07 |