diff options
| author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2023-04-04 16:39:34 +0100 |
|---|---|---|
| committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2023-04-05 15:29:59 +0100 |
| commit | 33cb9de5cba0e3b428a2bab4bd8368bf55806430 (patch) | |
| tree | 63884e6c4509f00baf13066ac12efcd6cf29b85c /sysdeps | |
| parent | 47e61ba7720c1c646077318e079dcb75224b1001 (diff) | |
| download | glibc-arm/morello/main.tar.xz glibc-arm/morello/main.zip | |
cheri: malloc: exact capability check in free/reallocarm/morello/main
Capability narrowing uses a lookup table from an address to the
internally used wide capability. Keep the narrow capability in the
table instead of just the address and check it. This allows free
and realloc to check their input and only accept capabilities
exactly matching what was returned by malloc.
When a user adds restrictions on top of malloc returned capabilities
(e.g. narrower bounds), realloc could bypass those restrictions when
it simply looked up the internal wide capability for the address.
Diffstat (limited to 'sysdeps')
| -rw-r--r-- | sysdeps/aarch64/morello/libc-cap.h | 66 | ||||
| -rw-r--r-- | sysdeps/generic/libc-cap.h | 1 |
2 files changed, 41 insertions, 26 deletions
diff --git a/sysdeps/aarch64/morello/libc-cap.h b/sysdeps/aarch64/morello/libc-cap.h index 9e6f66aa22..84c20e9df8 100644 --- a/sysdeps/aarch64/morello/libc-cap.h +++ b/sysdeps/aarch64/morello/libc-cap.h @@ -30,8 +30,7 @@ struct htentry { - uint64_t key; - uint64_t unused; + void *key; void *value; }; @@ -48,19 +47,19 @@ struct ht static inline bool htentry_isempty (struct htentry *e) { - return e->key == 0; + return (uint64_t) e->key == 0; } static inline bool htentry_isdeleted (struct htentry *e) { - return e->key == -1; + return (uint64_t) e->key == -1; } static inline bool htentry_isused (struct htentry *e) { - return e->key != 0 && e->key != -1; + return !htentry_isempty (e) && !htentry_isdeleted (e); } static inline uint64_t @@ -154,9 +153,10 @@ ht_resize (struct ht *ht) { if (htentry_isused (e)) { - uint64_t hash = ht_key_hash (e->key); + uint64_t k = (uint64_t) e->key; + uint64_t hash = ht_key_hash (k); used--; - *ht_lookup (ht, e->key, hash) = *e; + *ht_lookup (ht, k, hash) = *e; } } ht_tab_free (oldtab, oldlen); @@ -191,48 +191,61 @@ ht_unreserve (struct ht *ht) } static bool -ht_add (struct ht *ht, uint64_t key, void *value) +ht_add (struct ht *ht, void *key, void *value) { + uint64_t k = (uint64_t) key; + uint64_t hash = ht_key_hash (k); + assert (k != 0 && k != -1); + __libc_lock_lock (ht->mutex); assert (ht->reserve > 0); ht->reserve--; - uint64_t hash = ht_key_hash (key); - struct htentry *e = ht_lookup (ht, key, hash); + struct htentry *e = ht_lookup (ht, k, hash); bool r = false; if (!htentry_isused (e)) { if (htentry_isempty (e)) ht->fill++; ht->used++; - e->key = key; r = true; } + e->key = key; e->value = value; __libc_lock_unlock (ht->mutex); return r; } static bool -ht_del (struct ht *ht, uint64_t key) +ht_del (struct ht *ht, void *key) { + uint64_t k = (uint64_t) key; + uint64_t hash = ht_key_hash (k); + assert (k != 0 && k != -1); + __libc_lock_lock (ht->mutex); - struct htentry *e = ht_lookup (ht, key, ht_key_hash (key)); + struct htentry *e = ht_lookup (ht, k, hash); bool r = htentry_isused (e); if (r) { + r = __builtin_cheri_equal_exact(e->key, key); ht->used--; - e->key = -1; + e->key = (void *) -1; + e->value = NULL; } __libc_lock_unlock (ht->mutex); return r; } static void * -ht_get (struct ht *ht, uint64_t key) +ht_get (struct ht *ht, void *key) { + uint64_t k = (uint64_t) key; + uint64_t hash = ht_key_hash (k); + assert (k != 0 && k != -1); + __libc_lock_lock (ht->mutex); - struct htentry *e = ht_lookup (ht, key, ht_key_hash (key)); - void *v = htentry_isused (e) ? e->value : NULL; + struct htentry *e = ht_lookup (ht, k, hash); + void *v = __builtin_cheri_equal_exact(e->key, key) ? e->value : NULL; __libc_lock_unlock (ht->mutex); return v; } @@ -317,10 +330,9 @@ __libc_cap_align (size_t n) static __always_inline void * __libc_cap_narrow (void *p, size_t n) { - assert (p != NULL); - uint64_t key = (uint64_t)(uintptr_t) p; - assert (ht_add (&__libc_cap_ht, key, p)); void *narrow = __builtin_cheri_bounds_set_exact (p, n); + assert (__builtin_cheri_tag_get (narrow)); + assert (ht_add (&__libc_cap_ht, narrow, p)); return narrow; } @@ -329,9 +341,7 @@ __libc_cap_narrow (void *p, size_t n) static __always_inline void * __libc_cap_widen (void *p) { - assert (__builtin_cheri_tag_get (p) && __builtin_cheri_offset_get (p) == 0); - uint64_t key = (uint64_t)(uintptr_t) p; - void *cap = ht_get (&__libc_cap_ht, key); + void *cap = ht_get (&__libc_cap_ht, p); assert (cap == p); return cap; } @@ -351,9 +361,13 @@ __libc_cap_unreserve (void) static __always_inline void __libc_cap_drop (void *p) { - assert (p != NULL); - uint64_t key = (uint64_t)(uintptr_t) p; - assert (ht_del (&__libc_cap_ht, key)); + assert (ht_del (&__libc_cap_ht, p)); +} + +static __always_inline void +__libc_cap_put_back (void *p, void *narrow) +{ + assert (ht_add (&__libc_cap_ht, narrow, p)); } #endif diff --git a/sysdeps/generic/libc-cap.h b/sysdeps/generic/libc-cap.h index 9d93d61c9e..4a385d823b 100644 --- a/sysdeps/generic/libc-cap.h +++ b/sysdeps/generic/libc-cap.h @@ -39,5 +39,6 @@ void __libc_cap_link_error (void); #define __libc_cap_reserve(p) __libc_cap_fail (bool) #define __libc_cap_unreserve(p) __libc_cap_fail (void) #define __libc_cap_drop(p) __libc_cap_fail (void) +#define __libc_cap_put_back(p, q) __libc_cap_fail (void) #endif |
