Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <agPq_e6A1cNnHgUz@mail.gmail.com>
Date: Wed, 13 May 2026 05:07:41 +0200
From: Luca Kellermann <mailto.luca.kellermann@...il.com>
To: Rich Felker <dalias@...c.org>
Cc: musl@...ts.openwall.com
Subject: Re: musl multi-level table format for binary locale images

On Tue, May 12, 2026 at 07:09:32PM -0400, Rich Felker wrote:
> [...]
> 
> The code to perform lookups is not yet merged much less hooked up to
> any test framework, but I'm attaching a draft to this email. It needs
> to be pointed at the start of the actual table (after the 16-byte file
> header).
> 
> [...]
> 
> static unsigned get32(const char *b0)
> {
> 	const unsigned char *b = (const void *)b0;
> 	return (b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3];
> }

b[0] is promoted to int before shifting so a bit is shifted into the
sign position (UB) if b[0] > 0x7f.

> const char *lookup(const char *ld, int key)
> {
> 	unsigned shift, scale, len, val, x, k = key;
> 
> 	do {
> 		k -= get32(ld);
> 		shift = ld[4];
> 		scale = ld[5];
> 		//if (shift > 31 || scale > 2) return 0;
> 		//len = (get16(ld+6)+1) << scale;
> 		len = get16(ld+6);

Here you could also check that len & ((1 << scale) - 1) == 0 to ensure
that len is a multiple of 1 << scale.

> 		x = (k>>shift) << scale;
> 		k &= (1U<<shift) - 1;
> 		if (x >= len) return 0;

If scale > shift and k > (0xffffffff >> (scale - shift)), the invalid
index would not be detected. For strerror() this would mean, for
example, that INT_MIN + 1 results in "Operation not permitted" instead
of NULL (which would presumably be replaced by "Unknown error")
because: (0x80000002>>0) << 1 == 4.

Invalid indexes should instead be detected before applying scale:

x = k>>shift;
k &= (1U<<shift) - 1;
if (x >= (len>>scale)) return 0;
x <<= scale;

> 		ld += 8;
> 		for (int i=val=0; i<(1U<<scale); i++)
> 			val = 256*val + get8(ld+x+i);
> 		if (!val) return 0;
> 		ld += len + val-1;

Because len + val-1 is evaluated as type unsigned, this will wrap
around and give an incorrect result when the sum is greater than
0xffffffff (locale file has to be unreasonably large though). A
possible fix:

ld += len;
ld += val-1;

> 	} while (shift);
> 
> 	return ld;
> }
> 
> [...]

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.