
Local privilege escalation exploit for CVE-2023-0386 targeting Linux kernel overlayfs. Includes detailed vulnerability analysis, PoC code, and step-by-step exploitation guide using FUSE and user namespaces.
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

The theoretical knowledge in this article (namespaces, overlay filesystem, fuse filesystem, etc.) comes from ChatGPT.
Vulnerability ID: CVE-2023-0386
Vulnerable Product: Linux kernel - overlay filesystem
Affected Versions: 5.11 ~ 5.19
Exploit Condition: Ability to unshare or create an overlay filesystem
Exploit Effect: Local privilege escalation
Compile the kernel yourself:
Prepare a kernel within the affected version range, outside 5.15 (5.15 seems problematic), enable overlay and fuse filesystems:
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS
Ubuntu 21.10 kernel version 5.13.0-16-generic tested and works:

Before analyzing the vulnerability, let's ask ChatGPT to role-play as a Linux kernel expert:
(Asking ChatGPT: Now you will play the role of a Linux kernel expert to help me answer some questions)
Public information about the vulnerability is scarce; the most direct source is the patch information. Patch link below:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a

It can be seen that a new check was added in the ovl_copy_up_one function. Let's first ask ChatGPT what this function does:

So this function is involved in copying a lower layer file of the overlay filesystem to the upper layer. Now, let's examine the new check added by the patch in context:
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] Get the stat of the underlying filesystem
STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
if (err)
return err;
//[2] The patch adds a check to see if the user ID and group ID from the file's stat are mapped in the current namespace
if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
!kgid_has_mapping(current_user_ns(), ctx.stat.gid))
return -EOVERFLOW;
[1] First, the vfs_getattr function retrieves the attributes of the target file on the underlying filesystem. vfs_getattr obtains the struct stat for a file by passing its struct path.
[1.1] ctx.lowerpath is the path to a file on the lower filesystem of the overlay filesystem. The overlay filesystem will be introduced later.
[1.2] struct stat holds file metadata, including the file's owner and group. The owner information obtained here will be checked by the patch's new condition.
[2] Then, the kuid_has_mapping function is called to check the owner and group information just obtained. It determines whether the file's owner and group are mapped in the current user namespace.
[2.1] kuid_has_mapping takes two parameters: a struct user_namespace structure and a struct kuid kernel user structure. This function checks whether the given user information is mapped in the given user namespace. User mapping in namespaces will be detailed later.
So we know that when the vulnerable function (ovl_copy_up_one) is executed, if the owner user or group of the target lower file is not mapped in the current namespace, the operation fails.
Thus the patch principle is clear. However, we still need to solve the following questions to reproduce this vulnerability:
ovl_copy_up_one resides — that is, copying a lower layer file to the upper layer in the overlay filesystem?lowerpath, whose owner is checked, play in the above chain?Before answering these questions, we need to understand some basic knowledge:
(Asking ChatGPT: Please introduce namespaces in the Linux kernel)
In Linux, namespaces are a kernel feature used to achieve resource isolation. By using namespaces, a group of processes can appear to run in an independent system environment, improving security and manageability. Namespaces play a key role in container technology (e.g., Docker), allowing containers to run in isolation without affecting other containers or the host system.
The Linux kernel supports 7 types of namespaces (mount, pid, net, ipc, user, time, cgroup), each isolating a specific type of system resource. Namespaces are created, modified, and managed via system calls such as clone, unshare, and setns. Container runtimes (like Docker) and other virtualization tools use these namespace features to provide independent, isolated running environments for containers.
The check function kuid_has_mapping added in the vulnerability patch involves the user namespace among the seven namespaces.
(Asking ChatGPT: Please introduce user namespaces)
User namespaces isolate user IDs (UID) and group IDs (GID). Through user namespaces, independent sets of user and group IDs can be used in different namespaces. This means that a user or group in one user namespace may have a different ID or different privileges in another namespace. User namespaces improve system security and manageability, especially in container environments.
The key feature of user namespaces is ID mapping: User namespaces allow mapping UIDs and GIDs from one namespace to UIDs and GIDs in another namespace. This means that the same UID and GID could represent different users and groups in different user namespaces. For example, a root user (UID 0) in a container may be mapped to an unprivileged user on the host system.
We only need to remember the following points:
For example, if user "breeze" creates a new user namespace, and then checks a file owned by root in the initial namespace, the file's owner will be shown as nobody in the new namespace:

This is because in the new namespace, root is the user "breeze" who created it, and the root from the initial namespace was not manually mapped, so it is recognized as nobody.
So now we understand the significance of the patch: For a file being copied from the overlay lower filesystem, the operation only continues if its owner (group) is mapped in the current namespace. Otherwise, an error is returned. That is, situations where the owner is recognized as nobody will cause the copy to fail.
(Asking ChatGPT: Please introduce the overlay filesystem in Linux)