]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ntfs: fix missing kstrdup() error check in ntfs_write_volume_label()
authorZhan Xusheng <zhanxusheng@xiaomi.com>
Fri, 8 May 2026 07:29:34 +0000 (15:29 +0800)
committerNamjae Jeon <linkinjeon@kernel.org>
Sat, 9 May 2026 03:12:59 +0000 (12:12 +0900)
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: 6251f0b0de7d ("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>
fs/ntfs/super.c

index e9de84fb82973f003669b8e8ba59ab3e2d96b39e..d282cf6e712e7762cab3ed787b47173eb8cab6de 100644 (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;
 }