Skip to content

Commit efc095b

Browse files
dubeykogregkh
authored andcommitted
hfs: fix slab-out-of-bounds in hfs_bnode_read()
[ Upstream commit a431930 ] This patch introduces is_bnode_offset_valid() method that checks the requested offset value. Also, it introduces check_and_correct_requested_length() method that checks and correct the requested length (if it is necessary). These methods are used in hfs_bnode_read(), hfs_bnode_write(), hfs_bnode_clear(), hfs_bnode_copy(), and hfs_bnode_move() with the goal to prevent the access out of allocated memory and triggering the crash. Signed-off-by: Viacheslav Dubeyko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Viacheslav Dubeyko <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 5d8b249 commit efc095b

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

fs/hfs/bnode.c

Lines changed: 92 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];

0 commit comments

Comments
 (0)