ShlibvisibilityChecker es una pequeña herramienta que localiza símbolos internos que se exportan innecesariamente desde bibliotecas compartidas. Tales símbolos son indeseables porque causan
--gc-sections ) ShlibvisibilityChecker compara API declaradas en encabezados públicos contra API exportadas de bibliotecas compartidas y advierte sobre las discrepancias. En la mayoría de los casos, tales símbolos son símbolos de la biblioteca interna que deben ocultarse (en casos raros, estos son símbolos internos que utilizan otras bibliotecas o ejecutables en el mismo paquete y shlibvischeck-debian intenta no informar tales casos).
Dichas discrepancias deben solucionarse recompiendo el paquete con -fvisibility=hidden (ver aquí para más detalles). Una solución típica, para un proyecto de autoconf típico, se puede encontrar aquí.
ShlibvisibilityChecker no está destinado a ser 100% preciso, sino que brinda asistencia para localizar paquetes que pueden beneficiarse más de las anotaciones de visibilidad (y comprender cuán mala es la situación con la visibilidad en las distribuciones modernas).
Para verificar un paquete en bruto, es decir, un montón de encabezados y librios compartidos, recolectar interfaces de origen e binarias y compararlos:
$ bin/read_header_api --only-args /usr/include/xcb/* > api.txt
$ ./read_binary_api --permissive /usr/lib/x86_64-linux-gnu/libxcb*.so > abi.txt
$ vimdiff api.txt abi.txt # Or `comm -13 api.txt abi.txt'
Otro escenario útil es localizar símbolos que se exportan de las bibliotecas compartidas del paquete de Debian, pero no se declaran en sus encabezados. La herramienta principal para esto es un script shlibvischeck-debian .
Para aplicarlo a un paquete, ejecute
$ shlibvischeck-debian libacl1
The following exported symbols in package 'libacl1' are private:
__acl_extended_file
__acl_from_xattr
__acl_to_xattr
__bss_start
_edata
_end
_fini
_init
closed
head
high_water_alloc
next_line
num_dir_handles
walk_tree
Para omitir símbolos autogéneados como _init o _edata (causado por scripts de enlazador LD y archivos de inicio de libgcc) Agregar --permissive .
También puede verificar los problemas de visibilidad en el conjunto arbitrario de encabezados y bibliotecas:
$ shlibvischeck-common --permissive --cflags="-I/usr/include -I$AUDIT_INSTALL/include -I/usr/lib/llvm-5.0/lib/clang/5.0.0/include" $AUDIT_INSTALL/include/*.h $AUDIT_INSTALL/lib/*.so*
Los requisitos previos del tiempo de construcción son python3 (módulo setuptools ), clang , llvm , libclang-dev , g++ y make . Las dependencias en tiempo de ejecución son python3 (módulo python-magic ), pkg-config y aptitude . Para instalar todo en Ubuntu, ejecute
$ sudo apt-get install python3 clang llvm libclang-dev g++ make pkg-config aptitude
$ sudo python3 -mensurepip
$ sudo pip3 install setuptools python-magic
(También puede usar script scripts/install-deps.sh ).
También debe habilitar el acceso a los paquetes fuente de Ubuntu a través de
$ sudo sed -Ei 's/^# *deb-src /deb-src /' /etc/apt/sources.list
$ sudo apt-get update
Python y los componentes binarios se construyen por separado:
$ make clean all && make install
$ ./setup.py build && pip3 install .
Durante el análisis, shlibvischeck-debian instala nuevos paquetes de Debian, por lo que se recomienda ejecutarlo bajo Chroot o en VM. Hay muchas instrucciones sobre la configuración de Chroot, por ejemplo, este.
Se puede obtener una lista de paquetes para el análisis de la calificación de Debian:
$ curl https://popcon.debian.org/by_vote | awk '/^[0-9]+ +lib/{print $2}' > by_vote
$ shlibvischeck-debian $(head -500 by_vote | tr 'n' ' ')
Una vez que haya encontrado un paquete problemático, puede solucionarlo restringiendo la visibilidad de los símbolos internos. La mejor manera de controlar la visibilidad del símbolo en un paquete es
-fvisibility=hidden a CFLAGS en el proyecto BuildScripts ( Makefile.in o CMakeLists.txt )__attribute__((visibility("default")))Ver Fix in Libcaca, por ejemplo.
En este momento, la herramienta solo funciona en sistemas basados en Debian (por ejemplo, Ubuntu). Esto debería estar bien ya que los buildscripts son los mismos en todas las distribuciones, por lo que detectar problemas en Ubuntu también serviría a todos los demás.
Un problema de diseño importante es que la herramienta no puede detectar símbolos que se usan indirectamente, es decir, no a través de una API sino a través de dlsym o una declaración explícita de prototipo fuera del cabeza de cabeza en el archivo fuente. Esto sucede en complementos o shlibs estrictamente interconectados dentro del mismo proyecto. Con suerte, tales casos deberían ser raros.
ShlibvisibilityChecker es una herramienta heurística, por lo que no podrá analizar todos los paquetes. La tasa de éxito actual es de alrededor del 60%. Las principales razones de los errores son
libatasmart no incluyen stddef.h y tdb no incluyen sys/types.h ).lzma/container.h )dpkg/macros.h requiere LIBDPKG_VOLATILE_API )libverto-dev usa encabezados GLIB pero no declara esto)Otros problemas:
La herramienta encontró una gran cantidad de paquetes que carecían de anotaciones de visibilidad (en la práctica, cada segundo paquete tiene exportaciones espurias). Aquí hay algunos que intenté arreglar:
Más paquetes de perspectiva (de Debian Top-100): Libpopt1, Libgpg-error0, LibXML2, Librap0, LibpCre3, LibKeyutils1, Libedit2, LiblCMS2-2.