Home > Blockchain >  How to extract and compare the libc versions at runtime?
How to extract and compare the libc versions at runtime?

Time:02-13

How to extract and compare the libc versions at runtime with the following restrictions?

  • stable solution (commands output parsing is discarded as this may vary)
  • should not rely on executing external tools like ldd, gcc or others
  • must work on a statically linked binary (AppRun)
  • will be implemented in C

Context:

In the AppImage project have been working on a feature to allow creating backward compatible bundles. To achieve this we created a program named AppRun. Things program compares the system glibc version with the one shipped in the bundle and configures the bundle to use the newer at runtime. This program is statically linked and should not depend on external tools.

Right now we scan the libc.so file for occurrences of GLIBC_X.XX and store the greater. But this is no longer working in the latest binary include in Ubuntu 20.04. The binary is 2.31 but there are no GLIBC_2.31 strings in the file therefore the method fails.

Related issues:

CodePudding user response:

the libc versions

There are alternatives to glibc.

Right now we scan the libc.so file for occurrences of GLIBC_X.XX

Search for the string that glibc prints - GNU C Library <pkg release_name> release version <version>[,.]..., and version has format [0-9] \.[0-9] (\.[0-9] )?.

Just find libc.so.6 in /etc/ld.so.cache.

Do this in C:

libcfile="$(grep -azm1 '/libc.so.6$' /etc/ld.so.cache | tr -d '\0')"
grep -aoP 'GNU C Library [^\n]* release version \K[0-9]*.[0-9]*' "$libcfile"

Looking at commits, this should work since forever:
https://github.com/bminor/glibc/blame/b7eb84454020c59d528e826ae1889f411ed69e26/version.c#L28
https://github.com/bminor/glibc/blame/9f70e81bcaa12b0673cd0879d6f4a21ad6dddce5/version.c#L28
https://github.com/bminor/glibc/blame/92e4b6a92716f8b2457376291171a6330d072b0d/csu/version.c#L27
https://github.com/bminor/glibc/blame/50c66c7acd90f257b295e58bf938ed120cbc27c7/csu/version.c#L27
https://github.com/bminor/glibc/blame/b92a49359f33a461db080a33940d73f47c756126/csu/version.c#L27

Seems to work on the oldest ubuntu in docker I can find:

$ cmd='grep -aoP "GNU C Library [^\n]* release version \K[0-9]*.[0-9]*" "$(grep -azm1 "/libc.so.6$" /etc/ld.so.cache | tr -d "\0")"'
$ echo -n 'local: '; sh -c "$cmd"; for i in 13.04 16.04 14.04 22.04 21.10 20.04 18.04; do echo -n "ubuntu:$i "; docker run -ti --rm ubuntu:$i sh -c "$cmd"; done
local: 2.33
ubuntu:13.04 2.17
ubuntu:16.04 2.23
ubuntu:14.04 2.19
ubuntu:22.04 2.34
ubuntu:21.10 2.34
ubuntu:20.04 2.31
ubuntu:18.04 2.27

I also tested opensuse12.2 with glibc2.15, libc.so.6 prints GNU C Library stable release version 2.15 (20120628), by Roland McGrath et al. there.

CodePudding user response:

This program compares the system glibc version with the one shipped in the bundle and configures the bundle to use the newer at runtime.

Note that "configuring at runtime" involves more than just pointing the programs to the "correct" libc.so.6, as this answer explains.

Right now we scan the libc.so file for occurrences of GLIBC_X.XX and store the greater. But this is no longer working in the latest binary include in Ubuntu 20.04.

You appear to have a fundamental misunderstanding of how symbol versioning works. This answer may help understanding this better.

Your method is working.

The binary is 2.31 but there are no GLIBC_2.31 strings in the file therefore the method fails.

As above referenced answer explains, this means that GLIBC-2.31 didn't introduce any new ABI-incompatible symbols, and programs linked against that version of GLIBC will work when older GLIBC version is present at runtime (but may run into GLIBC bugs fixed between versions 2.30 and 2.31, etc.).

  • Related