Commit b3e1c785 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull hfs updates from Viacheslav Dubeyko:
 "This contains several fixes of syzbot reported issues, HFS/HFS+ fixes
  of xfstests failures, and rework of HFS/HFS+ debug output subsystem.

   - Kang Chen fixed a slab-out-of-bounds issue in hfsplus_uni2asc()
     when hfsplus_uni2asc() is called from hfsplus_listxattr().

   - Yang Chenzhi fixed a crash in hfsplus_bmap_alloc() if record offset
     or length is larger than node_size.

   - Yangtao Li corrected the error code from hfsplus_fill_super() if
     Catalog File contains corrupted record for the case of hidden
     directory's type.

   - KMSAN uninit-value fixes: hfs_find_set_zero_bits() and
     __hfsplus_ext_cache_extent() use kzalloc() instead of kmalloc(),
     and in hfsplus_delete_cat() by proper initialization of struct
     hfsplus_inode_info in the hfsplus_iget() logic.

   - A slab-out-of-bounds issue could happen in hfsplus_strcasecmp() if
     the length field of struct hfsplus_unistr is bigger than
     HFSPLUS_MAX_STRLEN. Fixed by checking the length of comparing
     strings, and if the strings' length is bigger than
     HFSPLUS_MAX_STRLEN, then the length is corrected to this value.

   - The generic/736 xfstest failed for HFS because the HFS volume
     becomes corrupted after the test run.

     The main reason was the absence of logic that corrects
     mdb->drNxtCNID/HFS_SB(sb)->next_id (next unused CNID) after
     deleting a record in Catalog File. That was fixed by implementing
     the necessary logic in hfs_correct_next_unused_CNID()"

* tag 'hfs-v6.18-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs:
  hfs/hfsplus: rework debug output subsystem
  hfsplus: fix slab-out-of-bounds read in hfsplus_strcasecmp()
  hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc()
  hfs: clear offset and space out of valid records in b-tree node
  hfs: add logic of correcting a next unused CNID
  hfsplus: fix KMSAN uninit-value issue in hfsplus_delete_cat()
  hfs: fix KMSAN uninit-value issue in hfs_find_set_zero_bits()
  hfs: make proper initalization of struct hfs_find_data
  hfsplus: fix KMSAN uninit-value issue in __hfsplus_ext_cache_extent()
  hfs: validate record offset in hfsplus_bmap_alloc
  hfsplus: return EIO when type of hidden directory mismatch in hfsplus_fill_super()
  MAINTAINERS: update location of hfs&hfsplus trees
parents a9401710 f32a26fa
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -10806,8 +10806,10 @@ M: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
M:	Yangtao Li <frank.li@vivo.com>
L:	linux-fsdevel@vger.kernel.org
S:	Maintained
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs.git
F:	Documentation/filesystems/hfs.rst
F:	fs/hfs/
F:	include/linux/hfs_common.h
HFSPLUS FILESYSTEM
M:	Viacheslav Dubeyko <slava@dubeyko.com>
@@ -10815,8 +10817,10 @@ M: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
M:	Yangtao Li <frank.li@vivo.com>
L:	linux-fsdevel@vger.kernel.org
S:	Maintained
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs.git
F:	Documentation/filesystems/hfsplus.rst
F:	fs/hfsplus/
F:	include/linux/hfs_common.h
HGA FRAMEBUFFER DRIVER
M:	Ferenc Bakonyi <fero@drama.obuda.kando.hu>
+9 −3
Original line number Diff line number Diff line
@@ -21,12 +21,12 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)

	fd->tree = tree;
	fd->bnode = NULL;
	ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
	ptr = kzalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
	if (!ptr)
		return -ENOMEM;
	fd->search_key = ptr;
	fd->key = ptr + tree->max_key_len + 2;
	hfs_dbg(BNODE_REFS, "find_init: %d (%p)\n",
	hfs_dbg("cnid %d, caller %ps\n",
		tree->cnid, __builtin_return_address(0));
	switch (tree->cnid) {
	case HFS_CAT_CNID:
@@ -48,7 +48,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
{
	hfs_bnode_put(fd->bnode);
	kfree(fd->search_key);
	hfs_dbg(BNODE_REFS, "find_exit: %d (%p)\n",
	hfs_dbg("cnid %d, caller %ps\n",
		fd->tree->cnid, __builtin_return_address(0));
	mutex_unlock(&fd->tree->tree_lock);
	fd->tree = NULL;
@@ -115,6 +115,12 @@ int hfs_brec_find(struct hfs_find_data *fd)
	__be32 data;
	int height, res;

	fd->record = -1;
	fd->keyoffset = -1;
	fd->keylength = -1;
	fd->entryoffset = -1;
	fd->entrylength = -1;

	tree = fd->tree;
	if (fd->bnode)
		hfs_bnode_put(fd->bnode);
+2 −2
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits)
		}
	}

	hfs_dbg(BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
	hfs_dbg("pos %u, num_bits %u\n", pos, *num_bits);
	HFS_SB(sb)->free_ablocks -= *num_bits;
	hfs_bitmap_dirty(sb);
out:
@@ -200,7 +200,7 @@ int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count)
	if (!count)
		return 0;

	hfs_dbg(BITMAP, "clear_bits: %u,%u\n", start, count);
	hfs_dbg("start %u, count %u\n", start, count);
	/* are all of the bits in range? */
	if ((start + count) > HFS_SB(sb)->fs_ablocks)
		return -2;
+14 −14
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
{
	struct page *src_page, *dst_page;

	hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
	hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
	if (!len)
		return;

@@ -221,7 +221,7 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
	struct page *page;
	void *ptr;

	hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
	hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
	if (!len)
		return;

@@ -243,16 +243,16 @@ void hfs_bnode_dump(struct hfs_bnode *node)
	__be32 cnid;
	int i, off, key_off;

	hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
	hfs_dbg("node %d\n", node->this);
	hfs_bnode_read(node, &desc, 0, sizeof(desc));
	hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
	hfs_dbg("next %d, prev %d, type %d, height %d, num_recs %d\n",
		be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
		desc.type, desc.height, be16_to_cpu(desc.num_recs));

	off = node->tree->node_size - 2;
	for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
		key_off = hfs_bnode_read_u16(node, off);
		hfs_dbg_cont(BNODE_MOD, " %d", key_off);
		hfs_dbg(" key_off %d", key_off);
		if (i && node->type == HFS_NODE_INDEX) {
			int tmp;

@@ -260,18 +260,18 @@ void hfs_bnode_dump(struct hfs_bnode *node)
				tmp = (hfs_bnode_read_u8(node, key_off) | 1) + 1;
			else
				tmp = node->tree->max_key_len + 1;
			hfs_dbg_cont(BNODE_MOD, " (%d,%d",
			hfs_dbg(" (%d,%d",
				tmp, hfs_bnode_read_u8(node, key_off));
			hfs_bnode_read(node, &cnid, key_off + tmp, 4);
			hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
			hfs_dbg(", cnid %d)", be32_to_cpu(cnid));
		} else if (i && node->type == HFS_NODE_LEAF) {
			int tmp;

			tmp = hfs_bnode_read_u8(node, key_off);
			hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
			hfs_dbg(" (%d)", tmp);
		}
	}
	hfs_dbg_cont(BNODE_MOD, "\n");
	hfs_dbg("\n");
}

void hfs_bnode_unlink(struct hfs_bnode *node)
@@ -361,7 +361,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
	node->this = cnid;
	set_bit(HFS_BNODE_NEW, &node->flags);
	atomic_set(&node->refcnt, 1);
	hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
	hfs_dbg("cnid %d, node %d, refcnt 1\n",
		node->tree->cnid, node->this);
	init_waitqueue_head(&node->lock_wq);
	spin_lock(&tree->hash_lock);
@@ -401,7 +401,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
{
	struct hfs_bnode **p;

	hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
	hfs_dbg("cnid %d, node %d, refcnt %d\n",
		node->tree->cnid, node->this, atomic_read(&node->refcnt));
	for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
	     *p && *p != node; p = &(*p)->next_hash)
@@ -546,7 +546,7 @@ void hfs_bnode_get(struct hfs_bnode *node)
{
	if (node) {
		atomic_inc(&node->refcnt);
		hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
		hfs_dbg("cnid %d, node %d, refcnt %d\n",
			node->tree->cnid, node->this,
			atomic_read(&node->refcnt));
	}
@@ -559,7 +559,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
		struct hfs_btree *tree = node->tree;
		int i;

		hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
		hfs_dbg("cnid %d, node %d, refcnt %d\n",
			node->tree->cnid, node->this,
			atomic_read(&node->refcnt));
		BUG_ON(!atomic_read(&node->refcnt));
+27 −8
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
	end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
	end_off = hfs_bnode_read_u16(node, end_rec_off);
	end_rec_off -= 2;
	hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
	hfs_dbg("rec %d, size %d, end_off %d, end_rec_off %d\n",
		rec, size, end_off, end_rec_off);
	if (size > end_rec_off - end_off) {
		if (new_node)
@@ -179,6 +179,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
	struct hfs_btree *tree;
	struct hfs_bnode *node, *parent;
	int end_off, rec_off, data_off, size;
	int src, dst, len;

	tree = fd->tree;
	node = fd->bnode;
@@ -191,7 +192,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
		mark_inode_dirty(tree->inode);
	}
	hfs_bnode_dump(node);
	hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
	hfs_dbg("rec %d, len %d\n",
		fd->record, fd->keylength + fd->entrylength);
	if (!--node->num_recs) {
		hfs_bnode_unlink(node);
@@ -208,10 +209,14 @@ int hfs_brec_remove(struct hfs_find_data *fd)
	}
	hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);

	if (rec_off == end_off)
		goto skip;
	size = fd->keylength + fd->entrylength;

	if (rec_off == end_off) {
		src = fd->keyoffset;
		hfs_bnode_clear(node, src, size);
		goto skip;
	}

	do {
		data_off = hfs_bnode_read_u16(node, rec_off);
		hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
@@ -219,9 +224,23 @@ int hfs_brec_remove(struct hfs_find_data *fd)
	} while (rec_off >= end_off);

	/* fill hole */
	hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
		       data_off - fd->keyoffset - size);
	dst = fd->keyoffset;
	src = fd->keyoffset + size;
	len = data_off - src;

	hfs_bnode_move(node, dst, src, len);

	src = dst + len;
	len = data_off - src;

	hfs_bnode_clear(node, src, len);

skip:
	/*
	 * Remove the obsolete offset to free space.
	 */
	hfs_bnode_write_u16(node, end_off, 0);

	hfs_bnode_dump(node);
	if (!fd->record)
		hfs_brec_update_parent(fd);
@@ -242,7 +261,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
	if (IS_ERR(new_node))
		return new_node;
	hfs_bnode_get(node);
	hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
	hfs_dbg("this %d, new %d, next %d\n",
		node->this, new_node->this, node->next);
	new_node->next = node->next;
	new_node->prev = node->this;
@@ -378,7 +397,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
		newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
	else
		fd->keylength = newkeylen = tree->max_key_len + 1;
	hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
	hfs_dbg("rec %d, keylength %d, newkeylen %d\n",
		rec, fd->keylength, newkeylen);

	rec_off = tree->node_size - (rec + 2) * 2;
Loading