Skip to content

Commit 59c39b5

Browse files
author
Andy Ross
committed
lib/os/mempool: Fix corruption case with block splitting
The block_fits() predicate was borked. It would check that a block fits within the bounds of the whole heap. But that's not enough: because of alignment changes between levels the sub-blocks may be adjusted forward. It needs to fit inside the PARENT block that it was split from. What could happen at runtime is that the last subblocks of a misaligned parent block would overlap memory from subsequent blocks, or even run off the end of the heap. That's bad. Change the API of block_fits() a little so it can extract the parent region and do this properly. Fixes #15279. Passes test introduced in #16728 to demonstrate what seems like the same issue. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
1 parent 639eb76 commit 59c39b5

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

lib/os/mempool.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,23 @@ static size_t buf_size(struct sys_mem_pool_base *p)
7272
return p->n_max * p->max_sz;
7373
}
7474

75-
static bool block_fits(struct sys_mem_pool_base *p, void *block, size_t bsz)
75+
static bool block_fits(struct sys_mem_pool_base *p,
76+
int lvl, int bn, size_t *lsizes)
7677
{
77-
return ((u8_t *)block + bsz - 1 - (u8_t *)p->buf) < buf_size(p);
78+
u8_t *parent, *block_end;
79+
size_t parent_sz;
80+
81+
block_end = (u8_t *)block_ptr(p, lsizes[lvl], bn) + lsizes[lvl];
82+
83+
if (lvl == 0) {
84+
parent_sz = buf_size(p);
85+
parent = p->buf;
86+
} else {
87+
parent_sz = lsizes[lvl - 1];
88+
parent = block_ptr(p, lsizes[lvl - 1], bn / 4);
89+
}
90+
91+
return block_end <= (parent + parent_sz);
7892
}
7993

8094
void z_sys_mem_pool_base_init(struct sys_mem_pool_base *p)
@@ -161,7 +175,7 @@ static unsigned int bfree_recombine(struct sys_mem_pool_base *p, int level,
161175
int i, lsz = lsizes[level];
162176
void *block = block_ptr(p, lsz, bn);
163177

164-
__ASSERT(block_fits(p, block, lsz), "");
178+
__ASSERT(block_fits(p, level, bn, lsizes), "");
165179

166180
/* Put it back */
167181
set_free_bit(p, level, bn);
@@ -179,7 +193,7 @@ static unsigned int bfree_recombine(struct sys_mem_pool_base *p, int level,
179193
for (i = 0; i < 4; i++) {
180194
int b = (bn & ~3) + i;
181195

182-
if (block_fits(p, block_ptr(p, lsz, b), lsz)) {
196+
if (block_fits(p, level, b, lsizes)) {
183197
clear_free_bit(p, level, b);
184198
sys_dlist_remove(block_ptr(p, lsz, b));
185199
}
@@ -220,7 +234,7 @@ static void *block_break(struct sys_mem_pool_base *p, void *block, int l,
220234
void *block2 = (lsz * i) + (char *)block;
221235

222236
set_free_bit(p, l + 1, lbn);
223-
if (block_fits(p, block2, lsz)) {
237+
if (block_fits(p, l + 1, lbn, lsizes)) {
224238
sys_dlist_append(&p->levels[l + 1].free_list, block2);
225239
}
226240
}

0 commit comments

Comments
 (0)