poppler¶
poppler is code extracted from the venerable Xpdf PDF viewer and made available as a general-purpose library. It has numerous reverse dependencies, including Evince/Atril and Inkscape, and Debian’s Xpdf itself (really xpopple).
poppler builds multiple libraries (-glib/-qtN/-gir/-cpp/….so.X), and the fast-changing libpoppler.so.XX. libpoppler.so.XX exposes the internal API, and its soname bumps at every release, hence with it has no backward-compatibility.
Packages relying on the private API build-depend on libpoppler-private-dev and directly depend on libpopplerXX. CVE fixes often change the function signatures of libpopplerXX hence break ABI, so testing direct reverse dependencies is crucial when updating poppler. See for instance #1104287. Rebuilding them may be necessary, if they actually use the modified subset of the internal API.
Code using the previous API will fail when using the changed function (not on start-up):
$ /usr/lib/boomaga/boomagamerger helloworld.pdf 0 0 out.pdf
/usr/lib/boomaga/boomagamerger: symbol lookup error: /usr/lib/boomaga/boomagamerger: undefined symbol: _ZN6PDFDoc15markPageObjectsEP4DictP4XRefS3_jii
Overview of private API usage (#include <poppler/InternalHeader.h>
or #include <InternalHeader.h>
); not exhaustive as some internal
headers import others:
apt-rdepends -r libpopplerXX | head -40
$EDITOR rdeps.txt # copy/paste direct deps lines (1st section)
apt source $(awk '{print $3}' rdeps.txt | grep -v ^libpoppler)
for i in */; do
echo
echo "- $i"
grep -hrwP "#include .(poppler/)?($(cd /usr/include/poppler/ && ls | grep -vP '^(qt.|glib|cpp)' | tr '\n' '|' | sed 's/|$//'))" $i | sort -u
done
You can look for specific functions in the source code, e.g. for CVE-2017-7515:
grep -rE 'markPageObjects|markAnnotations|writeObject|markDictionnary|markObject|writeDictionnary' rdeps/
Identifying imported symbols in binaries is possible, but those are usually split between all dynamic executables and libraries, and it’s easy to miss occurrences:
nm -D /usr/bin/boomaga | c++filt | grep writeObject # nothing (stretch)
objdump -T /usr/bin/boomaga | c++filt | grep writeObject # nothing (stretch)
nm -D /usr/lib/boomaga/boomagamerger | c++filt | grep writeObject # match (stretch)
objdump -T /usr/lib/boomaga/boomagamerger | c++filt | grep writeObject # match (stretch)
nm -D /usr/bin/inkscape | c++filt | grep getNumPages # nothing (buster)
nm -D /usr/lib/inkscape/libinkscape_base.so | c++filt | grep getNumPages # match (buster)
nm -D /usr/lib/x86_64-linux-gnu/inkscape/libinkscape_base.so | c++filt | grep getNumPages # match (bullseye)
Some work-arounds are available to maintain a matching function signature, but often it’s easier and safer to just identify and rebuild the reverse dependencies.
Test data¶
You can enable additional Qt tests by cloning the poppler data in the source’s parent directory:
git clone git://git.freedesktop.org/git/poppler/test
cd poppler-xxx/
debuild
export ASAN_OPTIONS=detect_leaks=0 # if testing an ASan build
cd obj-x86_64-linux-gnu/ # buster
make test
make check # stretch
# check_strings currently broken, work-around
make check -k
find qt*/tests/check* -executable | while read test; do $test || break; done
It would be nice to package this somehow.