ntfs: fix missing kstrdup() error check in ntfs_write_volume_label()

ntfs_write_volume_label() does not check the return value of
kstrdup().  If the allocation fails, vol->volume_label is set to
NULL while the function returns success.  A subsequent
FS_IOC_GETFSLABEL then returns an empty string even though the
on-disk label was updated correctly.

Fix by allocating the new label before taking vol_ni->mrec_lock and
updating any on-disk metadata, so an -ENOMEM from kstrdup() leaves
both the in-memory and on-disk labels untouched and consistent.  On
success the preallocated copy replaces the old vol->volume_label.
Also move mark_inode_dirty_sync() into the success path so that it
is not called when no metadata was actually modified.

Fixes: 6251f0b0de ("ntfs: update super block operations")
Suggested-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Zhan Xusheng 2026-05-08 15:29:34 +08:00 committed by Namjae Jeon
parent 3086c49a07
commit d1aabc2132

View File

@ -413,6 +413,7 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
{
struct ntfs_inode *vol_ni = NTFS_I(vol->vol_ino);
struct ntfs_attr_search_ctx *ctx;
char *new_label;
__le16 *uname;
int uname_len, ret;
@ -425,7 +426,7 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
return uname_len;
}
if (uname_len > NTFS_MAX_LABEL_LEN) {
if (uname_len > NTFS_MAX_LABEL_LEN) {
ntfs_error(vol->sb,
"Volume label is too long (max %d characters).",
NTFS_MAX_LABEL_LEN);
@ -433,11 +434,22 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
return -EINVAL;
}
/*
* Allocate the in-memory label copy up front. If kstrdup() fails we
* bail out before touching on-disk metadata, so the in-memory label
* and the on-disk label stay in sync.
*/
new_label = kstrdup(label, GFP_KERNEL);
if (!new_label) {
kvfree(uname);
return -ENOMEM;
}
mutex_lock(&vol_ni->mrec_lock);
ctx = ntfs_attr_get_search_ctx(vol_ni, NULL);
if (!ctx) {
ret = -ENOMEM;
goto out;
goto out;
}
if (!ntfs_attr_lookup(AT_VOLUME_NAME, NULL, 0, 0, 0, NULL, 0,
@ -450,12 +462,14 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, char *label)
out:
mutex_unlock(&vol_ni->mrec_lock);
kvfree(uname);
mark_inode_dirty_sync(vol->vol_ino);
if (ret >= 0) {
kfree(vol->volume_label);
vol->volume_label = kstrdup(label, GFP_KERNEL);
vol->volume_label = new_label;
mark_inode_dirty_sync(vol->vol_ino);
ret = 0;
} else {
kfree(new_label);
}
return ret;
}