[Rpm-maint] [rpm-software-management/rpm] Relocatable packages with plain `/` in `%files` can't be installed as regular user (Issue #3173)

Michal Domonkos notifications at github.com
Tue Jun 18 15:25:44 UTC 2024


**Describe the bug**
An attempt to install a relocatable package as a regular user that was built from a spec file that contains
```
Prefix: /
%files
%{prefix}
```
results in a failure.

**To Reproduce**
1. Build the following package:
```
Name:           reproducer
Version:        0.0.1
Release:        1%{?dist}
Summary:        Reproducer for JIRA 
License:        GPL
Prefix:         /

%description
%{summary}.

%install
mkdir -p $RPM_BUILD_ROOT/foo
touch $RPM_BUILD_ROOT/foo/bar

%files
%{prefix}

%changelog
* Wed Mar 13 2024 root
- 
```
2. Install the package locally as non-root user:
```
$ rpm -Uhv --prefix $PWD/RPMROOTDIR --dbpath $PWD/RPMDB /path/to/reproducer.rpm
```

**Actual behavior**
```
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:reproducer-0.0.1-1               ################################# [100%]
error: unpacking of archive failed on file [...]/RPMROOTDIR//: cpio: chmod failed - Device or resource busy
error: reproducer-0.0.1-1.x86_64: install failed
```

**Expected behavior**
No failure, package gets installed successfully.

**Environment**
 - OS / Distribution: RHEL-9.5 and later
 - Version: RPM 4.16.1.3

**Additional context**
This is a regression introduced with fsm rework to use the `*at()` family of calls that was made to address the symlink CVEs (#1919).

The root cause seems to be this:

When processing the payload files, we eventually call `fsmSetmeta()` for the top-level directory `/` which obviously fails for a regular user. This happens despite us already being (via `di.dirfd`) in the right top-level directory `$PWD/RPMROOTDIR`, because `fp->fpath` is set to `/` there and when we pass it to `fchownat(2)`, since the path is absolute, `di.dirfd` is ignored by the function (as per specification).

One fix that works (but I haven't yet thought about its consequences) is simply making sure `fp->fpath` is never an absolute path, i.e. replacing the `/` with a `.`, like so:

```diff
diff --git a/lib/fsm.c b/lib/fsm.c
index 20b270cf5..938a2db1d 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -78,7 +78,7 @@ static int fsmClose(int *wfdp);
 static char * fsmFsPath(rpmfi fi, const char * suffix)
 {
     const char *bn = rpmfiBN(fi);
-    return rstrscat(NULL, *bn ? bn : "/", suffix ? suffix : "", NULL);
+    return rstrscat(NULL, *bn ? bn : ".", suffix ? suffix : "", NULL);
 }
 
 static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path)
```

This use case comes from a RHEL customer and was filed as https://issues.redhat.com/browse/RHEL-28967.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/rpm-software-management/rpm/issues/3173
You are receiving this because you are subscribed to this thread.

Message ID: <rpm-software-management/rpm/issues/3173 at github.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rpm.org/pipermail/rpm-maint/attachments/20240618/2e89515b/attachment.html>


More information about the Rpm-maint mailing list