Merge tag 'for-linus-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 Apr 2020 19:40:56 +0000 (12:40 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 Apr 2020 19:40:56 +0000 (12:40 -0700)
Pull UBI and UBIFS updates from Richard Weinberger:

 - Fix for memory leaks around UBIFS orphan handling

 - Fix for memory leaks around UBI fastmap

 - Remove zero-length array from ubi-media.h

 - Fix for TNC lookup in UBIFS orphan code

* tag 'for-linus-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
  ubi: ubi-media.h: Replace zero-length array with flexible-array member
  ubifs: Fix out-of-bounds memory access caused by abnormal value of node_len
  ubi: fastmap: Only produce the initial anchor PEB when fastmap is used
  ubi: fastmap: Free unused fastmap anchor peb during detach
  ubifs: ubifs_add_orphan: Fix a memory leak bug
  ubifs: ubifs_jnl_write_inode: Fix a memory leak bug
  ubifs: Fix ubifs_tnc_lookup() usage in do_kill_orphans()

drivers/mtd/ubi/fastmap-wl.c
drivers/mtd/ubi/ubi-media.h
drivers/mtd/ubi/wl.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/orphan.c

index 426820a..b486250 100644 (file)
@@ -39,6 +39,13 @@ static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root)
        return victim;
 }
 
+static inline void return_unused_peb(struct ubi_device *ubi,
+                                    struct ubi_wl_entry *e)
+{
+       wl_tree_add(e, &ubi->free);
+       ubi->free_count++;
+}
+
 /**
  * return_unused_pool_pebs - returns unused PEB to the free tree.
  * @ubi: UBI device description object
@@ -52,8 +59,7 @@ static void return_unused_pool_pebs(struct ubi_device *ubi,
 
        for (i = pool->used; i < pool->size; i++) {
                e = ubi->lookuptbl[pool->pebs[i]];
-               wl_tree_add(e, &ubi->free);
-               ubi->free_count++;
+               return_unused_peb(ubi, e);
        }
 }
 
@@ -361,6 +367,11 @@ static void ubi_fastmap_close(struct ubi_device *ubi)
        return_unused_pool_pebs(ubi, &ubi->fm_pool);
        return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
 
+       if (ubi->fm_anchor) {
+               return_unused_peb(ubi, ubi->fm_anchor);
+               ubi->fm_anchor = NULL;
+       }
+
        if (ubi->fm) {
                for (i = 0; i < ubi->fm->used_blocks; i++)
                        kfree(ubi->fm->e[i]);
index b5fe8f8..386db05 100644 (file)
@@ -498,6 +498,6 @@ struct ubi_fm_volhdr {
 struct ubi_fm_eba {
        __be32 magic;
        __be32 reserved_pebs;
-       __be32 pnum[0];
+       __be32 pnum[];
 } __packed;
 #endif /* !__UBI_MEDIA_H__ */
index 837d690..5146cce 100644 (file)
@@ -1875,7 +1875,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
                goto out_free;
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
-       ubi_ensure_anchor_pebs(ubi);
+       if (!ubi->ro_mode && !ubi->fm_disabled)
+               ubi_ensure_anchor_pebs(ubi);
 #endif
        return 0;
 
index 8ceb514..7e4bfaf 100644 (file)
@@ -225,7 +225,7 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
 int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
                     int offs, int quiet, int must_chk_crc)
 {
-       int err = -EINVAL, type, node_len;
+       int err = -EINVAL, type, node_len, dump_node = 1;
        uint32_t crc, node_crc, magic;
        const struct ubifs_ch *ch = buf;
 
@@ -278,10 +278,22 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
 out_len:
        if (!quiet)
                ubifs_err(c, "bad node length %d", node_len);
+       if (type == UBIFS_DATA_NODE && node_len > UBIFS_DATA_NODE_SZ)
+               dump_node = 0;
 out:
        if (!quiet) {
                ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
-               ubifs_dump_node(c, buf);
+               if (dump_node) {
+                       ubifs_dump_node(c, buf);
+               } else {
+                       int safe_len = min3(node_len, c->leb_size - offs,
+                               (int)UBIFS_MAX_DATA_NODE_SZ);
+                       pr_err("\tprevent out-of-bounds memory access\n");
+                       pr_err("\ttruncated data node length      %d\n", safe_len);
+                       pr_err("\tcorrupted data node:\n");
+                       print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+                                       buf, safe_len, 0);
+               }
                dump_stack();
        }
        return err;
index 3bf8b1f..e5ec1af 100644 (file)
@@ -905,6 +905,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
                                ubifs_err(c, "dead directory entry '%s', error %d",
                                          xent->name, err);
                                ubifs_ro_mode(c, err);
+                               kfree(xent);
                                goto out_release;
                        }
                        ubifs_assert(c, ubifs_inode(xino)->xattr);
index edf43dd..283f9eb 100644 (file)
@@ -157,7 +157,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
        int err = 0;
        ino_t xattr_inum;
        union ubifs_key key;
-       struct ubifs_dent_node *xent;
+       struct ubifs_dent_node *xent, *pxent = NULL;
        struct fscrypt_name nm = {0};
        struct ubifs_orphan *xattr_orphan;
        struct ubifs_orphan *orphan;
@@ -181,11 +181,16 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
                xattr_inum = le64_to_cpu(xent->inum);
 
                xattr_orphan = orphan_add(c, xattr_inum, orphan);
-               if (IS_ERR(xattr_orphan))
+               if (IS_ERR(xattr_orphan)) {
+                       kfree(xent);
                        return PTR_ERR(xattr_orphan);
+               }
 
+               kfree(pxent);
+               pxent = xent;
                key_read(c, &xent->key, &key);
        }
+       kfree(pxent);
 
        return 0;
 }
@@ -688,14 +693,14 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 
                        ino_key_init(c, &key1, inum);
                        err = ubifs_tnc_lookup(c, &key1, ino);
-                       if (err)
+                       if (err && err != -ENOENT)
                                goto out_free;
 
                        /*
                         * Check whether an inode can really get deleted.
                         * linkat() with O_TMPFILE allows rebirth of an inode.
                         */
-                       if (ino->nlink == 0) {
+                       if (err == 0 && ino->nlink == 0) {
                                dbg_rcvry("deleting orphaned inode %lu",
                                          (unsigned long)inum);