From 488245ed6c0c5db282ec7fed646e8bc00ce0d487 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 25 May 2022 15:44:03 +0100 Subject: [PATCH] daemon: rpm: Check return values from librpm calls We previously didn't bother to check the return values from any librpm calls. In some cases where possibly the RPM database is faulty, this caused us to return a zero-length list of installed applications (but no error indication). One way to reproduce this is given below. Note this reproducer will only work when run on a RHEL 8 host (or more specifically, with rpm <= 4.16): $ virt-builder fedora-28 $ guestfish -a fedora-28.img -i rm /var/lib/rpm/Packages $ guestfish --ro -a fedora-28.img -i inspect-list-applications /dev/sda4 -vx ... chroot: /sysroot: running 'librpm' error: cannot open Packages index using db5 - Read-only file system (30) error: cannot open Packages database in error: cannot open Packages index using db5 - Read-only file system (30) error: cannot open Packages database in librpm returned 0 installed packages ... With this commit we get an error instead: ... chroot: /sysroot: running 'librpm' error: cannot open Packages index using db5 - Read-only file system (30) error: cannot open Packages database in ocaml_exn: 'internal_list_rpm_applications' raised 'Failure' exception guestfsd: error: rpmtsInitIterator guestfsd: => internal_list_rpm_applications (0x1fe) took 0.01 secs libguestfs: trace: internal_list_rpm_applications = NULL (error) libguestfs: error: internal_list_rpm_applications: rpmtsInitIterator libguestfs: trace: inspect_list_applications2 = NULL (error) libguestfs: trace: inspect_list_applications = NULL (error) ... Not in this case, but in some cases of corrupt RPM databases it is possible to recover them by running "rpmdb --rebuilddb" as a guest command (ie. with guestfs_sh). See-also: https://bugzilla.redhat.com/show_bug.cgi?id=2089623#c12 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2089623 Fixes: commit c9ee831affed55abe0f928134cbbd2ed83b2f510 Reported-by: Xiaodai Wang Reported-by: Ming Xie Acked-by: Laszlo Ersek --- daemon/rpm-c.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/daemon/rpm-c.c b/daemon/rpm-c.c index 74d325a17..2cb50a62d 100644 --- a/daemon/rpm-c.c +++ b/daemon/rpm-c.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -79,7 +80,14 @@ value guestfs_int_daemon_rpm_init (value unitv) { CAMLparam1 (unitv); - rpmReadConfigFiles (NULL, NULL); + + /* Nothing in actual RPM C code bothers to check if this call + * succeeds, so using that as an example, just print a debug message + * if it failed, but continue. (The librpm Python bindings do check) + */ + if (rpmReadConfigFiles (NULL, NULL) == -1) + fprintf (stderr, "rpmReadConfigFiles: failed, errno=%d\n", errno); + CAMLreturn (Val_unit); } @@ -92,6 +100,8 @@ guestfs_int_daemon_rpm_start_iterator (value unitv) CAMLparam1 (unitv); ts = rpmtsCreate (); + if (ts == NULL) + caml_failwith ("rpmtsCreate"); #ifdef RPMVSF_MASK_NOSIGNATURES /* Disable signature checking (RHBZ#2064182). */ @@ -99,6 +109,14 @@ guestfs_int_daemon_rpm_start_iterator (value unitv) #endif iter = rpmtsInitIterator (ts, RPMDBI_PACKAGES, NULL, 0); + /* This could return NULL in theory if there are no packages, but + * that could not happen in a real guest. However it also returns + * NULL when unable to open the database (RHBZ#2089623) which is + * something we do need to detect. + */ + if (iter == NULL) + caml_failwith ("rpmtsInitIterator"); + CAMLreturn (Val_unit); }