ntfs3: reject direct userspace writes to reserved $LX* xattrs

NTFS3 uses $LXUID, $LXGID, $LXMOD and $LXDEV as internal WSL
permission metadata and reloads them into i_uid, i_gid and i_mode
from ntfs_get_wsl_perm().

Because the empty-prefix xattr handler also lets file owners call
setxattr() on these names directly, an unprivileged writer on a
writable ntfs3 mount can plant root ownership and S_ISUID on their own
file and gain euid 0 after inode reload.

Reject direct userspace writes to the reserved $LX* names. Internal
ntfs3 metadata updates are unchanged because ntfs_save_wsl_perm()
writes them via ntfs_set_ea() directly.

Signed-off-by: Zhen Yan <sdjasjbuaa@gmail.com>
[almaz.alexandrovich@paragon-software.com: added an additional check for non privileged users]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
Konstantin Komarov
2026-06-10 12:31:01 +02:00
parent 5a35454179
commit 5b08dccecf

View File

@@ -851,6 +851,12 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
return err;
}
static bool ntfs_is_reserved_lxattr(const char *name)
{
return !strcmp(name, "$LXUID") || !strcmp(name, "$LXGID") ||
!strcmp(name, "$LXMOD") || !strcmp(name, "$LXDEV");
}
/*
* ntfs_setxattr - inode_operations::setxattr
*/
@@ -957,6 +963,12 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
goto out;
}
/* Do not allow non privileged users to change $LXUID/$LXGID... */
if (ntfs_is_reserved_lxattr(name) && !capable(CAP_SYS_ADMIN)) {
err = -EPERM;
goto out;
}
/* Deal with NTFS extended attribute. */
err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0,
NULL);