Uploaded image for project: 'RHEL'
  1. RHEL
  2. RHEL-28969

Harden removal code of relocatable packages

    • Icon: Story Story
    • Resolution: Duplicate
    • Icon: Undefined Undefined
    • rhel-8.10
    • rhel-8.9.0
    • rpm
    • rhel-sst-cs-software-management
    • ssg_core_services
    • None
    • False
    • Hide

      None

      Show
      None
    • None
    • Red Hat Enterprise Linux
    • None
    • Approved Blocker
    • None

      This issue is seen on customer RHEL8 systems, I can reproduce on RHEL9 systems as well (see reproducer below).

      When installing a custom Relocatable package, the paths are unlinked first using unlinkat() syscalls.
      If the package contains / in its %files list, this leads to getting a EBUSY failure, which didn't happen prior to fixing CVE-2021-35939 (on RHEL8, pre-CVE: rpm-4.14.3-26.el8).

      From my point of view, having / in the %files list is kind of user error, because the node is already shipped by us (filesystem package), but it would be nice to harden the code to avoid the error (through skipping this specific node from being unlinked).

      Reproducer

      Install relocatable package reproducer-0.0.1-1.el8.x86_64.rpm as a user:

      [user@vm-rhel9 ~]$ strace -fttTvyy -s 128 -o rpm.strace -- rpm -ivhU --reinstall --prefix $PWD/RPMROOTDIR --dbpath $PWD/RPMDB /tmp/reproducer-0.0.1-1.el9.x86_64.rpm 
      Verifying...                          ################################# [100%]
      warning: Unable to get systemd shutdown inhibition lock: Permission denied
      Preparing...                          ################################# [100%]
      Updating / installing...
         1:reproducer-0.0.1-1.el9           ################################# [100%]
      error: unpacking of archive failed on file //: cpio: chmod failed - Device or resource busy
      error: reproducer-0.0.1-1.el9.x86_64: install failed
      

      Strace shows the issue on / node:

      $ grep unlinkat rpm.strace 
      38285 10:58:44.159680 unlinkat(10</>, "foo;65f178d4", 0) = -1 ENOENT (No such file or directory) <0.000002>
      38285 10:58:44.159691 unlinkat(10</>, "/", AT_REMOVEDIR) = -1 EBUSY (Device or resource busy) <0.000002>
      

      Here above rpm tries to deletes its own node.

      Related code is:

        276 static int fsmRmdir(int dirfd, const char *path)
        277 {
        278     int rc = unlinkat(dirfd, path, AT_REMOVEDIR);           <<<<< HERE
        279     if (_fsm_debug)
        280         rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__,
        281                dirfd, path, (rc < 0 ? strerror(errno) : ""));
        282     if (rc < 0)
        283         switch (errno) {
        284         case ENOENT:        rc = RPMERR_ENOENT;    break;
        285         case ENOTEMPTY:     rc = RPMERR_ENOTEMPTY; break;
        286         default:            rc = RPMERR_RMDIR_FAILED; break;
        287         }
        288     return rc;
        289 }
      

      I'm attaching the SPEC file to build the reproducer package if necessary.

        1. reproducer.spec
          0.3 kB
          Renaud Métrich

              packaging-team-maint packaging-team-maint
              rhn-support-rmetrich Renaud Métrich
              packaging-team-maint packaging-team-maint
              Software Management QE Software Management QE
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: