]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
udf: Allocate name buffer in directory iterator on heap
authorJan Kara <jack@suse.cz>
Tue, 20 Dec 2022 11:38:45 +0000 (12:38 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 17 Nov 2024 14:06:26 +0000 (15:06 +0100)
commit 0aba4860b0d0216a1a300484ff536171894d49d8 upstream.

Currently we allocate name buffer in directory iterators (struct
udf_fileident_iter) on stack. These structures are relatively large
(some 360 bytes on 64-bit architectures). For udf_rename() which needs
to keep three of these structures in parallel the stack usage becomes
rather heavy - 1536 bytes in total. Allocate the name buffer in the
iterator from heap to avoid excessive stack usage.

Link: https://lore.kernel.org/all/202212200558.lK9x1KW0-lkp@intel.com
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
[Add extra include linux/slab.h]
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/udf/directory.c
fs/udf/udfdecl.h

index e97ffae078330119255d03078141e64e32b54c36..a30898debdd183a61fe31fef8acd3a01637edba5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/bio.h>
 #include <linux/crc-itu-t.h>
 #include <linux/iversion.h>
+#include <linux/slab.h>
 
 static int udf_verify_fi(struct udf_fileident_iter *iter)
 {
@@ -248,9 +249,14 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
        iter->elen = 0;
        iter->epos.bh = NULL;
        iter->name = NULL;
+       iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL);
+       if (!iter->namebuf)
+               return -ENOMEM;
 
-       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-               return udf_copy_fi(iter);
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               err = udf_copy_fi(iter);
+               goto out;
+       }
 
        if (inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
                       &iter->eloc, &iter->elen, &iter->loffset) !=
@@ -260,17 +266,17 @@ int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
                udf_err(dir->i_sb,
                        "position %llu not allocated in directory (ino %lu)\n",
                        (unsigned long long)pos, dir->i_ino);
-               return -EFSCORRUPTED;
+               err = -EFSCORRUPTED;
+               goto out;
        }
        err = udf_fiiter_load_bhs(iter);
        if (err < 0)
-               return err;
+               goto out;
        err = udf_copy_fi(iter);
-       if (err < 0) {
+out:
+       if (err < 0)
                udf_fiiter_release(iter);
-               return err;
-       }
-       return 0;
+       return err;
 }
 
 int udf_fiiter_advance(struct udf_fileident_iter *iter)
@@ -307,6 +313,8 @@ void udf_fiiter_release(struct udf_fileident_iter *iter)
        brelse(iter->bh[0]);
        brelse(iter->bh[1]);
        iter->bh[0] = iter->bh[1] = NULL;
+       kfree(iter->namebuf);
+       iter->namebuf = NULL;
 }
 
 static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2,
index f764b4d15094d48b95b5d1306c3dc7bb34b746cf..d35aa42bb577781de2e518fbd03b58b824be7029 100644 (file)
@@ -99,7 +99,7 @@ struct udf_fileident_iter {
        struct extent_position epos;    /* Position after the above extent */
        struct fileIdentDesc fi;        /* Copied directory entry */
        uint8_t *name;                  /* Pointer to entry name */
-       uint8_t namebuf[UDF_NAME_LEN_CS0]; /* Storage for entry name in case
+       uint8_t *namebuf;               /* Storage for entry name in case
                                         * the name is split between two blocks
                                         */
 };