Commit ca010e2e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull hfs/hfsplus updates from Viacheslav Dubeyko:
 "Several fixes for syzbot reported issues, HFS/HFS+ fixes of xfstests
  failures, Kunit-based unit-tests introduction, and code cleanup:

   - Dan Carpenter fixed a potential use-after-free issue in
     hfs_correct_next_unused_CNID() method. Tetsuo Handa has made nice
     fix of syzbot reported issue related to incorrect inode->i_mode
     management if volume has been corrupted somehow. Yang Chenzhi has
     made really good fix of potential race condition in
     __hfs_bnode_create() method for HFS+ file system.

   - Several fixes to xfstests failures. Particularly, generic/070,
     generic/073, and generic/101 test-cases finish successfully for the
     case of HFS+ file system right now.

   - HFS and HFS+ drivers share multiple structures of on-disk layout
     declarations. Some structures are used without any change. However,
     we had two independent declarations of the same structures in HFS
     and HFS+ drivers.

     The on-disk layout declarations have been moved into
     include/linux/hfs_common.h with the goal to exclude the
     declarations duplication and to keep the HFS/HFS+ on-disk layout
     declarations in one place.

     Also, this patch prepares the basis for creating a hfslib that can
     aggregate common functionality without necessity to duplicate the
     same code in HFS and HFS+ drivers.

   - HFS/HFS+ really need unit-tests because of multiple xfstests
     failures. The first two patches introduce Kunit-based unit-tests
     for the case string operations in HFS/HFS+ file system drivers"

* tag 'hfs-v6.19-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs:
  hfs/hfsplus: move on-disk layout declarations into hfs_common.h
  hfsplus: fix volume corruption issue for generic/101
  hfsplus: introduce KUnit tests for HFS+ string operations
  hfs: introduce KUnit tests for HFS string operations
  hfsplus: fix volume corruption issue for generic/073
  hfsplus: Verify inode mode when loading from disk
  hfsplus: fix volume corruption issue for generic/070
  hfs/hfsplus: prevent getting negative values of offset/length
  hfsplus: fix missing hfs_bnode_get() in __hfs_bnode_create
  hfs: fix potential use after free in hfs_correct_next_unused_CNID()
parents 76962860 ec95cd10
Loading
Loading
Loading
Loading

fs/hfs/.kunitconfig

0 → 100644
+7 −0
Original line number Diff line number Diff line
CONFIG_KUNIT=y
CONFIG_HFS_FS=y
CONFIG_HFS_KUNIT_TEST=y
CONFIG_BLOCK=y
CONFIG_BUFFER_HEAD=y
CONFIG_NLS=y
CONFIG_LEGACY_DIRECT_IO=y
+15 −0
Original line number Diff line number Diff line
@@ -13,3 +13,18 @@ config HFS_FS

	  To compile this file system support as a module, choose M here: the
	  module will be called hfs.

config HFS_KUNIT_TEST
	tristate "KUnit tests for HFS filesystem" if !KUNIT_ALL_TESTS
	depends on HFS_FS && KUNIT
	default KUNIT_ALL_TESTS
	help
	  This builds KUnit tests for the HFS filesystem.

	  KUnit tests run during boot and output the results to the debug
	  log in TAP format (https://testanything.org/). Only useful for
	  kernel devs running KUnit test harness and are not for inclusion
	  into a production build.

	  For more information on KUnit and unit tests in general please
	  refer to the KUnit documentation in Documentation/dev-tools/kunit/.
+2 −0
Original line number Diff line number Diff line
@@ -9,3 +9,5 @@ hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \
	    catalog.o dir.o extent.o inode.o attr.o mdb.o \
            part_tbl.o string.o super.o sysdep.o trans.o

# KUnit tests
obj-$(CONFIG_HFS_KUNIT_TEST) += string_test.o
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ int hfs_brec_find(struct hfs_find_data *fd)
	return res;
}

int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len)
int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len)
{
	int res;

+26 −26
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@
#include "btree.h"

static inline
bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off)
{
	bool is_valid = off < node->tree->node_size;

	if (!is_valid) {
		pr_err("requested invalid offset: "
		       "NODE: id %u, type %#x, height %u, "
		       "node_size %u, offset %d\n",
		       "node_size %u, offset %u\n",
		       node->this, node->type, node->height,
		       node->tree->node_size, off);
	}
@@ -32,7 +32,7 @@ bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
}

static inline
int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
u32 check_and_correct_requested_length(struct hfs_bnode *node, u32 off, u32 len)
{
	unsigned int node_size;

@@ -42,12 +42,12 @@ int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
	node_size = node->tree->node_size;

	if ((off + len) > node_size) {
		int new_len = (int)node_size - off;
		u32 new_len = node_size - off;

		pr_err("requested length has been corrected: "
		       "NODE: id %u, type %#x, height %u, "
		       "node_size %u, offset %d, "
		       "requested_len %d, corrected_len %d\n",
		       "node_size %u, offset %u, "
		       "requested_len %u, corrected_len %u\n",
		       node->this, node->type, node->height,
		       node->tree->node_size, off, len, new_len);

@@ -57,12 +57,12 @@ int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
	return len;
}

void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len)
{
	struct page *page;
	int pagenum;
	int bytes_read;
	int bytes_to_read;
	u32 pagenum;
	u32 bytes_read;
	u32 bytes_to_read;

	if (!is_bnode_offset_valid(node, off))
		return;
@@ -70,7 +70,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
	if (len == 0) {
		pr_err("requested zero length: "
		       "NODE: id %u, type %#x, height %u, "
		       "node_size %u, offset %d, len %d\n",
		       "node_size %u, offset %u, len %u\n",
		       node->this, node->type, node->height,
		       node->tree->node_size, off, len);
		return;
@@ -86,7 +86,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
		if (pagenum >= node->tree->pages_per_bnode)
			break;
		page = node->page[pagenum];
		bytes_to_read = min_t(int, len - bytes_read, PAGE_SIZE - off);
		bytes_to_read = min_t(u32, len - bytes_read, PAGE_SIZE - off);

		memcpy_from_page(buf + bytes_read, page, off, bytes_to_read);

@@ -95,7 +95,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
	}
}

u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off)
{
	__be16 data;
	// optimize later...
@@ -103,7 +103,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
	return be16_to_cpu(data);
}

u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off)
{
	u8 data;
	// optimize later...
@@ -111,10 +111,10 @@ u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
	return data;
}

void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off)
{
	struct hfs_btree *tree;
	int key_len;
	u32 key_len;

	tree = node->tree;
	if (node->type == HFS_NODE_LEAF ||
@@ -125,14 +125,14 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)

	if (key_len > sizeof(hfs_btree_key) || key_len < 1) {
		memset(key, 0, sizeof(hfs_btree_key));
		pr_err("hfs: Invalid key length: %d\n", key_len);
		pr_err("hfs: Invalid key length: %u\n", key_len);
		return;
	}

	hfs_bnode_read(node, key, off, key_len);
}

void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len)
{
	struct page *page;

@@ -142,7 +142,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
	if (len == 0) {
		pr_err("requested zero length: "
		       "NODE: id %u, type %#x, height %u, "
		       "node_size %u, offset %d, len %d\n",
		       "node_size %u, offset %u, len %u\n",
		       node->this, node->type, node->height,
		       node->tree->node_size, off, len);
		return;
@@ -157,20 +157,20 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
	set_page_dirty(page);
}

void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data)
{
	__be16 v = cpu_to_be16(data);
	// optimize later...
	hfs_bnode_write(node, &v, off, 2);
}

void hfs_bnode_write_u8(struct hfs_bnode *node, int off, u8 data)
void hfs_bnode_write_u8(struct hfs_bnode *node, u32 off, u8 data)
{
	// optimize later...
	hfs_bnode_write(node, &data, off, 1);
}

void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len)
{
	struct page *page;

@@ -180,7 +180,7 @@ void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
	if (len == 0) {
		pr_err("requested zero length: "
		       "NODE: id %u, type %#x, height %u, "
		       "node_size %u, offset %d, len %d\n",
		       "node_size %u, offset %u, len %u\n",
		       node->this, node->type, node->height,
		       node->tree->node_size, off, len);
		return;
@@ -195,8 +195,8 @@ void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
	set_page_dirty(page);
}

void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
		struct hfs_bnode *src_node, int src, int len)
void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst,
		    struct hfs_bnode *src_node, u32 src, u32 len)
{
	struct page *src_page, *dst_page;

@@ -216,7 +216,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
	set_page_dirty(dst_page);
}

void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len)
{
	struct page *page;
	void *ptr;
Loading