Message ID | 1449098562-9513-1-git-send-email-aurelien@aurel32.net |
---|---|
State | New |
Headers | show |
Aurelien Jarno <aurelien@aurel32.net> writes: > +static int > +convert_from_uname26 (int version) > +{ > + if ((version & 0xffff00) == 0x020600) > + { > + /* 2.6.40+x to 3.x */ > + if ((version & 0xff) >= 60) > + version += 0x020000 - 60; > + /* 2.6.60+x to 4.x */ > + else if ((version & 0xff) >= 40) > + version += 0x010000 - 40; The comments are backwards. Andreas.
On 12/03/2015 12:22 AM, Aurelien Jarno wrote: > When the kernel is running under the uname26 personality (for programs > that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and > 4.x to 2.6.60+x. When the GNU libc is configured with --enable-kernel=3.x > or 4.x and uname26 personality is enabled, binaries get abort with a > "FATAL: kernel too old message", even if the kernel actually supports > such a binary. I'm sorry, I don't think this is the correct way to handle this. The reason is that > +/* When the kernel is running under the uname26 personality (for programs > + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and > + 4.x to 2.6.60+x. We need to convert that back to the standard version > + numbering to be able to compare versions. */ > +static int > +convert_from_uname26 (int version) > +{ > + if ((version & 0xffff00) == 0x020600) > + { > + /* 2.6.40+x to 3.x */ > + if ((version & 0xff) >= 60) > + version += 0x020000 - 60; > + /* 2.6.60+x to 4.x */ > + else if ((version & 0xff) >= 40) > + version += 0x010000 - 40; > + } > + > + return version; > +} … this function will have to be changed again for Linux 5.0. A long-term solution would map the minimum required version hard-coded into libc to its 2.6 equivalent, and check that if the kernel reports a 2.6 version. This is solves the forward compatibility issue because the 2.6 mapping for the minimum version is known at the time glibc is compiled. Florian
On 2015-12-03 10:12, Florian Weimer wrote: > On 12/03/2015 12:22 AM, Aurelien Jarno wrote: > > When the kernel is running under the uname26 personality (for programs > > that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and > > 4.x to 2.6.60+x. When the GNU libc is configured with --enable-kernel=3.x > > or 4.x and uname26 personality is enabled, binaries get abort with a > > "FATAL: kernel too old message", even if the kernel actually supports > > such a binary. > > I'm sorry, I don't think this is the correct way to handle this. The > reason is that > > > +/* When the kernel is running under the uname26 personality (for programs > > + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and > > + 4.x to 2.6.60+x. We need to convert that back to the standard version > > + numbering to be able to compare versions. */ > > +static int > > +convert_from_uname26 (int version) > > +{ > > + if ((version & 0xffff00) == 0x020600) > > + { > > + /* 2.6.40+x to 3.x */ > > + if ((version & 0xff) >= 60) > > + version += 0x020000 - 60; > > + /* 2.6.60+x to 4.x */ > > + else if ((version & 0xff) >= 40) > > + version += 0x010000 - 40; > > + } > > + > > + return version; > > +} > > … this function will have to be changed again for Linux 5.0. > > A long-term solution would map the minimum required version hard-coded > into libc to its 2.6 equivalent, and check that if the kernel reports a > 2.6 version. This is solves the forward compatibility issue because the > 2.6 mapping for the minimum version is known at the time glibc is compiled. So you mean that we should have for example two defines in our code, one for the standard version and the other for the 2.6 version and that both would be defined at compilation time. Correct? That still means we need to do the conversion at compile time to be able to define both values. Aurelien
On 12/03/2015 09:32 PM, Aurelien Jarno wrote: >>> +/* When the kernel is running under the uname26 personality (for programs >>> + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and >>> + 4.x to 2.6.60+x. We need to convert that back to the standard version >>> + numbering to be able to compare versions. */ >>> +static int >>> +convert_from_uname26 (int version) >>> +{ >>> + if ((version & 0xffff00) == 0x020600) >>> + { >>> + /* 2.6.40+x to 3.x */ >>> + if ((version & 0xff) >= 60) >>> + version += 0x020000 - 60; >>> + /* 2.6.60+x to 4.x */ >>> + else if ((version & 0xff) >= 40) >>> + version += 0x010000 - 40; >>> + } >>> + >>> + return version; >>> +} >> >> … this function will have to be changed again for Linux 5.0. >> >> A long-term solution would map the minimum required version hard-coded >> into libc to its 2.6 equivalent, and check that if the kernel reports a >> 2.6 version. This is solves the forward compatibility issue because the >> 2.6 mapping for the minimum version is known at the time glibc is compiled. > > So you mean that we should have for example two defines in our code, one > for the standard version and the other for the 2.6 version and that both > would be defined at compilation time. Correct? Essentially, yes. > That still means we need to do the conversion at compile time to be able > to define both values. Or you could write the inverse function convert_from_uname26 as an inline function or macro, and apply it to the (constant) minimum version. I don't have a preference in either direction. Florian
On 2015-12-04 15:21, Florian Weimer wrote: > On 12/03/2015 09:32 PM, Aurelien Jarno wrote: > > >>> +/* When the kernel is running under the uname26 personality (for programs > >>> + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and > >>> + 4.x to 2.6.60+x. We need to convert that back to the standard version > >>> + numbering to be able to compare versions. */ > >>> +static int > >>> +convert_from_uname26 (int version) > >>> +{ > >>> + if ((version & 0xffff00) == 0x020600) > >>> + { > >>> + /* 2.6.40+x to 3.x */ > >>> + if ((version & 0xff) >= 60) > >>> + version += 0x020000 - 60; > >>> + /* 2.6.60+x to 4.x */ > >>> + else if ((version & 0xff) >= 40) > >>> + version += 0x010000 - 40; > >>> + } > >>> + > >>> + return version; > >>> +} > >> > >> … this function will have to be changed again for Linux 5.0. > >> > >> A long-term solution would map the minimum required version hard-coded > >> into libc to its 2.6 equivalent, and check that if the kernel reports a > >> 2.6 version. This is solves the forward compatibility issue because the > >> 2.6 mapping for the minimum version is known at the time glibc is compiled. > > > > So you mean that we should have for example two defines in our code, one > > for the standard version and the other for the 2.6 version and that both > > would be defined at compilation time. Correct? > > Essentially, yes. > > > That still means we need to do the conversion at compile time to be able > > to define both values. > > Or you could write the inverse function convert_from_uname26 as an > inline function or macro, and apply it to the (constant) minimum > version. I don't have a preference in either direction. But then this function will have to be changed again for Linux 5.0… Which is exactly your argument against the above code.
On 12/04/2015 06:43 AM, Aurelien Jarno wrote: > On 2015-12-04 15:21, Florian Weimer wrote: >> On 12/03/2015 09:32 PM, Aurelien Jarno wrote: >> >>>>> +/* When the kernel is running under the uname26 personality (for programs >>>>> + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and >>>>> + 4.x to 2.6.60+x. We need to convert that back to the standard version >>>>> + numbering to be able to compare versions. */ >>>>> +static int >>>>> +convert_from_uname26 (int version) >>>>> +{ >>>>> + if ((version & 0xffff00) == 0x020600) >>>>> + { >>>>> + /* 2.6.40+x to 3.x */ >>>>> + if ((version & 0xff) >= 60) >>>>> + version += 0x020000 - 60; >>>>> + /* 2.6.60+x to 4.x */ >>>>> + else if ((version & 0xff) >= 40) >>>>> + version += 0x010000 - 40; >>>>> + } >>>>> + >>>>> + return version; >>>>> +} >>>> >>>> … this function will have to be changed again for Linux 5.0. >>>> >>>> A long-term solution would map the minimum required version hard-coded >>>> into libc to its 2.6 equivalent, and check that if the kernel reports a >>>> 2.6 version. This is solves the forward compatibility issue because the >>>> 2.6 mapping for the minimum version is known at the time glibc is compiled. >>> >>> So you mean that we should have for example two defines in our code, one >>> for the standard version and the other for the 2.6 version and that both >>> would be defined at compilation time. Correct? >> >> Essentially, yes. >> >>> That still means we need to do the conversion at compile time to be able >>> to define both values. >> >> Or you could write the inverse function convert_from_uname26 as an >> inline function or macro, and apply it to the (constant) minimum >> version. I don't have a preference in either direction. > > But then this function will have to be changed again for Linux 5.0… > Which is exactly your argument against the above code. It doesn't make a difference either way, as far as I can see. One presumes that no matter what the 2.6.x version numbers will be increasing. So if the above is not updated for 5.0, it will still produce a 4.y for y larger than ever existed in the real version 4 line. So the 4.y produced by the above function will still be "newer" than any hard-coded minimum. Similarly if one works it the other way around. r~
diff --git a/ChangeLog b/ChangeLog index c7c4c25..593cfad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-12-03 Aurelien Jarno <aurel32@debian.org> + + * sysdeps/unix/sysv/linux/dl-sysdep.c (convert_from_uname26): New. + (_dl_discover_osversion): Call convert_from_uname26 before returning + the version. + 2015-12-01 H.J. Lu <hongjiu.lu@intel.com> [BZ #19313] diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c index a4c32f6..4fca8d1 100644 --- a/sysdeps/unix/sysv/linux/dl-sysdep.c +++ b/sysdeps/unix/sysv/linux/dl-sysdep.c @@ -38,6 +38,25 @@ frob_brk (void) # include <elf/dl-sysdep.c> #endif +/* When the kernel is running under the uname26 personality (for programs + that cannot handle "Linux 3.0"), it maps version 3.x to 2.6.40+x and + 4.x to 2.6.60+x. We need to convert that back to the standard version + numbering to be able to compare versions. */ +static int +convert_from_uname26 (int version) +{ + if ((version & 0xffff00) == 0x020600) + { + /* 2.6.40+x to 3.x */ + if ((version & 0xff) >= 60) + version += 0x020000 - 60; + /* 2.6.60+x to 4.x */ + else if ((version & 0xff) >= 40) + version += 0x010000 - 40; + } + + return version; +} int attribute_hidden @@ -65,8 +84,9 @@ _dl_discover_osversion (void) while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) { if (!memcmp (note, &expected_note, sizeof expected_note)) - return *(const ElfW(Word) *) ((const void *) note - + sizeof expected_note); + return convert_from_uname26( + *(const ElfW(Word) *) ((const void *) note + + sizeof expected_note)); #define ROUND(len) (((len) + sizeof note->n_type - 1) & -sizeof note->n_type) note = ((const void *) (note + 1) + ROUND (note->n_namesz) + ROUND (note->n_descsz)); @@ -128,5 +148,5 @@ _dl_discover_osversion (void) if (parts < 3) version <<= 8 * (3 - parts); - return version; + return convert_from_uname26(version); }