Commit 763dede1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs

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()
parents 762a9f2f 3676f32a
...@@ -39,6 +39,13 @@ static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root) ...@@ -39,6 +39,13 @@ static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root)
return victim; 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. * return_unused_pool_pebs - returns unused PEB to the free tree.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -52,8 +59,7 @@ static void return_unused_pool_pebs(struct ubi_device *ubi, ...@@ -52,8 +59,7 @@ static void return_unused_pool_pebs(struct ubi_device *ubi,
for (i = pool->used; i < pool->size; i++) { for (i = pool->used; i < pool->size; i++) {
e = ubi->lookuptbl[pool->pebs[i]]; e = ubi->lookuptbl[pool->pebs[i]];
wl_tree_add(e, &ubi->free); return_unused_peb(ubi, e);
ubi->free_count++;
} }
} }
...@@ -361,6 +367,11 @@ static void ubi_fastmap_close(struct ubi_device *ubi) ...@@ -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_pool);
return_unused_pool_pebs(ubi, &ubi->fm_wl_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) { if (ubi->fm) {
for (i = 0; i < ubi->fm->used_blocks; i++) for (i = 0; i < ubi->fm->used_blocks; i++)
kfree(ubi->fm->e[i]); kfree(ubi->fm->e[i]);
......
...@@ -498,6 +498,6 @@ struct ubi_fm_volhdr { ...@@ -498,6 +498,6 @@ struct ubi_fm_volhdr {
struct ubi_fm_eba { struct ubi_fm_eba {
__be32 magic; __be32 magic;
__be32 reserved_pebs; __be32 reserved_pebs;
__be32 pnum[0]; __be32 pnum[];
} __packed; } __packed;
#endif /* !__UBI_MEDIA_H__ */ #endif /* !__UBI_MEDIA_H__ */
...@@ -1875,7 +1875,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ...@@ -1875,7 +1875,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
goto out_free; goto out_free;
#ifdef CONFIG_MTD_UBI_FASTMAP #ifdef CONFIG_MTD_UBI_FASTMAP
ubi_ensure_anchor_pebs(ubi); if (!ubi->ro_mode && !ubi->fm_disabled)
ubi_ensure_anchor_pebs(ubi);
#endif #endif
return 0; return 0;
......
...@@ -225,7 +225,7 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum) ...@@ -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 ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
int offs, int quiet, int must_chk_crc) 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; uint32_t crc, node_crc, magic;
const struct ubifs_ch *ch = buf; const struct ubifs_ch *ch = buf;
...@@ -278,10 +278,22 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, ...@@ -278,10 +278,22 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
out_len: out_len:
if (!quiet) if (!quiet)
ubifs_err(c, "bad node length %d", node_len); ubifs_err(c, "bad node length %d", node_len);
if (type == UBIFS_DATA_NODE && node_len > UBIFS_DATA_NODE_SZ)
dump_node = 0;
out: out:
if (!quiet) { if (!quiet) {
ubifs_err(c, "bad node at LEB %d:%d", lnum, offs); 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(); dump_stack();
} }
return err; return err;
......
...@@ -905,6 +905,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -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", ubifs_err(c, "dead directory entry '%s', error %d",
xent->name, err); xent->name, err);
ubifs_ro_mode(c, err); ubifs_ro_mode(c, err);
kfree(xent);
goto out_release; goto out_release;
} }
ubifs_assert(c, ubifs_inode(xino)->xattr); ubifs_assert(c, ubifs_inode(xino)->xattr);
......
...@@ -157,7 +157,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ...@@ -157,7 +157,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
int err = 0; int err = 0;
ino_t xattr_inum; ino_t xattr_inum;
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent, *pxent = NULL;
struct fscrypt_name nm = {0}; struct fscrypt_name nm = {0};
struct ubifs_orphan *xattr_orphan; struct ubifs_orphan *xattr_orphan;
struct ubifs_orphan *orphan; struct ubifs_orphan *orphan;
...@@ -181,11 +181,16 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ...@@ -181,11 +181,16 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
xattr_inum = le64_to_cpu(xent->inum); xattr_inum = le64_to_cpu(xent->inum);
xattr_orphan = orphan_add(c, xattr_inum, orphan); 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); return PTR_ERR(xattr_orphan);
}
kfree(pxent);
pxent = xent;
key_read(c, &xent->key, &key); key_read(c, &xent->key, &key);
} }
kfree(pxent);
return 0; return 0;
} }
...@@ -688,14 +693,14 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -688,14 +693,14 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ino_key_init(c, &key1, inum); ino_key_init(c, &key1, inum);
err = ubifs_tnc_lookup(c, &key1, ino); err = ubifs_tnc_lookup(c, &key1, ino);
if (err) if (err && err != -ENOENT)
goto out_free; goto out_free;
/* /*
* Check whether an inode can really get deleted. * Check whether an inode can really get deleted.
* linkat() with O_TMPFILE allows rebirth of an inode. * 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", dbg_rcvry("deleting orphaned inode %lu",
(unsigned long)inum); (unsigned long)inum);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment