Skip to content

Commit

Permalink
Prevent memory coalescing if cap-bounds do not span full length on CHERI
Browse files Browse the repository at this point in the history
(a cherry-pick of commit d8ecfa3 partly from capablevms/bdwgc)

Issue #627 (bdwgc).

During a GC sweep, coalescing contiguous memory that spans two separate
system OS allocations (e.g. using `mmap()`), causes memory leakage in
CHERI systems.  This is because the capability used to represent such
coalesced (expanded) memory regions has memory bounds derived from the
original allocation syscall (smaller than the size of the coalesced
memory).  To prevent a client being given a capability with invalid
bounds, such coalescing is prevented.

* allchblk.c [CHERI_PURECAP] (GC_freehblk): Call
`CAPABILITY_COVERS_RANGE()` for `hbp` and `next` to check if coalescing
with the successor is possible; add comment and FIXME item; evaluate
`cheri_base_get(hbp)<=ADDR(prev)` to check if coalescing with the
predecessor is possible.
* include/private/gc_priv.h [CHERI_PURECAP] (CAPABILITY_COVERS_RANGE):
New macro.
* include/private/gc_priv.h [CHERI_PURECAP] (SPANNING_CAPABILITY): Use
`CAPABILITY_COVERS_RANGE()`.
  • Loading branch information
Dejice Jacob authored and ivmai committed Nov 12, 2024
1 parent 5c21ac4 commit c1038fa
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
17 changes: 15 additions & 2 deletions allchblk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,15 @@ GC_freehblk(struct hblk *hbp)
GET_HDR(next, nexthdr);
prev = GC_free_block_ending_at(hbp);
/* Coalesce with successor, if possible. */
if (nexthdr != NULL && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)
if (nexthdr != NULL && HBLK_IS_FREE(nexthdr)
&& IS_MAPPED(nexthdr)
#ifdef CHERI_PURECAP
/* FIXME: Coalesce with super-capability. */
/* Bounds of capability should span the entire coalesced memory; */
/* bounds being larger than the block size is OK; bounded by the */
/* imprecision of original capability obtained from system memory. */
&& CAPABILITY_COVERS_RANGE(hbp, ADDR(next), ADDR(next) + nexthdr->hb_sz)
#endif
&& !BLOCKS_MERGE_OVERFLOW(hhdr, nexthdr)) {
GC_remove_from_fl(nexthdr);
hhdr->hb_sz += nexthdr->hb_sz;
Expand All @@ -1105,7 +1113,12 @@ GC_freehblk(struct hblk *hbp)
/* Coalesce with predecessor, if possible. */
if (prev /* != NULL */) { /* CPPCHECK */
prevhdr = HDR(prev);
if (IS_MAPPED(prevhdr) && !BLOCKS_MERGE_OVERFLOW(prevhdr, hhdr)) {
if (IS_MAPPED(prevhdr)
#ifdef CHERI_PURECAP
/* FIXME: Coalesce with super-capability. */
&& cheri_base_get(hbp) <= ADDR(prev)
#endif
&& !BLOCKS_MERGE_OVERFLOW(prevhdr, hhdr)) {
GC_remove_from_fl(prevhdr);
prevhdr->hb_sz += hhdr->hb_sz;
#ifdef USE_MUNMAP
Expand Down
6 changes: 4 additions & 2 deletions include/private/gc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2178,9 +2178,11 @@ ptr_t GC_save_regs_in_stack(void);
#endif /* !E2K */

#ifdef CHERI_PURECAP
# define CAPABILITY_COVERS_RANGE(cap, b_addr, e_addr) \
(cheri_base_get(cap) <= (b_addr) \
&& cheri_base_get(cap) + cheri_length_get(cap) >= (e_addr))
# define SPANNING_CAPABILITY(cap, b_addr, e_addr) \
(cheri_tag_get(cap) && cheri_base_get(cap) <= (b_addr) \
&& cheri_base_get(cap) + cheri_length_get(cap) >= (e_addr) \
(cheri_tag_get(cap) && CAPABILITY_COVERS_RANGE(cap, b_addr, e_addr) \
&& (cheri_perms_get(cap) & (CHERI_PERM_LOAD | CHERI_PERM_LOAD_CAP)) \
!= 0)
#endif
Expand Down

0 comments on commit c1038fa

Please sign in to comment.