Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 Jan 2022 13:44:44 +0100
From:      Stefan Esser <se@FreeBSD.org>
To:        =?UTF-8?Q?Jan_Kokem=c3=bcller?= <jan.kokemueller@gmail.com>, Mark Millard <marklmi@yahoo.com>
Cc:        bugs@openbsd.org, freebsd-current <freebsd-current@freebsd.org>, Baptiste Daroussin <bapt@FreeBSD.org>
Subject:   Re: UBSAN report for main [so: 14] /usr/bin/whatis: non-zero (48) and zero offsets from null pointer in qsort.c
Message-ID:  <b38c57e4-554d-dd46-dbfd-2ea961fe45b4@FreeBSD.org>
In-Reply-To: <80e1f514-c0b3-cf79-ea6f-8c62cb1db386@gmail.com>
References:  <A4577E70-AB32-450F-A3F6-A2B42B09A1B3.ref@yahoo.com> <A4577E70-AB32-450F-A3F6-A2B42B09A1B3@yahoo.com> <35333abc-9d4a-4b78-586d-1e869df4f9d4@FreeBSD.org> <BEFB4665-F32B-4AA0-BE4A-5ABB8B973012@yahoo.com> <7babd754-6dab-223a-7bfd-ff06f10c71e2@FreeBSD.org> <80e1f514-c0b3-cf79-ea6f-8c62cb1db386@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--------------bRIpNhbcXHLAE6JIYyS9A76J
Content-Type: multipart/mixed; boundary="------------sWzOcjTR2UPOZjVfWKWfqCl2";
 protected-headers="v1"
From: Stefan Esser <se@FreeBSD.org>
To: =?UTF-8?Q?Jan_Kokem=c3=bcller?= <jan.kokemueller@gmail.com>,
 Mark Millard <marklmi@yahoo.com>
Cc: bugs@openbsd.org, freebsd-current <freebsd-current@freebsd.org>,
 Baptiste Daroussin <bapt@FreeBSD.org>
Message-ID: <b38c57e4-554d-dd46-dbfd-2ea961fe45b4@FreeBSD.org>
Subject: Re: UBSAN report for main [so: 14] /usr/bin/whatis: non-zero (48) and
 zero offsets from null pointer in qsort.c
References: <A4577E70-AB32-450F-A3F6-A2B42B09A1B3.ref@yahoo.com>
 <A4577E70-AB32-450F-A3F6-A2B42B09A1B3@yahoo.com>
 <35333abc-9d4a-4b78-586d-1e869df4f9d4@FreeBSD.org>
 <BEFB4665-F32B-4AA0-BE4A-5ABB8B973012@yahoo.com>
 <7babd754-6dab-223a-7bfd-ff06f10c71e2@FreeBSD.org>
 <80e1f514-c0b3-cf79-ea6f-8c62cb1db386@gmail.com>
In-Reply-To: <80e1f514-c0b3-cf79-ea6f-8c62cb1db386@gmail.com>

--------------sWzOcjTR2UPOZjVfWKWfqCl2
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Am 12.01.22 um 08:50 schrieb Jan Kokem=C3=BCller:
> On 11.01.22 22:08, Stefan Esser wrote:
>> diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
>> index 5016fff7895f..51c41e802330 100644
>> --- a/lib/libc/stdlib/qsort.c
>> +++ b/lib/libc/stdlib/qsort.c
>> @@ -108,6 +108,8 @@ local_qsort(void *a, size_t n, size_t es, cmp_t *c=
mp, void
>> *thunk)
>>  	int cmp_result;
>>  	int swap_cnt;
>>
>> +	if (__predict_false(a =3D=3D NULL))
>> +		return;
>>  loop:
>>  	swap_cnt =3D 0;
>>  	if (n < 7) {
>>
>> This would also work to prevent the NULL pointer arithmetik for
>> ports that might also path a =3D=3D NULL and n =3D=3D 0 in certain cas=
es.
>=20
> The UB happens in this line, when "a =3D=3D NULL" and "n =3D=3D 0", rig=
ht?
>=20
>     for (pm =3D (char *)a + es; pm < (char *)a + n * es; pm +=3D es)
>=20
> This is arithmetic on a pointer (the NULL pointer) which is not part of=
 an
> array, which is UB.

Yes.

> Then, wouldn't "if (__predict_false(n =3D=3D 0))" be more appropriate t=
han checking
> for "a =3D=3D NULL" here? Testing for "a =3D=3D NULL" might suppress UB=
SAN warnings of
> valid bugs, i.e. when "qsort" is called with "a =3D=3D NULL" and "n !=3D=
 0". In that
> case UBSAN _should_ trigger.

Yes, but not only UBSAN would trigger, the program would probably
crash due to an attempt to access an unmapped page.

> UBSAN should not trigger when n =3D=3D 0, though. At least, when "a" do=
es point to
> a valid array. But what about the case of "a =3D=3D NULL && n =3D=3D 0"=
? Is that deemed
> UB? It looks like at least FreeBSD's "qsort_s" implementation says it's=
 legal.

This might be legal, but it leads to adding the element size to a
NULL pointer, in the current implementation. The addition happens
in the initialization part of the for loop, before n =3D=3D 0 leads to
no actual iteration being performed (a + es < a + n * es is false
for es > 0).

There is no functional difference if the case of a =3D=3D NULL and
n =3D=3D 0 is silently ignored.

But your are correct: just returning early for a =3D=3D NULL and n !=3D 0=

will prevent the program abort.

> a !=3D NULL (pointing to valid array), n !=3D 0  ->  "normal" case, no =
UB
> a !=3D NULL (pointing to valid array), n =3D=3D 0  ->  should not trigg=
er UB, and
>                                                  doesn't in the current=

>                                                  implementation

It does trigger UB in a way that does not cause issues (or else
the problem would have been detected before). a =3D=3D NULL makes the
calculation of pm =3D (char *)a + es undefined, but the value of pm
will never be used if n =3D=3D 0.

> a =3D=3D NULL, n =3D=3D 0                            ->  should not tri=
gger UB?
>                                                  (debatable)
>=20
> So if "a =3D=3D NULL && n =3D=3D 0" was deemed legal, then there would =
be no bug in
> "mansearch.c", right?

IMHO it is not the question of "legal" or not, but we should prevent
the undefined behavior that results from execution reaching the
initialization part of the for loop.

Any you are correct, the patch should probably be:

diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
index 5016fff7895f..eef51d2dd3b3 100644
--- a/lib/libc/stdlib/qsort.c
+++ b/lib/libc/stdlib/qsort.c
@@ -108,6 +108,8 @@
 	int cmp_result;
 	int swap_cnt;

+	if (__predict_false(a =3D=3D NULL && n =3D=3D 0))
+		return;
 loop:
 	swap_cnt =3D 0;
 	if (n < 7) {

This will be detected by UBSAN if called with a =3D=3D NULL and n !=3D 0,=

but it will also cause the program to fail with typical parameters
for the elements to sort and the cmp function.

Regards, STefan

PS: I just saw Mark's reply regarding n =3D=3D 0 and cmp =3D=3D NULL. Tha=
t
    case is already covered, since n =3D=3D 0 will prevent cmp from
    being dereferenced (since that only happens in the loop body,
    which will not be entered for n =3D=3D 0).

--------------sWzOcjTR2UPOZjVfWKWfqCl2--

--------------bRIpNhbcXHLAE6JIYyS9A76J
Content-Type: application/pgp-signature; name="OpenPGP_signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="OpenPGP_signature"

-----BEGIN PGP SIGNATURE-----

wsB5BAABCAAjFiEEo3HqZZwL7MgrcVMTR+u171r99UQFAmHezTwFAwAAAAAACgkQR+u171r99USs
0ggAjg4TpVg6CHmFOCQpOHEtDapGG74qMzORO3AEBbCl5oZfXeYwds8c7AnOGbF2pjwGYg1xqFFU
sLXZTzUG5E/MtJCPF9x5KqovxwloqeCBwfJqafRRhlWBx4qiKBC3eVAr322zeWJKHDU7oIc5kNQk
ocPN5yAtSPu59YB5vxWUuVoM5wyOCwjCIB9HfMV05ziuQF2Z6ih6KBtVfAcgDEMXsk/hIYUyQFMM
oOe1ksqvx1MSwrHiU6NH9i7YSjQbgh80K2Dt25Mu5yVkU5yf7nVvxntJsG5vxOFaeM4NVNLKOeMN
gwTiVZymYs4jue0HsjnK/FaEJLlye+y8RP+k2KP8sw==
=WBax
-----END PGP SIGNATURE-----

--------------bRIpNhbcXHLAE6JIYyS9A76J--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b38c57e4-554d-dd46-dbfd-2ea961fe45b4>