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:
committed by
Manuel Diewald
parent
930c654223
commit
09ad3b1e99
+7
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user