From 39a1e8cceb63e0750c98858ab7a3bf501ffdc1fb Mon Sep 17 00:00:00 2001 From: Trung Date: Mon, 13 Jul 2026 11:00:39 +0700 Subject: [PATCH] Fix owner leakage on partial chown in overlay When a guest performs a partial chown to modify only the group (e.g., chown(path, -1, gid)), the overlay allocates a new entry. However, it previously initialized both `e->uid` and `e->gid` to the physical host's `cur_uid` and `cur_gid`. Since `new_owner` was -1, `e->uid` remained the physical host UID (e.g. 501). When guest later stats the file, the overlay unconditionally applied the physical UID, corrupting guest permissions. Solve this by: 1. Initializing new overlay entries with `(uint32_t)-1` for both fields to indicate "no override". 2. Only applying overrides to `st_uid`/`st_gid` in stat if the fields do not equal the `(uint32_t)-1` sentinel. 3. Checking effective UIDs/GIDs against host values before removing redundant entries. --- src/syscall/chown-overlay.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/syscall/chown-overlay.c b/src/syscall/chown-overlay.c index 18cdcbdf..dd94beb9 100644 --- a/src/syscall/chown-overlay.c +++ b/src/syscall/chown-overlay.c @@ -117,8 +117,8 @@ int chown_overlay_set(uint64_t dev, } e->dev = dev; e->ino = ino; - e->uid = cur_uid; - e->gid = cur_gid; + e->uid = (uint32_t) -1; + e->gid = (uint32_t) -1; unsigned int idx = bucket_index(dev, ino); e->next = buckets[idx]; buckets[idx] = e; @@ -131,7 +131,9 @@ int chown_overlay_set(uint64_t dev, if (new_group != (uint32_t) -1) e->gid = new_group; - if (e->uid == cur_uid && e->gid == cur_gid) + uint32_t effective_uid = e->uid == (uint32_t) -1 ? cur_uid : e->uid; + uint32_t effective_gid = e->gid == (uint32_t) -1 ? cur_gid : e->gid; + if (effective_uid == cur_uid && effective_gid == cur_gid) remove_locked(dev, ino); out: @@ -164,8 +166,10 @@ void chown_overlay_apply(struct stat *st) overlay_entry_t *e = find_locked((uint64_t) st->st_dev, (uint64_t) st->st_ino); if (e) { - st->st_uid = e->uid; - st->st_gid = e->gid; + if (e->uid != (uint32_t) -1) + st->st_uid = e->uid; + if (e->gid != (uint32_t) -1) + st->st_gid = e->gid; } pthread_rwlock_unlock(&overlay_lock);