Skip to content

Commit ca010e2

Browse files
committed
Merge tag 'hfs-v6.19-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs
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()
2 parents 7696286 + ec95cd1 commit ca010e2

30 files changed

Lines changed: 2698 additions & 914 deletions

fs/hfs/.kunitconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CONFIG_KUNIT=y
2+
CONFIG_HFS_FS=y
3+
CONFIG_HFS_KUNIT_TEST=y
4+
CONFIG_BLOCK=y
5+
CONFIG_BUFFER_HEAD=y
6+
CONFIG_NLS=y
7+
CONFIG_LEGACY_DIRECT_IO=y

fs/hfs/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,18 @@ config HFS_FS
1313

1414
To compile this file system support as a module, choose M here: the
1515
module will be called hfs.
16+
17+
config HFS_KUNIT_TEST
18+
tristate "KUnit tests for HFS filesystem" if !KUNIT_ALL_TESTS
19+
depends on HFS_FS && KUNIT
20+
default KUNIT_ALL_TESTS
21+
help
22+
This builds KUnit tests for the HFS filesystem.
23+
24+
KUnit tests run during boot and output the results to the debug
25+
log in TAP format (https://testanything.org/). Only useful for
26+
kernel devs running KUnit test harness and are not for inclusion
27+
into a production build.
28+
29+
For more information on KUnit and unit tests in general please
30+
refer to the KUnit documentation in Documentation/dev-tools/kunit/.

fs/hfs/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \
99
catalog.o dir.o extent.o inode.o attr.o mdb.o \
1010
part_tbl.o string.o super.o sysdep.o trans.o
1111

12+
# KUnit tests
13+
obj-$(CONFIG_HFS_KUNIT_TEST) += string_test.o

fs/hfs/bfind.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ int hfs_brec_find(struct hfs_find_data *fd)
167167
return res;
168168
}
169169

170-
int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len)
170+
int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len)
171171
{
172172
int res;
173173

fs/hfs/bnode.c

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
#include "btree.h"
1717

1818
static inline
19-
bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
19+
bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off)
2020
{
2121
bool is_valid = off < node->tree->node_size;
2222

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

3434
static inline
35-
int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
35+
u32 check_and_correct_requested_length(struct hfs_bnode *node, u32 off, u32 len)
3636
{
3737
unsigned int node_size;
3838

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

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

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

@@ -57,20 +57,20 @@ int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
5757
return len;
5858
}
5959

60-
void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
60+
void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len)
6161
{
6262
struct page *page;
63-
int pagenum;
64-
int bytes_read;
65-
int bytes_to_read;
63+
u32 pagenum;
64+
u32 bytes_read;
65+
u32 bytes_to_read;
6666

6767
if (!is_bnode_offset_valid(node, off))
6868
return;
6969

7070
if (len == 0) {
7171
pr_err("requested zero length: "
7272
"NODE: id %u, type %#x, height %u, "
73-
"node_size %u, offset %d, len %d\n",
73+
"node_size %u, offset %u, len %u\n",
7474
node->this, node->type, node->height,
7575
node->tree->node_size, off, len);
7676
return;
@@ -86,7 +86,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
8686
if (pagenum >= node->tree->pages_per_bnode)
8787
break;
8888
page = node->page[pagenum];
89-
bytes_to_read = min_t(int, len - bytes_read, PAGE_SIZE - off);
89+
bytes_to_read = min_t(u32, len - bytes_read, PAGE_SIZE - off);
9090

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

@@ -95,26 +95,26 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
9595
}
9696
}
9797

98-
u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
98+
u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off)
9999
{
100100
__be16 data;
101101
// optimize later...
102102
hfs_bnode_read(node, &data, off, 2);
103103
return be16_to_cpu(data);
104104
}
105105

106-
u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
106+
u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off)
107107
{
108108
u8 data;
109109
// optimize later...
110110
hfs_bnode_read(node, &data, off, 1);
111111
return data;
112112
}
113113

114-
void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
114+
void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off)
115115
{
116116
struct hfs_btree *tree;
117-
int key_len;
117+
u32 key_len;
118118

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

126126
if (key_len > sizeof(hfs_btree_key) || key_len < 1) {
127127
memset(key, 0, sizeof(hfs_btree_key));
128-
pr_err("hfs: Invalid key length: %d\n", key_len);
128+
pr_err("hfs: Invalid key length: %u\n", key_len);
129129
return;
130130
}
131131

132132
hfs_bnode_read(node, key, off, key_len);
133133
}
134134

135-
void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
135+
void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len)
136136
{
137137
struct page *page;
138138

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

160-
void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
160+
void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data)
161161
{
162162
__be16 v = cpu_to_be16(data);
163163
// optimize later...
164164
hfs_bnode_write(node, &v, off, 2);
165165
}
166166

167-
void hfs_bnode_write_u8(struct hfs_bnode *node, int off, u8 data)
167+
void hfs_bnode_write_u8(struct hfs_bnode *node, u32 off, u8 data)
168168
{
169169
// optimize later...
170170
hfs_bnode_write(node, &data, off, 1);
171171
}
172172

173-
void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
173+
void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len)
174174
{
175175
struct page *page;
176176

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

198-
void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
199-
struct hfs_bnode *src_node, int src, int len)
198+
void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst,
199+
struct hfs_bnode *src_node, u32 src, u32 len)
200200
{
201201
struct page *src_page, *dst_page;
202202

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

219-
void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
219+
void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len)
220220
{
221221
struct page *page;
222222
void *ptr;

fs/hfs/brec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
6262
return retval;
6363
}
6464

65-
int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
65+
int hfs_brec_insert(struct hfs_find_data *fd, void *entry, u32 entry_len)
6666
{
6767
struct hfs_btree *tree;
6868
struct hfs_bnode *node, *new_node;

fs/hfs/btree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
259259
}
260260

261261
/* Make sure @tree has enough space for the @rsvd_nodes */
262-
int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
262+
int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes)
263263
{
264264
struct inode *inode = tree->inode;
265265
u32 count;

fs/hfs/btree.h

Lines changed: 36 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -86,87 +86,46 @@ struct hfs_find_data {
8686

8787

8888
/* btree.c */
89-
extern struct hfs_btree *hfs_btree_open(struct super_block *, u32, btree_keycmp);
90-
extern void hfs_btree_close(struct hfs_btree *);
91-
extern void hfs_btree_write(struct hfs_btree *);
92-
extern int hfs_bmap_reserve(struct hfs_btree *, int);
93-
extern struct hfs_bnode * hfs_bmap_alloc(struct hfs_btree *);
89+
extern struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id,
90+
btree_keycmp keycmp);
91+
extern void hfs_btree_close(struct hfs_btree *tree);
92+
extern void hfs_btree_write(struct hfs_btree *tree);
93+
extern int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes);
94+
extern struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree);
9495
extern void hfs_bmap_free(struct hfs_bnode *node);
9596

9697
/* bnode.c */
97-
extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int);
98-
extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int);
99-
extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int);
100-
extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int);
101-
extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int);
102-
extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16);
103-
extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8);
104-
extern void hfs_bnode_clear(struct hfs_bnode *, int, int);
105-
extern void hfs_bnode_copy(struct hfs_bnode *, int,
106-
struct hfs_bnode *, int, int);
107-
extern void hfs_bnode_move(struct hfs_bnode *, int, int, int);
108-
extern void hfs_bnode_dump(struct hfs_bnode *);
109-
extern void hfs_bnode_unlink(struct hfs_bnode *);
110-
extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *, u32);
111-
extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *, u32);
112-
extern void hfs_bnode_unhash(struct hfs_bnode *);
113-
extern void hfs_bnode_free(struct hfs_bnode *);
114-
extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *, u32);
115-
extern void hfs_bnode_get(struct hfs_bnode *);
116-
extern void hfs_bnode_put(struct hfs_bnode *);
98+
extern void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len);
99+
extern u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off);
100+
extern u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off);
101+
extern void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off);
102+
extern void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len);
103+
extern void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data);
104+
extern void hfs_bnode_write_u8(struct hfs_bnode *node, u32 off, u8 data);
105+
extern void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len);
106+
extern void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst,
107+
struct hfs_bnode *src_node, u32 src, u32 len);
108+
extern void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len);
109+
extern void hfs_bnode_dump(struct hfs_bnode *node);
110+
extern void hfs_bnode_unlink(struct hfs_bnode *node);
111+
extern struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid);
112+
extern struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num);
113+
extern void hfs_bnode_unhash(struct hfs_bnode *node);
114+
extern void hfs_bnode_free(struct hfs_bnode *node);
115+
extern struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num);
116+
extern void hfs_bnode_get(struct hfs_bnode *node);
117+
extern void hfs_bnode_put(struct hfs_bnode *node);
117118

118119
/* brec.c */
119-
extern u16 hfs_brec_lenoff(struct hfs_bnode *, u16, u16 *);
120-
extern u16 hfs_brec_keylen(struct hfs_bnode *, u16);
121-
extern int hfs_brec_insert(struct hfs_find_data *, void *, int);
122-
extern int hfs_brec_remove(struct hfs_find_data *);
120+
extern u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off);
121+
extern u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec);
122+
extern int hfs_brec_insert(struct hfs_find_data *fd, void *entry, u32 entry_len);
123+
extern int hfs_brec_remove(struct hfs_find_data *fd);
123124

124125
/* bfind.c */
125-
extern int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
126-
extern void hfs_find_exit(struct hfs_find_data *);
127-
extern int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *);
128-
extern int hfs_brec_find(struct hfs_find_data *);
129-
extern int hfs_brec_read(struct hfs_find_data *, void *, int);
130-
extern int hfs_brec_goto(struct hfs_find_data *, int);
131-
132-
133-
struct hfs_bnode_desc {
134-
__be32 next; /* (V) Number of the next node at this level */
135-
__be32 prev; /* (V) Number of the prev node at this level */
136-
u8 type; /* (F) The type of node */
137-
u8 height; /* (F) The level of this node (leaves=1) */
138-
__be16 num_recs; /* (V) The number of records in this node */
139-
u16 reserved;
140-
} __packed;
141-
142-
#define HFS_NODE_INDEX 0x00 /* An internal (index) node */
143-
#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */
144-
#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */
145-
#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */
146-
147-
struct hfs_btree_header_rec {
148-
__be16 depth; /* (V) The number of levels in this B-tree */
149-
__be32 root; /* (V) The node number of the root node */
150-
__be32 leaf_count; /* (V) The number of leaf records */
151-
__be32 leaf_head; /* (V) The number of the first leaf node */
152-
__be32 leaf_tail; /* (V) The number of the last leaf node */
153-
__be16 node_size; /* (F) The number of bytes in a node (=512) */
154-
__be16 max_key_len; /* (F) The length of a key in an index node */
155-
__be32 node_count; /* (V) The total number of nodes */
156-
__be32 free_nodes; /* (V) The number of unused nodes */
157-
u16 reserved1;
158-
__be32 clump_size; /* (F) clump size. not usually used. */
159-
u8 btree_type; /* (F) BTree type */
160-
u8 reserved2;
161-
__be32 attributes; /* (F) attributes */
162-
u32 reserved3[16];
163-
} __packed;
164-
165-
#define BTREE_ATTR_BADCLOSE 0x00000001 /* b-tree not closed properly. not
166-
used by hfsplus. */
167-
#define HFS_TREE_BIGKEYS 0x00000002 /* key length is u16 instead of u8.
168-
used by hfsplus. */
169-
#define HFS_TREE_VARIDXKEYS 0x00000004 /* variable key length instead of
170-
max key length. use din catalog
171-
b-tree but not in extents
172-
b-tree (hfsplus). */
126+
extern int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd);
127+
extern void hfs_find_exit(struct hfs_find_data *fd);
128+
extern int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd);
129+
extern int hfs_brec_find(struct hfs_find_data *fd);
130+
extern int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len);
131+
extern int hfs_brec_goto(struct hfs_find_data *fd, int cnt);

fs/hfs/catalog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,9 @@ int hfs_correct_next_unused_CNID(struct super_block *sb, u32 cnid)
322322
}
323323
}
324324

325+
node_id = node->prev;
325326
hfs_bnode_put(node);
326327

327-
node_id = node->prev;
328328
} while (node_id >= leaf_head);
329329

330330
return -ENOENT;

0 commit comments

Comments
 (0)