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

libdnf may create /run/user/0 directory, causing a bad context to be applied, leading to further issues

    • Icon: Bug Bug
    • Resolution: Done-Errata
    • Icon: Major Major
    • rhel-8.10
    • rhel-8.8.0
    • libdnf
    • libdnf-0.63.0-19.el8
    • None
    • Important
    • rhel-sst-cs-software-management
    • ssg_core_services
    • 20
    • 22
    • None
    • QE ack
    • False
    • Hide

      None

      Show
      None
    • Yes
    • None
    • Bug Fix
    • Hide
      .`systemd` now correctly manages the `/run/user/0` directory created by `libdnf`

      Previously, if the `libdnf` functions were called from an Insights client before logging in root, the `/run/user/0` directory could be created with a wrong SELinux context type. This prevented `systemd` from cleaning the directory after you logged out from root.

      With this update, the `libdnf` package now sets a default creation type according to default file system labeling rules defined in a SELinux policy. As a result, `systemd` now correctly manages the `/run/user/0` directory created by `libdnf`.
      Show
      .`systemd` now correctly manages the `/run/user/0` directory created by `libdnf` Previously, if the `libdnf` functions were called from an Insights client before logging in root, the `/run/user/0` directory could be created with a wrong SELinux context type. This prevented `systemd` from cleaning the directory after you logged out from root. With this update, the `libdnf` package now sets a default creation type according to default file system labeling rules defined in a SELinux policy. As a result, `systemd` now correctly manages the `/run/user/0` directory created by `libdnf`.
    • Done
    • None

      Description of problem:

      This is observed on a customer system when insights-client executes.
      In this specific case (but there are likely other cases), the /run/user/0 directory gets created with insights_client_tmp_t context, causing systemd's user-runtime-dir@0.service unit to fail forever:
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
      Aug 08 13:24:22 vm-insights8 systemd[1]: Stopping User runtime directory /run/user/0...
      Aug 08 13:24:22 vm-insights8 systemd-user-runtime-dir[34749]: Failed to remove runtime directory /run/user/0 (after unmounting): Permission denied
      Aug 08 13:24:22 vm-insights8 systemd[1]: user-runtime-dir@0.service: Control process exited, code=exited status=1
      Aug 08 13:24:22 vm-insights8 systemd[1]: user-runtime-dir@0.service: Failed with result 'exit-code'.
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      The root cause for this is the libdnf code forcibly creates the /run/user/0 directory when trying to import GPG keys:
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
      865 static void ensure_socket_dir_exists() {
      866 auto logger(Log::getLogger());
      867 std::string dirname = "/run/user/" + std::to_string(getuid());
      868 int res = mkdir(dirname.c_str(), 0700); <<<<<<< HERE
      869 if (res != 0 && errno != EEXIST)

      { 870 logger->debug(tfm::format("Failed to create directory \"%s\": %d - %s", 871 dirname, errno, strerror(errno))); 872 }

      873 }
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      This is not an issue when /run/user/0 already exists since mkdir is then a no-op, but this is not always the case.
      For example, when the root user has no session, this is an issue if a libdnf client, such as yum, executes through sudo (e.g. "sudo yum check-update").
      This code then creates the directory in the context of the caller, which may be problematic when there is no transition rule in the SELinux policy to automatically create the directory with proper "user_tmp_t" context.

      In the case of "insights-client", the context is "insights_client_t", which leads to creating the directory with "insights_client_tmp_t" context, which then prevents systemd from deleting that directory once root user logged in and logged out again.

      Version-Release number of selected component (if applicable):

      libdnf-0.63.0-14.el8_8.x86_64

      How reproducible:

      Always when executing in "insights_client_t" contxt

      Steps to Reproduce:
      1. Setup EPEL and REMI repositories (to get the key for REMI repo imported)

      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      1. yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
      2. yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
      3. yum clean all
                    • 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      2. Create a wrapper to execute libdnf as a service running as if it was executed from insights-client

      You need to have insights-client package installed to get access to the context.

      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      1. cat > /usr/local/bin/fake_insights << EOF
        #!/bin/sh
        exec /usr/libexec/platform-python /usr/bin/yum -y check-update
        EOF
      1. chmod +x /usr/local/bin/fake_insights
      2. chcon -t insights_client_exec_t /usr/local/bin/fake_insights
                    • 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      Note: here above we use "/usr/libexec/platform-python" to avoid the transition to "rpm_t".

      3. Create an admin user which will start the wrapper in insights-client context

      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      1. useradd -G wheel admin
      2. echo "redhat" | passwd --stdin admin
                    • 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      4. Login as "admin" and make sure no root session is present

      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
      $ ssh admin@system
      $ sudo systemctl stop user-0.slice
      $ ls -Zd /run/user/0
      ls: cannot access '/run/user/0': No such file or directory
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      5. Execute "yum check-update" in insights-client context and wait for /run/user/0 to be created

      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
      $ sudo systemd-run /usr/local/bin/fake_insights
      $ while :; do date; ls -Z /run/user; sleep 1; done
      Tue Aug 8 14:26:07 CEST 2023
      system_u:object_r:user_tmp_t:s0 1000
      [...]
      system_u:object_r:user_tmp_t:s0 1000
      Tue Aug 8 14:26:12 CEST 2023
      system_u:object_r:insights_client_tmp_t:s0 0 system_u:object_r:user_tmp_t:s0 1000
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      Actual results:

      Here above the directory got created with bad context.

      Expected results:

      No directory /run/user/0 created at all or proper "user_tmp_t" context set.

      Additional info:

      You may also reproduce with executing "subscription-manager repos --disable *" instead of "yum" in the wrapper:
      -------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      1. cat > /usr/local/bin/fake_insights << EOF
        #!/bin/sh
        exec subscription-manager repos --disable *
        EOF
      1. chmod +x /usr/local/bin/fake_insights
      2. chcon -t insights_client_exec_t /usr/local/bin/fake_insights
                    • 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

      IMHO it's not up to libdnf to create the /run/user/0 directory but systemd and this should be considered as a systemd-private thing.
      I would expect the GPG command to not populate this directory at all either.
      The comment above function ensure_socket_dir_exists() tends to indicate this thing is a workaround for GPG issues actually.

      Not creating this directory is the only reliable solution to make sure whatever the caller is, this will work.

              rhn-support-ppisar Petr Pisar
              rhn-support-rmetrich Renaud Métrich
              Eva Mrakova Eva Mrakova
              Mariya Pershina Mariya Pershina
              Votes:
              0 Vote for this issue
              Watchers:
              11 Start watching this issue

                Created:
                Updated:
                Resolved: