Szabolcs Nagy [Fri, 21 Oct 2022 11:35:33 +0000 (12:35 +0100)]
cheri: malloc: Ensure the mappings have RW permission
The arena allocator incrementally applies RW mprotect to a PROT_NONE
mapping. Use PROT_MAX to ensure the pointers derived from the original
mapping have RW capability permission.
Szabolcs Nagy [Fri, 21 Oct 2022 11:10:11 +0000 (12:10 +0100)]
aarch64: morello: define PROT_MAX
Specifies the prot flags a mapping may gain via mprotect or MAP_FIXED.
On CHERI targets this is used to get capability with more permissions
than the original mmap protection would imply.
Szabolcs Nagy [Thu, 29 Sep 2022 16:40:58 +0000 (17:40 +0100)]
cheri: malloc: Capability narrowing using internal lookup table
Add more cap_ hooks to implement narrowing without depending on a
global capability covering the heap. Either recording every
narrowed capability in a lookup table or recording every mapping
used for the heap are supported. The morello implmentation uses
a lookup table for now.
The lookup table adds memory overhead, failure paths and locks.
Recording and removing entries from the lookup table must be done
carefully in realloc so on failure the old pointer is usable and
on success the old pointer is immediately reusable concurrently.
The locks require fork hooks so malloc works in multi-threaded
fork child.
Szabolcs Nagy [Wed, 21 Sep 2022 14:32:34 +0000 (15:32 +0100)]
cheri: malloc: Initial capability narrowing support
Public interfaces return pointers with narrow bounds, this internally
requires bumping the size and alignment requirement of allocations so
the bounds are representible.
When pointers with narrow bounds need to be turned back to have wide
bounds (free, realloc), the pointer is rederived from DDC. (So this
patch relies on DDC to cover all heap memory with RW permission.)
Allocations above the mmap threshold waste memory for alignment and
realloc often falls back to the inefficient alloc, copy, free sequence
instead of mremap or other inplace solution.
Szabolcs Nagy [Mon, 3 Oct 2022 10:58:09 +0000 (11:58 +0100)]
malloc: Don't use __libc_free for tcache cleanup
__libc_free must only be used for memory given out by __libc_malloc
and similar public apis, but tcache stores a cache of already freed
pointers and itself is allocated using internal malloc apis. Strong
double free detection in __libc_free breaks tcache_thread_shutdown,
so use a cut down version of free to reset tcache entries.
Szabolcs Nagy [Wed, 14 Sep 2022 13:04:18 +0000 (14:04 +0100)]
cheri: elf: make sure dlpi_phdr covers the load segments
In dl_iterate_phdr phdr is the only capability passed to the callback
that may be used to derive pointers of the elf module, so ensure it
has wide bounds.
Szabolcs Nagy [Wed, 14 Sep 2022 10:25:55 +0000 (11:25 +0100)]
aarch64: morello: add dl-r_debug.h
Used internally for r_debug tests, but with the assumption that
the return value can be dereferenced, so change the prototype
and return a valid capability.
Also used in pldd, where we only support purecap abi processes.
Szabolcs Nagy [Wed, 7 Sep 2022 16:37:38 +0000 (17:37 +0100)]
TODO(api): cheri: fix dl_iterate_phdr dlpi_addr
The dlpi_addr field is a capability that has value l_addr, but we can
only do this for libraries (ET_DYN) where l_addr == l_map_start,
otherwise we return l_addr which is normally 0 then (ET_EXEC) so the
caller can detect and special case it.
For now l_addr != 0 and l_addr != l_map_start case is not supported.
Note: this api may be used by the unwinder to find and read .eh_frame
data.
TODO: dlpi_addr could be address only, but requires unwinder update
and agreement about the abi.
Szabolcs Nagy [Wed, 7 Sep 2022 13:17:46 +0000 (14:17 +0100)]
aarch64: morello: elf: Return bounded pointer in __tls_get_addr
There is no traditional TLS support in morello that would explicitly
call __tls_get_addr, but the libc uses it internally and the returned
pointer escapes to user code. So bound the pointers according to
the tls symbol size instead of doing so in each caller.
Szabolcs Nagy [Tue, 6 Sep 2022 08:08:25 +0000 (09:08 +0100)]
cheri: fix SYMBOL_ADDRESS to return RX derived pointer
All symbol addresses can be derived from the RX capability of the
module (l_map_start). For RW object symbols pointer will have to
be rederived from l_rw_start.
Szabolcs Nagy [Fri, 2 Sep 2022 13:07:06 +0000 (14:07 +0100)]
cheri: elf: Use RW permissions for l_ld when needed
The dynamic section of an executable needs to be written to set the
DT_DEBUG entry for debuggers (unless the target has some other place
to store r_debug). For this reason we make l_ld writable whenever
the dynamic section is writable.
The ld.so l_ld is kept RX, since it does not have DT_DEBUG.
(Note: relocating the dynamic section is not allowed on cheri and
that's the only other reason glibc would write to it.)
Szabolcs Nagy [Thu, 1 Sep 2022 08:45:30 +0000 (09:45 +0100)]
cheri: elf: Setup per module RX and RW capabilities
The l_map_start and l_rw_start of the ld.so and exe comes from the auxv
since they are normally mapped by the kernel. Some generic code had to
be modified so l_map_start is propagated and not overwritten when it is
recomputed.
The l_rw_range should exclude the relro region, but in libc.so and
ld.so this does not work: symbols are accessed before relro is applied
and then the permission should be writable.
Szabolcs Nagy [Mon, 8 Aug 2022 08:22:44 +0000 (09:22 +0100)]
cheri: elf: add an RW capability to link_map
For each module keep an RX and an RW root capability. Use the existing
l_map_start for RX (covering all load segments) and add l_rw_start for
RW (covering all writable load segments).
For relocation processing, we also need individual RW ranges to decide
which objects need to be derived from RW and RX capabilities. In
practice most modules have exactly one RW segment and it's unlikely
that any module needs more than four distinct ranges to tightly cover
the RW mappings.
Only added on CHERI targets so always has to be used behind ifdef.
Szabolcs Nagy [Tue, 6 Sep 2022 07:40:52 +0000 (08:40 +0100)]
cheri: elf: make l_entry a capability
Previously the entry address was fixed up to be a capability before
using it so l_entry could be ElfW(Addr), but the code is simpler and
more consistent if l_entry is a capability throughout:
The AT_ENTRY auxv entry is specified to be a capability and a number
if internal l_entry usage is simpler if it is elfptr_t.
When printing numbers the alloca buffer size did not consider the
optional width parameter for padding. The width is used e.g. by
_dl_map_object_from_fd which passes '(int) sizeof (void *) * 2'
which can be larger than the buffer size on systems where
sizeof (void *) >= 2 * sizeof (unsigned long). But even if large
width is not used currently it is better to handle it to avoid
surprises.
Szabolcs Nagy [Tue, 11 Oct 2022 13:57:16 +0000 (14:57 +0100)]
Fix missing NUL terminator in stdio-common/scanf13 test
sscanf is only defined on nul terminated string input, but '\0' was
missing in this test which caused _IO_str_init_static_internal to
read OOB on the stack when computing the bounds of the string.
Szabolcs Nagy [Tue, 11 Oct 2022 12:23:25 +0000 (13:23 +0100)]
Fix malloc/tst-scratch_buffer
The test used scratch_buffer_dupfree incorrectly:
- The passed in size must be <= buf.length.
- Must be called at most once on a buf object since it frees it.
- After it is called buf.data and buf.length must not be accessed.
All of these were violated, the test happened to work because the
buffer was on the stack, which meant the test copied out-of-bounds
bytes from the stack into a new buffer and then compared those bytes.
Szabolcs Nagy [Mon, 26 Sep 2022 14:38:19 +0000 (15:38 +0100)]
Fix off-by-one error in iconv/tst-iconv-mt
The iconv buffer sizes must not include the \0 string terminator.
(When \0 cannot be part of a valid character encoding glibc iconv
would copy it to the output as expected, but then later the explicit
output termination with *outbufpos = '\0' is out of bounds.)
This is needed now to avoid referencing abort in ld.so.
TODO: Fixing shared library profiling for capabilities requires
type fixes so capabilities are not stored into shared memory
(maybe purecap layout can match the lp64 one and then no file format
and external tooling change is required.)
TODO: Proper fix also depends on _dl_runtime_profile plt entry
TODO(pldd): cheri: elf: fix pldd to compile for purecap abi
Adjust types in the E(*) structs to support capabilities.
TODO: purecap pldd should refuse to deal with lp64 and ELF32 processes.
the code for the 32bit case should be disabled.
TODO: a correct fix requires support for all abis that can run on the
same system (purecap, lp64 and ELF32 too).
* address: Virtual address of capability displayed as a hexadecimal
value with a 0x prefix.
* permissions: Zero or more of the following characters:
r: LOAD permission
w: STORE permission
x: EXECUTE permission
R: LOAD_CAP permission
W: STORE_CAP permission
E: EXECUTIVE permission (Morello only)
* base: Lower bound of capability displayed as a hexadecimal value
with a 0x prefix.
* top: Upper bound of capability plus 1 displayed as a hexadecimal
value with a 0x prefix.
* attr: Zero or more of the following comma-separated attributes. If
none of the attributes are present, this field is omitted (along
with the enclosing parentheses/brackets).
invalid: Capability's tag is clear.
sentry: Capability is a sealed entry.
sealed: Capability is sealed with a type other than the sealed
entry object type.
A %p option in printf will display the capability value (address) normally.
Szabolcs Nagy [Tue, 19 Apr 2022 14:18:56 +0000 (15:18 +0100)]
TODO(morello): cheri: fix posix timers
We need to distinguish timerids that are small integers returned by
the kernel and timerids that are pointers to struct timer. The existing
pointer tagging does not work for CHERI because of the pointer shift.
Simply use the top bit without shift to tag pointers. This still relies
on the top byte ignore of aarch64 (the top byte does not affect the
capability representation) and that pointers are not tagged for other
reasons (like HWASAN).
TODO: this is morello specific and does not work for generic cheri.
Szabolcs Nagy [Tue, 29 Mar 2022 14:24:38 +0000 (15:24 +0100)]
TODO(l_addr): aarch64: morello: dynamic linking support
Add morello specific dl-machine.h.
Add morello dynamic relocation processing support for purecap ABI.
Only support R_AARCH64_NONE, R_AARCH64_ABS64 and R_AARCH64_RELATIVE
dynamic relocs from the lp64 abi. This required several APIs to
change ElfW(Addr) to uintptr_t including in generic code (where
elfptr_t used to cover both traditional and capability abis).
RELATIVE and IRELATIVE relocs use a helper function to construct a
capability. Also fixed the IRELATIVE handling for static linking.
Use new machine routines on morello for load address computation so it
is a valid capability:
The ld.so load address is either AT_BASE or if it is invoked as a
command then derived from AT_PHDR or _DYNAMIC (pcc).
ELF_MACHINE_START_ADDRESS is updated to turn the ElfW(Addr) user entry
into a capability based on l_addr.
TODO: __tls_get_addr should return a bounded pointer.
(in case traditional tls is defined for morello)
note: tls_index struct that is used for trad tls is changed for morello.
(this is abi once trad tls is defined for morello)
arguably _dl_make_tlsdesc_dynamic should set up tlsinfo.ti_size too.
(but it's better to avoid changing the generic code)
TODO: use cheri auxv entries to derive ld.so capabilities, this will
require separate RW and RX base pointers instead of single l_addr.
AT_BASE will not be a capability covering ld.so.
Szabolcs Nagy [Thu, 7 Apr 2022 07:43:00 +0000 (08:43 +0100)]
TODO(l_addr): cheri: rtld: elfptr_t fixes in dl-map-segments.h
Ensure map_end is derived from map_start.
Use stricter mmap bounds when using MAP_FIXED:
c->mapend is aligned up to pagesize, but the capability representing
the mapping has bounds that are not page aligned, so use c->dataend
that is the actual end bound of the loaded segment.
TODO: l_addr of a pde is 0 but it should cover the exe.
this will have to be fixed. (and must not use morello asm)
Szabolcs Nagy [Fri, 15 Jul 2022 07:15:02 +0000 (08:15 +0100)]
aarch64: morello: fix ldconfig for purecap abi
Add purecap ld cache flag. Add the purecap ld.so name to known names.
Handle lib64c system library paths. And set the purecap abi flag on
cache entries.
Adjust ucontext layout for purecap ABI and add make/get/set/swapcontext
implementations accordingly.
Note: mcontext layout follows the linux sigcontext struct, in userspace
*context functions rely on the c registers stored in the extension area
and ignore the mcontext fields for x registers.
Szabolcs Nagy [Mon, 28 Mar 2022 12:57:10 +0000 (13:57 +0100)]
cheri: malloc: avoid switch over uintptr_t
We should use a type that guarantees to represent all address bits.
In CHERI C this would be ptraddr_t, but we use unsigned long for now
not to cause regressions on other targets where this type is missing.