Zuletzt aktualisiert am 21. April 2023

Spaß mit Yocto Project® "cross-prelink"

Zielsetzungen

Dieser Beitrag zeigt Ihnen, was es mit cross-prelink und dem Yocto Project® auf sich hat. Was soll es tun? Tut es das? Was sind die Probleme? Was sind die Vorteile?

Voraussetzungen

Die neueste Version des ursprünglichen Prelink-Programms ist vom 2013-05-03. Auf jeden Fall würde dies nur auf dem Host oder dem Zielsystem laufen. Es funktioniert nicht in einer Cross-Build-Umgebung wie dem Yocto Project®. Deshalb verwenden wir cross-prelink. Die letzte Änderung der verwendeten Version ist vom 2018-10-12.

Eigenschaften

Cross-prelink verspricht Laufzeit linking Optimierungen, die zu schnelleren Ladezeiten und geringerem Speicherverbrauch führen.

  • schnellere Ladezeiten
  • weniger Speicherplatzbedarf (weniger Speicherverlagerung - Kopie beim Schreiben)
  • weniger CPU-Verbrauch
  • schnellere Bootzeiten
  • weniger Stromverbrauch
  • optionale Adressraum-Layout-Randomisierung (ASLR)

Ignorieren wir ASLR von "prelink", da wir fortgeschrittenere Methoden haben, um mit ASLR umzugehen. Nach der Ausführung von "prelink" oder "cross-prelink" über eine ausführbare Datei oder eine Bibliothek wird die Größe leicht zunehmen, da ein ".gnu.prelink_undo" hinzugefügt wird. Auf diese Weise können wir alles rückgängig machen, was "prelink" tat. Behalten Sie das im Hinterkopf, denn ich werde diese Information verwenden, um festzustellen, ob "prelink" eine Binärdatei ändern konnte oder nicht.

Abgesehen von der Tatsache, dass der Code nicht gepflegt wird? Erste Tests zeigen: "cross-prelink" macht nichts Nützliches mehr. Es könnte also an der Zeit sein, es wegzuwerfen, so wie es viele andere Distros getan haben. Ein Schlüsselsatz in dem Beitrag meines Freundes Alex ist dieser: "Jüngste Tests zeigen keinen Unterschied mit und ohne ein "prelink". Und ohne einen Regressionstest ist es sehr schwer zu sagen, wann und wie das passiert ist.[0][1]" Ich mag immer eine gute Herausforderung. Vor allem, wenn jemand wie Alex sagt, dass es sehr schwer ist. Ich werde versuchen, ein bisschen tiefer zu graben und zu sehen, was da los ist.

Es gibt keinen Betreuer für "prelink". Das lässt die (Management-)Frage offen, wer einen solchen Fehler beheben wird[3]. Lassen Sie mich hier erwähnen, dass ich auch ein Problem habe. Es läuft darauf hinaus, dass "cross-prelink" die Binärdateien von Drittanbietern (grafana) zerstört. Aber meine Lösung für dieses Problem ist ganz einfach: Verwenden Sie "cross-prelink" nicht mit diesen Binärdateien.

PIE

Address Space Layout Randomization (ASLR) wurde um 2001 in den Linux-Kernel eingeführt. ASLR macht es möglich, dass bei jedem Neustart und Programmstart die Adressräume, in die das Programm geladen wird, nicht mehr vorhersehbar sind, sondern zufällig gewählt werden. Dies macht es schwieriger, Exploits zu schreiben.

Zunächst gab es den positionsunabhängigen Code (PIC). Gemeinsam genutzte Objekte ".so" wurden mit PIC erstellt. Dadurch wurde ASLR möglich, aber nur für Bibliotheken. Nicht auf die ausführbaren Dateien.

Dann gab es den PIE-Modus (position-independent executable), mit dem nicht nur Bibliotheken, sondern auch ausführbare Dateien an zufälligen Adressen im Speicher platziert werden können.

Denken Sie daran, dass der "PIE-Modus" geschaffen wurde, um ASLR zu ermöglichen.

Für weitere Einzelheiten siehe hier. Aber denken Sie daran: positionsunabhängige ausführbare Dateien sind nicht vorlinkbar. Oder mit anderen Worten: "cross-prelink" kann nicht auf Binärdateien angewendet werden, die im PIE-Modus erstellt wurden.

Das Yocto-Projekt® und der PIE-Modus

Der "PIE-Modus" wurde etwa 2017 eingeführt und ist in den Versionshinweisen von Yocto Project® 2.4 (rocko 18.0.0) (suchen Sie nach "knob"). Seitdem ist es der Standard auf den meisten Architekturen. Vier Jahre und elf Veröffentlichungen später findet es jemand heraus: "prelink" funktioniert nicht wie erwartet. Selbst in der Theorie sollte es nicht mit dem "PIE-Modus" funktionieren. Offenbar ist es den Leuten nicht wirklich wichtig, was "prelink" zu bieten hat. Hat es etwas zu bieten?

Die Unterstützung für "Prelink" wird von der Glibc ab der Version 2.36 eingestellt. Es verursacht bereits Probleme mit der Korruption von Binärdateien, hat eine Reihe von offenen Fehlern und ist von zweifelhaftem Nutzen ohne die Deaktivierung der Randomisierung von Ladeadressen und PIE-Executables. Prelink wurde von Honister (Oktober 2021) standardmäßig deaktiviert, aber die Leute konnten es immer noch benutzen. Jetzt wären wir nicht mehr in der Lage, es ohne Glibc-Unterstützung zu pflegen, also wurden die restlichen Teile entfernt. Siehe diesen Patch: [OE-core] [PATCH 1/2] prelink: Unterstützung dafür einstellen

Dies ist eine local.conf mit "prelink" aktiviert:

#
# Additional image features
#
# The following is a list of additional classes to use when building images which
# enable extra features. Some available options which can be included in this variable
# are:
#   - 'buildstats' collect build statistics
#   - 'image-mklibs' to reduce shared library files size for an image
#   - 'image-prelink' in order to prelink the filesystem image
# NOTE: if listing mklibs & prelink both, then make sure mklibs is before prelink
# NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended
USER_CLASSES += "image-prelink"

Dies ist eine local.conf mit "prelink" deaktiviert:

#
# Additional image features
#
# The following is a list of additional classes to use when building images which
# enable extra features. Some available options which can be included in this variable
# are:
#   - 'buildstats' collect build statistics
# USER_CLASSES += "image-prelink"

Nach dem Entfernen prelink-native benötigen wir auch den folgenden Patch:

author	Alexander Kanavin <alex.kanavin@gmail.com>	2022-01-27 11:20:05 +0100
committer	Richard Purdie <richard.purdie@linuxfoundation.org>	2022-02-01 07:31:18 +0000
commit	1adbf5ba2727f0023f31720e0ac7bcb2e67f039b (patch)
tree	2ddb88a41d8dd4123a68466456d7983054db6632
parent	8b562100df06f4655eb377ec259b58b10a13abee (diff)
download	poky-contrib-1adbf5ba2727f0023f31720e0ac7bcb2e67f039b.tar.gz
poky-contrib-1adbf5ba2727f0023f31720e0ac7bcb2e67f039b.tar.bz2
poky-contrib-1adbf5ba2727f0023f31720e0ac7bcb2e67f039b.zip
gobject-introspection: replace prelink-rtld with objdump -p
g-i internally processes the output with regexes, and seems
happy with what objdump is printing. It only needs to resolve
the library name as passed to the linker to the library file name.
Also recursive resolution (that ldd is doing and objdump is not)
is not necessary.

(From OE-Core rev: 767e0880d4d729e659e859dd99c1cdb084b8ba51)

Signed-off-by: Alexander Kanavin <alex@linutronix.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat
-rw-r--r--	meta/classes/gobject-introspection.bbclass	2	
-rw-r--r--	meta/recipes-gnome/gobject-introspection/gobject-introspection/0001-giscanner-ignore-error-return-codes-from-ldd-wrapper.patch	28	
-rw-r--r--	meta/recipes-gnome/gobject-introspection/gobject-introspection_1.70.0.bb	14	
3 files changed, 3 insertions, 41 deletions
diff --git a/meta/classes/gobject-introspection.bbclass b/meta/classes/gobject-introspection.bbclass
index 4db1b362d9..7bf9feb0d6 100644
--- a/meta/classes/gobject-introspection.bbclass
+++ b/meta/classes/gobject-introspection.bbclass
@@ -29,7 +29,7 @@ EXTRA_OEMESON:prepend:class-nativesdk = "${@['', '${GIRMESONBUILD}'][d.getVar('G
 
 # Generating introspection data depends on a combination of native and target
 # introspection tools, and qemu to run the target tools.
-DEPENDS:append:class-target = " gobject-introspection gobject-introspection-native qemu-native prelink-native"
+DEPENDS:append:class-target = " gobject-introspection gobject-introspection-native qemu-native"
 
 # Even though introspection is disabled on -native, gobject-introspection package is still
 # needed for m4 macros.
diff --git a/meta/recipes-gnome/gobject-introspection/gobject-introspection/0001-giscanner-ignore-error-return-codes-from-ldd-wrapper.patch b/meta/recipes-gnome/gobject-introspection/gobject-introspection/0001-giscanner-ignore-error-return-codes-from-ldd-wrapper.patch
deleted file mode 100644
index b484b5e9e6..0000000000
--- a/meta/recipes-gnome/gobject-introspection/gobject-introspection/0001-giscanner-ignore-error-return-codes-from-ldd-wrapper.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From f742da8b3913f4818d3f419117076afe62f4dbf4 Mon Sep 17 00:00:00 2001
-From: Alexander Kanavin <alex.kanavin@gmail.com>
-Date: Wed, 5 Sep 2018 16:46:52 +0200
-Subject: [PATCH] giscanner: ignore error return codes from ldd-wrapper
-
-prelink-rtld, which we use instead of ldd returns 127 when it can't find a library.
-It is not an error per se, but it breaks subprocess.check_output().
-
-Upstream-Status: Inappropriate [oe-core specific]
-Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
-
----
- giscanner/shlibs.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/giscanner/shlibs.py b/giscanner/shlibs.py
-index d67df95..80352a6 100644
---- a/giscanner/shlibs.py
-+++ b/giscanner/shlibs.py
-@@ -102,7 +102,7 @@ def _resolve_non_libtool(options, binary, libraries):
-             args.extend(['otool', '-L', binary.args[0]])
-         else:
-             args.extend(['ldd', binary.args[0]])
--        output = subprocess.check_output(args)
-+        output = subprocess.run(args, check=False, stdout=subprocess.PIPE).stdout
-         if isinstance(output, bytes):
-             output = output.decode("utf-8", "replace")
- 
diff --git a/meta/recipes-gnome/gobject-introspection/gobject-introspection_1.70.0.bb b/meta/recipes-gnome/gobject-introspection/gobject-introspection_1.70.0.bb
index d4ee03d33c..4f72a33bfa 100644
--- a/meta/recipes-gnome/gobject-introspection/gobject-introspection_1.70.0.bb
+++ b/meta/recipes-gnome/gobject-introspection/gobject-introspection_1.70.0.bb
@@ -14,7 +14,6 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=c434e8128a68bedd59b80b2ac1eb1c4a \
                     "
 
 SRC_URI = "${GNOME_MIRROR}/${BPN}/${@oe.utils.trim_version("${PV}", 2)}/${BPN}-${PV}.tar.xz \
-           file://0001-giscanner-ignore-error-return-codes-from-ldd-wrapper.patch \
            file://0001-build-Avoid-the-doctemplates-hack.patch \
            "
 
@@ -33,9 +32,7 @@ DEPENDS += " libffi zlib glib-2.0 python3 flex-native bison-native autoconf-arch
 # target build needs qemu to run temporary introspection binaries created
 # on the fly by g-ir-scanner and a native version of itself to run
 # native versions of its own tools during build.
-# Also prelink-rtld is used to find out library dependencies of introspection binaries
-# (standard ldd doesn't work when cross-compiling).
-DEPENDS:append:class-target = " gobject-introspection-native qemu-native prelink-native"
+DEPENDS:append:class-target = " gobject-introspection-native qemu-native"
 
 # needed for writing out the qemu wrapper script
 export STAGING_DIR_HOST
@@ -55,13 +52,6 @@ EXTRA_OEMESON:class-target = " \
     ${@'-Dgir_dir_prefix=${libdir}' if d.getVar('MULTILIBS') else ''} \
 "
 
-# Need to ensure ld.so.conf exists so prelink-native works
-# both before we build and if we install from sstate
-do_configure[prefuncs] += "gobject_introspection_preconfigure"
-python gobject_introspection_preconfigure () {
-    oe.utils.write_ld_so_conf(d)
-}
-
 do_configure:prepend:class-native() {
         # Tweak the native python scripts so that they don't refer to the
         # full path of native python binary (the solution is taken from glib-2.0 recipe)
@@ -113,7 +103,7 @@ EOF
         # for a different architecture
         cat > ${B}/g-ir-scanner-lddwrapper << EOF
 #!/bin/sh
-prelink-rtld --root=$STAGING_DIR_HOST "\$@"
+$OBJDUMP -p "\$@"
 EOF
         chmod +x ${B}/g-ir-scanner-lddwrapper
 

Tests

Root-Dateisysteme

Wir müssen hier vier Root-Dateisysteme erstellen:

Variante"image-prelink"PIE-Modus
prelinked-with-pie
(Standard)
jaja
no-prelink-with-piekeineja
prelinked-no-piejakeine
no-prelink-no-piekeinekeine

Die Klasse "image-prelink" kann aktiviert/deaktiviert werden, z. B. in local.conf wie hier:

# enable image-prelink
#USER_CLASSES ?= "buildstats image-prelink"
# disable image-prelink:
USER_CLASSES ?= "buildstats"

Der "PIE-Modus" ist standardmäßig aktiviert. Um ihn zu deaktivieren, habe ich etwas wie folgt gemacht:

# --> remove pie
GCCPIE = ""
GLIBCPIE = ""
SECURITY_CFLAGS_remove = "${SECURITY_PIE_CFLAGS}"
SECURITY_CFLAGS_pn-libgcc = ""
# <-- remove pie

Um festzustellen, ob Dateien im Root-Dateisystem "vorverlinkt" sind oder nicht, entpacke ich den rootfs-Tarball auf dem Host und führe dieses Skript aus:

#!/bin/sh

# That's what's in prelink.conf:

# -l /usr/local/sbin
# -l /sbin
# -l /usr/sbin
# -l /usr/local/bin
# -l /bin
# -l /usr/bin
# -l /usr/X11R6/bin
# -l /usr/games
# -l /usr/local/lib{,32,64,x32}
# -l /lib{,32,64,x32}
# -l /usr/lib{,32,64,x32}
# -l /usr/X11R6/lib{,32,64,x32}

# I assume there needs to be a prelink section to indicate that prelink was running

counter=0

if [ -f /tmp/elffiles ]; then
   rm -f /tmp/elffiles
fi

DIRS="usr/local/sbin sbin usr/sbin usr/local/bin bin usr/bin usr/X11R6/bin usr/games usr/local/lib lib usr/lib usr/X11R6/lib"

for directory in ${DIRS}; do
   if [ -d $directory ]; then
      # only do things if dir is not empty
      if [ "$(ls -A ${directory})" ]; then
         echo ">> ${directory}"
         find ${directory} -type f | xargs file | grep ELF | cut -f1 -d':' \
>> /tmp/elffiles
         echo "<< ${directory}"
      else
         echo "${directory} is empty"
      fi
   fi
done

for file in $(cat /tmp/elffiles) ; do
   #set -x
   readelf -S $file 2>/dev/null | grep -q prelink
   #set +x
   if [ $? -eq 0 ]; then
      echo "$file is prelinked"
      counter=$(($counter+1))
   fi
done

echo "${counter} files are prelinked"

prelinked-with-pie

$ ../../tests/check-prelink.sh 
>> sbin
<< sbin
>> usr/sbin
<< usr/sbin
>> bin
<< bin
>> usr/bin
<< usr/bin
usr/games is empty
>> lib
<< lib
>> usr/lib
<< usr/lib
usr/bin/grafana-cli is prelinked
usr/bin/grafana-server is prelinked
lib/libdl-2.33.so is prelinked
lib/ld-2.33.so is prelinked
lib/libpthread-2.33.so is prelinked
lib/libc-2.33.so is prelinked
6 files are prelinked

Bitte beachten Sie: "usr/bin/grafana-cli" und "usr/bin/grafana-server" sind Binärdateien von Drittanbietern. Sie werden zerstört durch "cross-prelink". Daher werden sie nicht ausgeführt, sondern geben einen Segmentierungsfehler.

$ ../../tests/check-prelink.sh 
>> sbin
<< sbin
>> usr/sbin
<< usr/sbin
>> bin
<< bin
>> usr/bin
<< usr/bin
usr/games is empty
>> lib
<< lib
>> usr/lib
<< usr/lib
0 files are prelinked

prelinked-no-pie

$ ../../tests/check-prelink.sh 
>> sbin
<< sbin
>> usr/sbin
<< usr/sbin
>> bin
<< bin
>> usr/bin
<< usr/bin
usr/games is empty
>> lib
<< lib
>> usr/lib
<< usr/lib
sbin/vipw.shadow is prelinked
sbin/fstab-decode is prelinked
sbin/mkfs.ext3 is prelinked
sbin/mkfs.ext4 is prelinked
sbin/halt.sysvinit is prelinked
sbin/mkfs.ext2.e2fsprogs is prelinked
sbin/sysctl.procps is prelinked
sbin/udevd is prelinked
sbin/nologin.shadow is prelinked
sbin/sulogin.util-linux is prelinked
sbin/init.sysvinit is prelinked
sbin/killall5 is prelinked
sbin/bootlogd is prelinked
sbin/shutdown.sysvinit is prelinked
sbin/runlevel.sysvinit is prelinked
sbin/mke2fs.e2fsprogs is prelinked
usr/sbin/chroot.coreutils is prelinked
usr/sbin/groupmod is prelinked
usr/sbin/groupadd is prelinked
usr/sbin/powerdebug is prelinked
usr/sbin/groupmems is prelinked
usr/sbin/start-stop-daemon.dpkg is prelinked
usr/sbin/grpconv is prelinked
usr/sbin/iw is prelinked
usr/sbin/avahi-daemon is prelinked
usr/sbin/lsof is prelinked
...
usr/lib/libxcb-dri2.so.0.0.0 is prelinked
usr/lib/libgio-2.0.so.0.6800.3 is prelinked
usr/lib/libxshmfence.so.1.0.0 is prelinked
usr/lib/libmicrohttpd.so.12.58.0 is prelinked
usr/lib/libprocps.so.8.0.3 is prelinked
usr/lib/libtirpc.so.3.0.0 is prelinked
usr/lib/libcairo.so.2.11600.0 is prelinked
usr/lib/libcrypt.so.2.0.0 is prelinked
usr/lib/libICE.so.6.3.0 is prelinked:
usr/lib/libperl.so.5.34.0 is prelinked
usr/lib/libxcb-sync.so.1.0.0 is prelinked
usr/lib/libunwind-arm.so.8.0.1 is prelinked
usr/lib/libxcb-present.so.0.0.0 is prelinked
usr/lib/libunwind.so.8.0.1 is prelinked
usr/lib/libXau.so.6.0.0 is prelinked
usr/lib/libpython3.9.so.1.0 is prelinked
usr/lib/libasm-0.185.so is prelinked
usr/lib/libxcb-xfixes.so.0.0.0 is prelinked
usr/lib/libreadline.so.8.1 is prelinked
usr/lib/libXcursor.so.1.0.2 is prelinked
usr/lib/libgdk-3.so.0.2404.25 is prelinked
usr/lib/libelf-0.185.so is prelinked
usr/lib/libX11.so.6.4.0 is prelinked
usr/lib/libXrandr.so.2.2.0 is prelinked
usr/lib/libglapi.so.0.0.0 is prelinked
usr/lib/libgmodule-2.0.so.0.6800.3 is prelinked
usr/lib/libatspi.so.0.0.1 is prelinked
usr/lib/libbfd-2.36.1.20210209.so is prelinked
usr/lib/libopcodes-2.36.1.20210209.so is prelinked
usr/lib/libdaemon.so.0.5.0 is prelinked
usr/lib/libXft.so.2.3.3 is prelinked
usr/lib/libxml2.so.2.9.12 is prelinked
usr/lib/libctf.so.0.0.0 is prelinked
usr/lib/libatk-bridge-2.0.so.0.0.0 is prelinked
usr/lib/libgtk-3.so.0.2404.25 is prelinked
usr/lib/libdw-0.185.so is prelinked
usr/lib/libXi.so.6.1.0 is prelinked
usr/lib/liblzma.so.5.2.5 is prelinked
usr/lib/libglib-2.0.so.0.6800.3 is prelinked
usr/lib/libgobject-2.0.so.0.6800.3 is prelinked
usr/lib/libsolv.so.1 is prelinked
usr/lib/libcairo-gobject.so.2.11600.0 is prelinked
usr/lib/libell.so.0.0.2 is prelinked
473 files are prelinked
$ ../../tests/check-prelink.sh 
>> sbin
<< sbin
>> usr/sbin
<< usr/sbin
>> bin
<< bin
>> usr/bin
<< usr/bin
usr/games is empty
>> lib
<< lib
>> usr/lib
<< usr/lib
0 files are prelinked

Variante"image-prelink"PIE-Modusvorverlinkte Dateien
prelinked-with-pie
(Standard)
jaja6
mindestens 2 von ihnen sind korrupt
no-prelink-with-piekeineja0
prelinked-no-piejakeine473
2 von ihnen sind korrupt
no-prelink-no-piekeinekeine0

Schlussfolgerung

In unserem speziellen Fall scheinen Theorie und Praxis übereinzustimmen. "Cross-prelink" zeigt keinen großen Unterschied, da es nicht mit Dateien arbeiten kann, die mit PIE kompiliert wurden.

Anhang

Wenn Sie erfahren möchten, wie Embedded Linux funktioniert, klicken Sie auf hier. Hier können Sie mehr über das Yocto Project® erfahren. Für einige weitere Tests und Messungen mit "cross-prelink" schauen Sie mal hier.

Kommende Veranstaltungen

Unsere 3 Punkte

der Differenzierung

Wir stellen Host- und Zielhardware für alle unsere Kurse zur Verfügung.

Drei oder mehr Personen aus demselben Unternehmen? Wir bieten maßgeschneiderte Privatschulungen an - Beratung inklusive.

Fachexperten entwickeln hochwertige, berufsbezogene, aktuelle und authentische Kursunterlagen.