From 308ac60677732e9979b9ce11e5a3085906da1901 Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Fri, 26 Jul 2024 10:44:04 +0200 Subject: [PATCH] Fix root relocation regression When relocating the root directory, make sure we insert the new path's dirname to dirNames[] even if the root itself is owned by the package. This appears to have been the intention from the first version (largely untouched since) of this code as we allow the root to pass through the first checks (by setting len to 0 in that case) as well as the second for loop where we do the relocations. This allows fsm to properly create and remove the relocated directory since we're now using fd-based calls (#1919) and the parent directory needs to be opened first. No need to do string comparison here, the empty basename signals that we're processing the root directory, so just use that. Building a relocatable package that owns the root directory seems to be a handy way to create user-installable packages (see RHEL-28967) and it happened to work before with the path-based calls so this technically was a regression. Add a test that emulates this use case. Fixes: #3173 --- lib/relocation.c | 8 +++++--- tests/data/SPECS/rootfs.spec | 17 +++++++++++++++++ tests/rpmi.at | 25 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tests/data/SPECS/rootfs.spec diff --git a/lib/relocation.c b/lib/relocation.c index d31cf47793..0202b5c461 100644 --- a/lib/relocation.c +++ b/lib/relocation.c @@ -181,8 +181,9 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations, rpmFileTypes ft; int fnlen; + size_t baselen = strlen(baseNames[i]); size_t len = maxlen + - strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1; + strlen(dirNames[dirIndexes[i]]) + baselen + 1; if (len >= fileAlloced) { fileAlloced = len * 2; fn = xrealloc(fn, fileAlloced); @@ -244,8 +245,9 @@ assert(fn != NULL); /* XXX can't happen */ continue; } - /* Relocation on full paths only, please. */ - if (fnlen != len) continue; + /* Relocation on '/' and full paths only, please. */ + if (baselen && fnlen != len) + continue; rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n", fn, relocations[j].newPath); diff --git a/tests/data/SPECS/rootfs.spec b/tests/data/SPECS/rootfs.spec new file mode 100644 index 0000000000..a3738896d5 --- /dev/null +++ b/tests/data/SPECS/rootfs.spec @@ -0,0 +1,17 @@ +Name: rootfs +Version: 1.0 +Release: 1 +Summary: Package owning top-level root directory +License: GPL +BuildArch: noarch +Prefix: / + +%description +%{summary}. + +%install +mkdir -p $RPM_BUILD_ROOT/foo +touch $RPM_BUILD_ROOT/foo/bar + +%files +/ diff --git a/tests/rpmi.at b/tests/rpmi.at index 372be0a8b7..488a9e93cb 100644 --- a/tests/rpmi.at +++ b/tests/rpmi.at @@ -1170,6 +1170,31 @@ runroot rpm -ql reloc []) RPMTEST_CLEANUP +AT_SETUP([rpm -i relocatable package 3]) +AT_KEYWORDS([install relocate]) +RPMTEST_USER +RPMDB_INIT + +runroot rpmbuild --quiet -bb /data/SPECS/rootfs.spec + +RPMTEST_CHECK([ +runroot_user \ + rpm -U --prefix \$PWD/root --dbpath \$PWD/rpmdb \ + /build/RPMS/noarch/rootfs-1.0-1.noarch.rpm +], +[0], +[], +[]) + +RPMTEST_CHECK([ +runroot_user rpm -e --dbpath \$PWD/rpmdb rootfs +runroot_user test ! -d \$PWD/root +], +[0], +[], +[]) +RPMTEST_CLEANUP + AT_SETUP([rpm -i with/without --excludedocs]) AT_KEYWORDS([install excludedocs]) RPMTEST_CHECK([