Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260513133508.GB3520958@port70.net>
Date: Wed, 13 May 2026 15:35:08 +0200
From: Szabolcs Nagy <nsz@...t70.net>
To: Florian Schmaus <florian.schmaus@...asip.com>
Cc: musl@...ts.openwall.com, dalias@...c.org, tg@...bsd.de
Subject: Re: [PATCH v2] qsort: align 'tmp' buffer to preserve CHERI
 capabilities

* Florian Schmaus <florian.schmaus@...asip.com> [2026-05-13 10:21:46 +0200]:
> The cycle() function in qsort.c uses a local stack buffer 'tmp'
> to temporarily hold elements being permuted.
> 
> Under CHERI architectures, like CHERI RISC-V, pointers are represented
> as capabilities, which include an out-of-band hardware tag bit used to
> enforce memory safety. For this tag bit to be preserved when a
> capability is written to memory, the target address must be strictly
> aligned to the capability's size requirement (e.g., 16-byte aligned
> for 128-bit capabilities).
> 
> Previously, 'tmp' was declared as an 'unsigned char' array, which only
> guarantees a 1-byte alignment. If qsort is called to sort an array of
> pointers, writing these capabilities into an unaligned 'tmp' buffer
> may cause the processor to strip their validity tags (depending on
> the actual alignment at run-time). When these untagged capabilities
> are copied back out and later dereferenced, the hardware will throw a
> capability fault, crashing the program.
> 
> By changing the buffer type to a union with a pointer member we force
> the compiler to align the stack allocation to the architectural
> pointer/capability alignment boundary. This ensures that capabilities
> stored in the buffer retain their tags and remain valid.
> ---
> Changes in v2:
> - Use union to guarantee proper alignment
> 
>  src/stdlib/qsort.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
> index 28607450b885..ffd523f7cd8c 100644
> --- a/src/stdlib/qsort.c
> +++ b/src/stdlib/qsort.c
> @@ -44,7 +44,12 @@ static inline int pntz(size_t p[2]) {
>  
>  static void cycle(size_t width, unsigned char* ar[], int n)
>  {
> -	unsigned char tmp[256];
> +	/* Union forces pointer alignment to preserve CHERI capability tags */
> +	union {
> +		unsigned char c[256];
> +		void *p;
> +	} tmp_u;
> +	unsigned char *tmp = tmp_u.c;
>  	size_t l;
>  	int i;

i guess this can be part of a cheri target port patchset.

cheri c is incompatible with standard c that allows
byte-by-byte copy of pointers. in cheri memcpy this can
be worked around if dst,src,size are aligned, but musl
does not have such a memcpy.

i think without cheri target support such changes need
stronger justification: either the behaviour improves
(e.g. memcpy may work better if tmp is aligned) or the
code quality improves (e.g. makes the intention clearer).

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.