_dl_discover_osversion: clamp parts to 255

Message ID 20220215231052.3378121-1-aurelien@aurel32.net
State Superseded
Headers
Series _dl_discover_osversion: clamp parts to 255 |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

Aurelien Jarno Feb. 15, 2022, 11:10 p.m. UTC
  Some stable Linux kernels have a lowest version part greater than 255,
and _dl_discover_osversion returns the wrong version for them as it uses
only 8 bits per part (just like LINUX_VERSION_CODE). For instance kernel
version 4.4.268 is reported as 0x4050c, ie 4.5.12. Kernel version
4.14.266 is reported as 4.15.10. The 4.9 and 4.19 branches are not
affected at this stage as the lower bit of the second part is already
set.

Fix that by clamping the parts to 255. This is fine given that the GNU
libc requires at least a kernel in version 3.2, and since kernel version
3.x.y the third part is not meaningful anymore from the GNU libc point
of view.
---
 sysdeps/unix/sysv/linux/dl-sysdep.c | 4 ++++
 1 file changed, 4 insertions(+)
  

Comments

Florian Weimer Feb. 16, 2022, 6:35 a.m. UTC | #1
* Aurelien Jarno:

> Some stable Linux kernels have a lowest version part greater than 255,
> and _dl_discover_osversion returns the wrong version for them as it uses
> only 8 bits per part (just like LINUX_VERSION_CODE). For instance kernel
> version 4.4.268 is reported as 0x4050c, ie 4.5.12. Kernel version
> 4.14.266 is reported as 4.15.10. The 4.9 and 4.19 branches are not
> affected at this stage as the lower bit of the second part is already
> set.
>
> Fix that by clamping the parts to 255. This is fine given that the GNU
> libc requires at least a kernel in version 3.2, and since kernel version
> 3.x.y the third part is not meaningful anymore from the GNU libc point
> of view.
> ---
>  sysdeps/unix/sysv/linux/dl-sysdep.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
> index 8ad72c4b7b..1be3867226 100644
> --- a/sysdeps/unix/sysv/linux/dl-sysdep.c
> +++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
> @@ -379,6 +379,10 @@ _dl_discover_osversion (void)
>  	  here += *cp++ - '0';
>  	}
>  
> +      /* Clamp parts to 255 as they are later saved using 8 bits only.  */
> +      if (here > 255)
> +	here = 255;
> +
>        ++parts;
>        version <<= 8;
>        version |= here;

I wonder if we should just remove the version checks, including the one
for NT_GNU_ABI_TAG.  The latter has had serious impact on Qt users even
without this particular problem.

Thanks,
Florian
  
Adhemerval Zanella Feb. 16, 2022, 12:58 p.m. UTC | #2
On 16/02/2022 03:35, Florian Weimer via Libc-alpha wrote:
> * Aurelien Jarno:
> 
>> Some stable Linux kernels have a lowest version part greater than 255,
>> and _dl_discover_osversion returns the wrong version for them as it uses
>> only 8 bits per part (just like LINUX_VERSION_CODE). For instance kernel
>> version 4.4.268 is reported as 0x4050c, ie 4.5.12. Kernel version
>> 4.14.266 is reported as 4.15.10. The 4.9 and 4.19 branches are not
>> affected at this stage as the lower bit of the second part is already
>> set.
>>
>> Fix that by clamping the parts to 255. This is fine given that the GNU
>> libc requires at least a kernel in version 3.2, and since kernel version
>> 3.x.y the third part is not meaningful anymore from the GNU libc point
>> of view.
>> ---
>>  sysdeps/unix/sysv/linux/dl-sysdep.c | 4 ++++
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
>> index 8ad72c4b7b..1be3867226 100644
>> --- a/sysdeps/unix/sysv/linux/dl-sysdep.c
>> +++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
>> @@ -379,6 +379,10 @@ _dl_discover_osversion (void)
>>  	  here += *cp++ - '0';
>>  	}
>>  
>> +      /* Clamp parts to 255 as they are later saved using 8 bits only.  */
>> +      if (here > 255)
>> +	here = 255;
>> +
>>        ++parts;
>>        version <<= 8;
>>        version |= here;
> 
> I wonder if we should just remove the version checks, including the one
> for NT_GNU_ABI_TAG.  The latter has had serious impact on Qt users even
> without this particular problem.

I agree, I think we can also print the minimum kernel version when executing
libc.so (to show the information similar to what 'file' tool does).
  

Patch

diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
index 8ad72c4b7b..1be3867226 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.c
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
@@ -379,6 +379,10 @@  _dl_discover_osversion (void)
 	  here += *cp++ - '0';
 	}
 
+      /* Clamp parts to 255 as they are later saved using 8 bits only.  */
+      if (here > 255)
+	here = 255;
+
       ++parts;
       version <<= 8;
       version |= here;