Skip to content

Commit cb6bbff

Browse files
committed
Merge tag 'hfs-v6.17-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs
Pull hfs/hfsplus updates from Viacheslav Dubeyko: "Johannes Thumshirn has made nice cleanup in hfsplus_submit_bio(). Tetsuo Handa has fixed the syzbot reported issue in hfsplus_create_attributes_file() for the case of corruption the Attributes File's metadata. Yangtao Li has fixed the syzbot reported issue by removing the uneccessary WARN_ON() in hfsplus_free_extents(). Other fixes: - restore generic/001 successful execution by erasing deleted b-tree nodes - eliminate slab-out-of-bounds issue in hfs_bnode_read() and hfsplus_bnode_read() by checking correctness of offset and length when accessing b-tree node contents - eliminate slab-out-of-bounds read in hfsplus_uni2asc() if the b-tree node record has corrupted length of a name that could be bigger than HFSPLUS_MAX_STRLEN - eliminate general protection fault in hfs_find_init() for the case of initial b-tree object creation" * tag 'hfs-v6.17-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfs: fix general protection fault in hfs_find_init() hfs: fix slab-out-of-bounds in hfs_bnode_read() hfsplus: fix slab-out-of-bounds in hfsplus_bnode_read() hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc() hfsplus: don't use BUG_ON() in hfsplus_create_attributes_file() hfsplus: don't set REQ_SYNC for hfsplus_submit_bio() hfsplus: remove mutex_lock check in hfsplus_free_extents hfs: make splice write available again hfsplus: make splice write available again hfs: fix not erasing deleted b-tree node issue
2 parents c7bfaff + 736a051 commit cb6bbff

File tree

12 files changed

+252
-20
lines changed

12 files changed

+252
-20
lines changed

fs/hfs/bfind.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
1616
{
1717
void *ptr;
1818

19+
if (!tree || !fd)
20+
return -EINVAL;
21+
1922
fd->tree = tree;
2023
fd->bnode = NULL;
2124
ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);

fs/hfs/bnode.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,69 @@
1515

1616
#include "btree.h"
1717

18+
static inline
19+
bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
20+
{
21+
bool is_valid = off < node->tree->node_size;
22+
23+
if (!is_valid) {
24+
pr_err("requested invalid offset: "
25+
"NODE: id %u, type %#x, height %u, "
26+
"node_size %u, offset %d\n",
27+
node->this, node->type, node->height,
28+
node->tree->node_size, off);
29+
}
30+
31+
return is_valid;
32+
}
33+
34+
static inline
35+
int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
36+
{
37+
unsigned int node_size;
38+
39+
if (!is_bnode_offset_valid(node, off))
40+
return 0;
41+
42+
node_size = node->tree->node_size;
43+
44+
if ((off + len) > node_size) {
45+
int new_len = (int)node_size - off;
46+
47+
pr_err("requested length has been corrected: "
48+
"NODE: id %u, type %#x, height %u, "
49+
"node_size %u, offset %d, "
50+
"requested_len %d, corrected_len %d\n",
51+
node->this, node->type, node->height,
52+
node->tree->node_size, off, len, new_len);
53+
54+
return new_len;
55+
}
56+
57+
return len;
58+
}
59+
1860
void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
1961
{
2062
struct page *page;
2163
int pagenum;
2264
int bytes_read;
2365
int bytes_to_read;
2466

67+
if (!is_bnode_offset_valid(node, off))
68+
return;
69+
70+
if (len == 0) {
71+
pr_err("requested zero length: "
72+
"NODE: id %u, type %#x, height %u, "
73+
"node_size %u, offset %d, len %d\n",
74+
node->this, node->type, node->height,
75+
node->tree->node_size, off, len);
76+
return;
77+
}
78+
79+
len = check_and_correct_requested_length(node, off, len);
80+
2581
off += node->page_offset;
2682
pagenum = off >> PAGE_SHIFT;
2783
off &= ~PAGE_MASK; /* compute page offset for the first page */
@@ -80,6 +136,20 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
80136
{
81137
struct page *page;
82138

139+
if (!is_bnode_offset_valid(node, off))
140+
return;
141+
142+
if (len == 0) {
143+
pr_err("requested zero length: "
144+
"NODE: id %u, type %#x, height %u, "
145+
"node_size %u, offset %d, len %d\n",
146+
node->this, node->type, node->height,
147+
node->tree->node_size, off, len);
148+
return;
149+
}
150+
151+
len = check_and_correct_requested_length(node, off, len);
152+
83153
off += node->page_offset;
84154
page = node->page[0];
85155

@@ -104,6 +174,20 @@ void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
104174
{
105175
struct page *page;
106176

177+
if (!is_bnode_offset_valid(node, off))
178+
return;
179+
180+
if (len == 0) {
181+
pr_err("requested zero length: "
182+
"NODE: id %u, type %#x, height %u, "
183+
"node_size %u, offset %d, len %d\n",
184+
node->this, node->type, node->height,
185+
node->tree->node_size, off, len);
186+
return;
187+
}
188+
189+
len = check_and_correct_requested_length(node, off, len);
190+
107191
off += node->page_offset;
108192
page = node->page[0];
109193

@@ -119,6 +203,10 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
119203
hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
120204
if (!len)
121205
return;
206+
207+
len = check_and_correct_requested_length(src_node, src, len);
208+
len = check_and_correct_requested_length(dst_node, dst, len);
209+
122210
src += src_node->page_offset;
123211
dst += dst_node->page_offset;
124212
src_page = src_node->page[0];
@@ -136,6 +224,10 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
136224
hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
137225
if (!len)
138226
return;
227+
228+
len = check_and_correct_requested_length(node, src, len);
229+
len = check_and_correct_requested_length(node, dst, len);
230+
139231
src += node->page_offset;
140232
dst += node->page_offset;
141233
page = node->page[0];
@@ -482,6 +574,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
482574
if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
483575
hfs_bnode_unhash(node);
484576
spin_unlock(&tree->hash_lock);
577+
hfs_bnode_clear(node, 0, tree->node_size);
485578
hfs_bmap_free(node);
486579
hfs_bnode_free(node);
487580
return;

fs/hfs/btree.c

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
2121
struct hfs_btree *tree;
2222
struct hfs_btree_header_rec *head;
2323
struct address_space *mapping;
24-
struct page *page;
24+
struct folio *folio;
25+
struct buffer_head *bh;
2526
unsigned int size;
27+
u16 dblock;
28+
sector_t start_block;
29+
loff_t offset;
2630

2731
tree = kzalloc(sizeof(*tree), GFP_KERNEL);
2832
if (!tree)
@@ -75,12 +79,40 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
7579
unlock_new_inode(tree->inode);
7680

7781
mapping = tree->inode->i_mapping;
78-
page = read_mapping_page(mapping, 0, NULL);
79-
if (IS_ERR(page))
82+
folio = filemap_grab_folio(mapping, 0);
83+
if (IS_ERR(folio))
8084
goto free_inode;
8185

86+
folio_zero_range(folio, 0, folio_size(folio));
87+
88+
dblock = hfs_ext_find_block(HFS_I(tree->inode)->first_extents, 0);
89+
start_block = HFS_SB(sb)->fs_start + (dblock * HFS_SB(sb)->fs_div);
90+
91+
size = folio_size(folio);
92+
offset = 0;
93+
while (size > 0) {
94+
size_t len;
95+
96+
bh = sb_bread(sb, start_block);
97+
if (!bh) {
98+
pr_err("unable to read tree header\n");
99+
goto put_folio;
100+
}
101+
102+
len = min_t(size_t, folio_size(folio), sb->s_blocksize);
103+
memcpy_to_folio(folio, offset, bh->b_data, sb->s_blocksize);
104+
105+
brelse(bh);
106+
107+
start_block++;
108+
offset += len;
109+
size -= len;
110+
}
111+
112+
folio_mark_uptodate(folio);
113+
82114
/* Load the header */
83-
head = (struct hfs_btree_header_rec *)(kmap_local_page(page) +
115+
head = (struct hfs_btree_header_rec *)(kmap_local_folio(folio, 0) +
84116
sizeof(struct hfs_bnode_desc));
85117
tree->root = be32_to_cpu(head->root);
86118
tree->leaf_count = be32_to_cpu(head->leaf_count);
@@ -95,22 +127,22 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
95127

96128
size = tree->node_size;
97129
if (!is_power_of_2(size))
98-
goto fail_page;
130+
goto fail_folio;
99131
if (!tree->node_count)
100-
goto fail_page;
132+
goto fail_folio;
101133
switch (id) {
102134
case HFS_EXT_CNID:
103135
if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
104136
pr_err("invalid extent max_key_len %d\n",
105137
tree->max_key_len);
106-
goto fail_page;
138+
goto fail_folio;
107139
}
108140
break;
109141
case HFS_CAT_CNID:
110142
if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
111143
pr_err("invalid catalog max_key_len %d\n",
112144
tree->max_key_len);
113-
goto fail_page;
145+
goto fail_folio;
114146
}
115147
break;
116148
default:
@@ -121,12 +153,15 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
121153
tree->pages_per_bnode = (tree->node_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
122154

123155
kunmap_local(head);
124-
put_page(page);
156+
folio_unlock(folio);
157+
folio_put(folio);
125158
return tree;
126159

127-
fail_page:
160+
fail_folio:
128161
kunmap_local(head);
129-
put_page(page);
162+
put_folio:
163+
folio_unlock(folio);
164+
folio_put(folio);
130165
free_inode:
131166
tree->inode->i_mapping->a_ops = &hfs_aops;
132167
iput(tree->inode);

fs/hfs/extent.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ int hfs_ext_keycmp(const btree_key *key1, const btree_key *key2)
7171
*
7272
* Find a block within an extent record
7373
*/
74-
static u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off)
74+
u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off)
7575
{
7676
int i;
7777
u16 count;

fs/hfs/hfs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ extern const struct inode_operations hfs_dir_inode_operations;
190190

191191
/* extent.c */
192192
extern int hfs_ext_keycmp(const btree_key *, const btree_key *);
193+
extern u16 hfs_ext_find_block(struct hfs_extent *ext, u16 off);
193194
extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int);
194195
extern int hfs_ext_write_extent(struct inode *);
195196
extern int hfs_extend_file(struct inode *);

fs/hfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ static const struct file_operations hfs_file_operations = {
692692
.write_iter = generic_file_write_iter,
693693
.mmap_prepare = generic_file_mmap_prepare,
694694
.splice_read = filemap_splice_read,
695+
.splice_write = iter_file_splice_write,
695696
.fsync = hfs_file_fsync,
696697
.open = hfs_file_open,
697698
.release = hfs_file_release,

0 commit comments

Comments
 (0)