UBUNTU: SAUCE: fs: hfs/hfsplus: add key_len boundary check to hfs_bnode_read_key

hfs_bnode_read_key is lacking boundary checks on key sizes.

This can cause an out-of-bounds (oob) write with an excessively large key_len.

Add checks to determine if the computed key_len exceeds the maximum allowed
length and return -EINVAL if so.

Reported-by: Attila Szász <szasza.contact@gmail.com> # working with SSD Secure Disclosure
CVE-2025-0927
Signed-off-by: Cengiz Can <cengiz.can@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Manuel Diewald <manuel.diewald@canonical.com>
Signed-off-by: Manuel Diewald <manuel.diewald@canonical.com>
This commit is contained in:
Cengiz Can
2025-02-06 17:43:38 +03:00
committed by Manuel Diewald
parent 930c654223
commit 09ad3b1e99
6 changed files with 50 additions and 12 deletions
+7 -1
View File
@@ -55,7 +55,7 @@ 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)
int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
{
struct hfs_btree *tree;
int key_len;
@@ -67,7 +67,13 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
else
key_len = tree->max_key_len + 1;
if (key_len > tree->max_key_len + 1) {
pr_err("key_len %d too large\n", key_len);
return -EINVAL;
}
hfs_bnode_read(node, key, off, key_len);
return 0;
}
void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
+17 -4
View File
@@ -70,6 +70,7 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
int data_off, end_off;
int idx_rec_off, data_rec_off, end_rec_off;
__be32 cnid;
int res;
tree = fd->tree;
if (!fd->bnode) {
@@ -138,7 +139,10 @@ skip:
* at the start of the node and it is not the new node
*/
if (!rec && new_node != node) {
hfs_bnode_read_key(node, fd->search_key, data_off + size);
res = hfs_bnode_read_key(node, fd->search_key, data_off + size);
if (res < 0)
return res;
hfs_brec_update_parent(fd);
}
@@ -156,7 +160,10 @@ skip:
entry_len = sizeof(cnid);
/* get index key */
hfs_bnode_read_key(new_node, fd->search_key, 14);
res = hfs_bnode_read_key(new_node, fd->search_key, 14);
if (res < 0)
return res;
__hfs_brec_find(fd->bnode, fd);
hfs_bnode_put(new_node);
@@ -356,6 +363,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
int newkeylen, diff;
int rec, rec_off, end_rec_off;
int start_off, end_off;
int res;
tree = fd->tree;
node = fd->bnode;
@@ -431,7 +439,10 @@ skip:
}
fd->bnode = hfs_bnode_find(tree, new_node->parent);
/* create index key and entry */
hfs_bnode_read_key(new_node, fd->search_key, 14);
res = hfs_bnode_read_key(new_node, fd->search_key, 14);
if (res < 0)
return res;
cnid = cpu_to_be32(new_node->this);
__hfs_brec_find(fd->bnode, fd);
@@ -443,7 +454,9 @@ skip:
if (new_node == node)
goto out;
/* restore search_key */
hfs_bnode_read_key(node, fd->search_key, 14);
res = hfs_bnode_read_key(node, fd->search_key, 14);
if (res < 0)
return res;
}
new_node = NULL;
}
+1 -1
View File
@@ -97,7 +97,7 @@ extern void hfs_bmap_free(struct hfs_bnode *node);
extern void hfs_bnode_read(struct hfs_bnode *, void *, int, int);
extern u16 hfs_bnode_read_u16(struct hfs_bnode *, int);
extern u8 hfs_bnode_read_u8(struct hfs_bnode *, int);
extern void hfs_bnode_read_key(struct hfs_bnode *, void *, int);
extern int hfs_bnode_read_key(struct hfs_bnode *, void *, int);
extern void hfs_bnode_write(struct hfs_bnode *, void *, int, int);
extern void hfs_bnode_write_u16(struct hfs_bnode *, int, u16);
extern void hfs_bnode_write_u8(struct hfs_bnode *, int, u8);
+7 -1
View File
@@ -54,7 +54,7 @@ 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)
int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
{
struct hfs_btree *tree;
int key_len;
@@ -67,7 +67,13 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
else
key_len = tree->max_key_len + 2;
if (key_len > tree->max_key_len + 2) {
pr_err("key_len %d too large\n", key_len);
return -EINVAL;
}
hfs_bnode_read(node, key, off, key_len);
return 0;
}
void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
+17 -4
View File
@@ -68,6 +68,7 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
int data_off, end_off;
int idx_rec_off, data_rec_off, end_rec_off;
__be32 cnid;
int res;
tree = fd->tree;
if (!fd->bnode) {
@@ -138,7 +139,10 @@ skip:
* at the start of the node and it is not the new node
*/
if (!rec && new_node != node) {
hfs_bnode_read_key(node, fd->search_key, data_off + size);
res = hfs_bnode_read_key(node, fd->search_key, data_off + size);
if (res < 0)
return res;
hfs_brec_update_parent(fd);
}
@@ -156,7 +160,10 @@ skip:
entry_len = sizeof(cnid);
/* get index key */
hfs_bnode_read_key(new_node, fd->search_key, 14);
res = hfs_bnode_read_key(new_node, fd->search_key, 14);
if (res < 0)
return res;
__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
hfs_bnode_put(new_node);
@@ -360,6 +367,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
int newkeylen, diff;
int rec, rec_off, end_rec_off;
int start_off, end_off;
int res;
tree = fd->tree;
node = fd->bnode;
@@ -435,7 +443,10 @@ skip:
}
fd->bnode = hfs_bnode_find(tree, new_node->parent);
/* create index key and entry */
hfs_bnode_read_key(new_node, fd->search_key, 14);
res = hfs_bnode_read_key(new_node, fd->search_key, 14);
if (res < 0)
return res;
cnid = cpu_to_be32(new_node->this);
__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
@@ -447,7 +458,9 @@ skip:
if (new_node == node)
goto out;
/* restore search_key */
hfs_bnode_read_key(node, fd->search_key, 14);
res = hfs_bnode_read_key(node, fd->search_key, 14);
if (res < 0)
return res;
}
new_node = NULL;
}
+1 -1
View File
@@ -396,7 +396,7 @@ void hfs_bmap_free(struct hfs_bnode *node);
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);
u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off);
void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off);
int hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off);
void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len);
void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data);
void hfs_bnode_clear(struct hfs_bnode *node, int off, int len);