|
Bugzilla – Full Text Bug Listing |
| Summary: | AUDIT-0: spice-vdagent: spice-vdagentd.service can be implicitly started by default | ||
|---|---|---|---|
| Product: | [Novell Products] SUSE Security Incidents | Reporter: | Fabian Vogt <fvogt> |
| Component: | Incidents | Assignee: | Matthias Gerstner <matthias.gerstner> |
| Status: | RESOLVED FIXED | QA Contact: | Security Team bot <security-team> |
| Severity: | Normal | ||
| Priority: | P5 - None | CC: | brogers, jsegitz, lnussel, matthias.gerstner, meissner |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | Other | ||
| OS: | Other | ||
| Whiteboard: | |||
| Found By: | --- | Services Priority: | |
| Business Priority: | Blocker: | --- | |
| Marketing QA Status: | --- | IT Deployment: | --- |
| Attachments: |
final version of security patches
tarball containing the reproducers for the issues described in the report in comment 15 |
||
|
Description
Fabian Vogt
2020-07-06 09:49:15 UTC
Meh, it's not quite that simple. This works fine when booting into graphical.target, but fails when booting into multi-user.target and switching to graphical.target with "systemctl isolate graphical.target" or "init 5". There is /usr/lib/udev/rules.d/70-spice-vdagentd.rules, which enables the socket once the virtio port appears. Apparently this is not part of the state which is kept across isolate. @security: Has this service not been audited before due to ^ evading the usual triggers? @systemd-maintainers: Is there anything that can be done to make udev triggered units stay across isolate? Maybe spice-vdagentd.socket needs IgnoreOnIsolate=true? systemd services do not require a security review per se. Adding a systemd service to the systemd presets to have it started automatically does require a review, however. The notion behind that is that we want to keep the default security on a high level. systemd services can for example be installed implicitly as dependencies of other packages. We usually don't want them to start up right away. It should be a conscious user decision to do so. The list of services that are automatically started is pretty short at the moment. So when you absolutely need this and have a convincing use case why it needs to be that way then we can do the AUDIT and add it to systemd-presents-branding-openSUSE. So are there any news here? Do you still needs this? (In reply to Matthias Gerstner from comment #2) > systemd services do not require a security review per se. Adding a systemd > service to the systemd presets to have it started automatically does require > a > review, however. > > The notion behind that is that we want to keep the default security on a high > level. systemd services can for example be installed implicitly as > dependencies of other packages. We usually don't want them to start up right > away. It should be a conscious user decision to do so. The udev rule starts the service, so effectively the service is automatically started, but only if the rule matches. That's why I'm asking whether an audit is required for that as well. (In reply to Matthias Gerstner from comment #3) > So are there any news here? Do you still needs this? If no audit is neccessary, only the systemd bug remains, so feel free to reassign. (In reply to fvogt@suse.com from comment #4) > The udev rule starts the service, so effectively the service is > automatically started, but only if the rule matches. That's why I'm asking > whether an audit is required for that as well. Is there a reason why the rule shouldn't match? It shows that we have a loophole in our security restrictions. udev rules can circumvent our systemd autostart restrictions. So maybe we should review this service here after all. > If no audit is neccessary, only the systemd bug remains, so feel free to > reassign. What do you mean by "the systemd bug"? (In reply to Matthias Gerstner from comment #5) > (In reply to fvogt@suse.com from comment #4) > > The udev rule starts the service, so effectively the service is > > automatically started, but only if the rule matches. That's why I'm asking > > whether an audit is required for that as well. > > Is there a reason why the rule shouldn't match? The service is for connecting to QEMU, so it only works if it's running in a VM with the appropriate guest device enabled. > It shows that we have a loophole in our security restrictions. udev rules can > circumvent our systemd autostart restrictions. So maybe we should review this > service here after all. > > > If no audit is neccessary, only the systemd bug remains, so feel free to > > reassign. > > What do you mean by "the systemd bug"? See comment 1. The udev rule has ENV{SYSTEMD_WANTS}="spice-vdagentd.socket" but the .socket unit is stopped on "systemctl isolate", even though the device (and therefore the wants relationship) is still there. (In reply to fvogt@suse.com from comment #6) > > Is there a reason why the rule shouldn't match? > > The service is for connecting to QEMU, so it only works if it's running in a VM with the appropriate guest device enabled. Does it help to enable the service when the device is not enabled? > See comment 1. The udev rule has ENV{SYSTEMD_WANTS}="spice-vdagentd.socket" > but the .socket unit is stopped on "systemctl isolate", even though the > device (and therefore the wants relationship) is still there. Is this actually a systemd bug / something that systemd is likely to fix in the sense of this bug here? After a review we can add this service to the systemd presets. Hopefully there won't be any side effects ... the package is not installed by default, I hope, so for users not needing this nothing should change. (In reply to Matthias Gerstner from comment #7) > (In reply to fvogt@suse.com from comment #6) > > > Is there a reason why the rule shouldn't match? > > > > The service is for connecting to QEMU, so it only works if it's running in a VM with the appropriate guest device enabled. > > Does it help to enable the service when the device is not enabled? It would most likely just fail immediately. > > See comment 1. The udev rule has ENV{SYSTEMD_WANTS}="spice-vdagentd.socket" > > but the .socket unit is stopped on "systemctl isolate", even though the > > device (and therefore the wants relationship) is still there. > > Is this actually a systemd bug / something that systemd is likely to fix in > the sense of this bug here? I hope so, we'll see. > After a review we can add this service to the systemd presets. Hopefully > there > won't be any side effects ... the package is not installed by default, I > hope, > so for users not needing this nothing should change. Yes, but I don't think that adding it to the preset is the right way actually. The udev rule is the right approach, just hits some corner cases... (In reply to fvogt@suse.com from comment #8) > Yes, but I don't think that adding it to the preset is the right way actually. > The udev rule is the right approach, just hits some corner cases... Okay then I suggest we keep this bug open for review. And you can create a split-off bug for systemd folks to address the separate issue of the `isolate` behaviour. (In reply to Matthias Gerstner from comment #9) > (In reply to fvogt@suse.com from comment #8) > > Yes, but I don't think that adding it to the preset is the right way actually. > > The udev rule is the right approach, just hits some corner cases... > > Okay then I suggest we keep this bug open for review. And you can create a > split-off bug for systemd folks to address the separate issue of the > `isolate` > behaviour. Done: bug 1175822 I will look into this service now. The review brought some security issues to light, so let's move this bug into SLE space and make it private for the time being. Internal CRD: 2020-12-17 preliminary This is an embargoed bug. This means that this information is not public. Please do NOT: - talk to other people about this unless they're involved in fixing the issue - make this bug public - submit this into OBS (e.g. fix Leap/Tumbleweed) until this bug becomes public (e.g. no EMBARGOED tag on the header) Consult with security team if you think that the issue is public and the bug is still private (e.g. subject still contains "EMBARGOED"). Please do NOT make the bug public yourself. Please be aware that the SUSE:SLE-15-SP3:GA codestream is available via OBS, so do NOT submit there before this is public. These are the steps that are asked from you: 1, Your primary responsibility is to submit a fix for this issue. Here's a how-to for submitting packages for maintenance releases in IBS: https://confluence.suse.com/display/maintenance/How+to+Submit+Packages+or+Containers+to+Maintenance Apart from the GA codestreams mentioned above, you can submit to IBS anytime. This is private and allows us to start testing as soon as possible. 2, We also want to fix openSUSE if it's affected. $ is_maintained $PACKAGE will tell you if the package is inherited from SLES or if it is branched for openSUSE. There are two cases: - It's coming from SLES: The update will automatically be released for openSUSE. Nothing to do for you. - It's branched for openSUSE: You need to submit AFTER the bug became public, to the current openSUSE codestreams. For openSUSE Factory please submit to the devel project of you package AFTER the bug became public. Security will then take the following steps: - We wait for your submission and package them into an incident for QA testing. The QA tester might reach out to you if he finds issues with the update. - Once the coordinated release date (CRD), the date this issue should become public, is reached (or for internal findings: once we're done testing), we remove the EMBARGOED tag from this bug and publish the updates. - Only if the bug here is public you may submit to public repositories (OBS). You can contact us at: * IRC: irc.suse.de #security * RocketChat: https://chat.suse.de/channel/security * Email: security-team@suse.de Following is the security report that I just shared with the two active
developers of the FreeDesktop GitLab repository for spice-vdagent. I couldn't
find any more suitable security contact documented anywhere. Let's see what
they respond.
# 1) Introduction
The SUSE security team got a request to review the `spice-vdagentd` daemon.
It got to our attention that this daemon can start indirectly via udev
(`70-spice-vdagentd.rules`) even if the service was not explicitly activated by
the Administrator and thus might introduce additional security attack
surface in default installations.
The `spice-vdagentd` is typically used in Qemu virtual machines to provide
additional features like:
- a shared clipboard between host and guest system to allow seamless
copy/paste
- file transfers from the host to the guest machine
- sharing information about the virtual display size and monitor configuration
- synchronizing audio device volume between host and guest
`spice-vdagentd` is running as *root* as a socket activated systemd service.
The following security report is based the spice-vdagent version 0.20.0,
which is the latest upstream release available as of this writing.
# 2) The `vdagentd` Communication Channels
This section gives a short introduction about the communication channels used
by `vdagentd` for readers that are not familiar with its design.
## a) The com.redhat.spice.0 Virtio Serial Device
In Qemu virtual machine instances that have the spice protocol enabled a
virtual serial device will be emulated, typically enabled by passing switches
like these to qemu:
```
-spice disable-ticketing,unix,addr=/path/to/spice_socket, -device virtio-serial-pci -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 -chardev spicevmc,id=spicechannel0,name=vdagent
```
Within the virtual machine `spice-vdagentd` talks to this serial device
(`/dev/virtio-ports/com.redhat.spice.0`) to exchange information with the host
machine and implement the spice features. The SPICE protocol is used on this
communication channel.
This serial device is of lesser importance in the context of this security
report.
## b) The spice-vdagent UNIX Domain Socket
The `spice-vdagentd` creates a listening UNIX domain socket of type
`SOCK_STREAM` in `/run/spice-vdagentd/spice-vdagent-sock`. This socket path is
accessible to all users in the system (file mode 0666). It is used by the
counterpart of `spice-vdagentd`, the `spice-vdagent`, which runs in the
context of a graphical user session with user privileges. This role will also
be called the "user agent" for the rest of this document.
The `spice-vdagent` e.g. informs the `spice-vdagentd` about changes in
clipboard contents in the graphical VM session, which in turn forwards this
information via the serial device to the host machine. Similarly requests from
the host machine to e.g. initiate a file transfer will be forwarded from
`spice-vdagentd` to the `spice-vdagent`, which will then store the file data
in the context of the user session.
Multiple user agents can connect to `spice-vdagentd` at the same time. At most
one user agent may be present in the currently active session, however. Only
a user agent running in the currently active session can access most of
the features of `spice-vdagentd`. `spice-vdagentd` determines the session a
user agent is part of by querying systemd facilities (e.g.
`sd_seat_get_active()`, `sd_pid_get_session()`). The user agent (if any)
associated with the currently active session will also be the target of any
forwarded requests received from the host on the virtual serial device.
# 3) Security Issues
This report is accompanied by two Python scripts (`vdagent.py`,
`create_vdagent_conns.py`) and a C++ source file (`socket_pid_attack.cxx`)
which can be used to reproduce the findings that follow. These reproducers
will be mentioned in the individual sections. All reproducers need to be
executed in the context of a host system running a SPICE enabled Qemu virtual
machine (see section 2.a for the required Qemu switches, or use something like
livbirtd and its Qemu backend with appropriate settings).
## a) Memory DoS via Arbitrary Entries in `active_xfers` Hash Table
The `spice-vdagentd` maintains a hash map named `active_xfers` that maps
`task_ids` to UNIX domain socket connections they belong to. These `task_ids`
refer to ongoing file transfers from the host to the virtual machine.
An arbitrary client connected to `spice-vdagentd` via a UNIX domain socket can
trigger an entry into this hash map, without the requirement that the client
is associated with the currently active graphical session (function
`do_agent_file_xfer_status`, specifically `vdagentd.c:1025`). There is no limit
on the maximum amount of file transfers ongoing in parallel and there are no
timeouts applied for a file transfer to be finished.
Therefore any unprivileged local user with access to the
`/run/spice-vdagentd/spice-vdagent-sock` socket path can perform a memory
denial-of-service by entering a large amount of entries into this hash map.
### Impact
- an unprivileged local attacker inside a virtual machine can cause large
memory allocation in a daemon running as *root*. These memory allocations will
persist as long as the UNIX domain socket connection remains intact. After a
longer while, depending on the available system memory and swap space, the
system might enter an out of memory situation, causing a denial-of-service for
`spice-vdagentd` or even other processes in the system (the Linux kernel OOM
killer is known to punish innocent victims at times).
- after a large amount of entries have been made by an attacker this way and
once the UNIX domain socket connection is terminated, the `spice-vdagentd`
will remove all the hash map entries belonging to this connection (function
`agent_disconnect`, specifically `vdagentd.c:955`). Each "cancelled" file
transfer will be logged in the system (`vdagentd.c:910`, `vdagentd.c:342`).
In my tests this also caused a high load in `systemd-journald` and high disk
space consumption from the logs stored in `/var/log`.
### Suggested Fix
Clients not belonging to the active session should not be allowed to cause
data to be entered into the `active_xfers` hash map. A maximum amount of file
transfers should be enforced that prevents any DoS situations (even a
legitimate client from the active session could still cause the DoS).
Furthermore, since file transfers are initiated by the host machine, only
entries for actually existing file transfers should be allowed to clients.
Additionally, a timeout could be implemented for file transfers (in relation
to the file size) that prevents file transfers from getting stuck.
### Reproducer
Using the supplied Python program the DoS can be performed this way:
```
user $ ./vdagent.py --xfer-status-DoS
```
The program will infinitely create new entries in the `active_xfers` hash map
up until the maximum 64-bit (for `x86_64` architectures) integer value. Memory
consumption will grow rather slowly but reliably. An exponential growth
allocation scheme seems to be in place, because the observed memory
consumption (as seen in `top`) only happens in jumps.
## b) Possible File Transfer DoS and Information Leak via `active_xfers` Hash Map
The same basic problem as described in section 3.a can lead to a file transfer
information leak. The file transfer protocol roughly works like this:
- The host will send a `VD_AGENT_FILE_XFER_START` message that is forwarded to
the user agent (function `do_client_file_xfer()`, specifically
`vdagentd.c:376`). This message contains a `task_id` that identifies the file
transfer process in future messages.
- The `spice-vdagent` will check free disk space and allocate a file of the
expected size in the file system. If all checks pass then it will reply with
a `VDAGENTD_FILE_XFER_STATUS_CAN_SEND_DATA` message, which causes
`spice-vdagentd` to associate the client connection with the ongoing file
transfer.
- The host will now start sending out chunks of the file data with
`VDAGENTD_FILE_XFER_DATA` messages (processed in function
`do_client_file_xfer()`, specifically `vdagentd.c:386`). `spice-vdagentd` will
forward each chunk to the client connection stored in the `active_xfers`
hash map.
The host application (tested with `remote-viewer` from the virt-viewer
package) chooses an incrementally growing `task_id` for file exchanges
which starts counting at 1. Thus the `task_id` is predictable. Since any
unauthenticated local client can replace the mapping of `task_id` to client
connection by its own client connection, there is a possibility for an
attacker to obtain parts of the transferred file data.
The attacker needs to win a race condition here, because it needs to hit the
time window after the legitimate client sends out the
`VDAGENTD_FILE_XFER_STATUS_CAN_SEND_DATA` message and before the host starts
sending out file chunks via `VDAGENTD_FILE_XFER_DATA`. If the attacker sends
his own `VDAGENTD_FILE_XFER_STATUS_CAN_SEND_DATA` using the correct `task_id`
during this time window, then he can obtain the complete file. At least for
large file exchanges bigger parts of the file are feasible to be
obtained, even when the initial parts of the file are transferred to the
legitimate client.
The more difficult part for an attacker will be to identify when such a file
transfer will take place. The reproducer shows the basic attack technique.
### Impact
File data from the host system can end up in full or in parts in the client
connection of an illegitimate local user in the VM system. Exploitability will
be difficult if there is not a suitable side channel with information about
file transfers going on.
In any case active file transfers from other users can also be interrupted
(DoS aspect).
### Suggested Fix
Basically the same as in section 3.a and additionally:
- it should be made sure that existing entries in `active_xfers` never get
overwritten before the transfer ends or is cancelled.
- only the same client that originally received the `VD_AGENT_FILE_XFER_START`
should be able to reply with `VDAGENTD_FILE_XFER_STATUS_CAN_SEND_DATA`.
- `task_ids` could be randomized to become unpredictable (but this is not in
the `spice-vdagentd` code, rather in the code of the tools running on the
host).
### Reproducer
This reproducer has the precondition that the victim's home directory is
world-readable (or at least readable by the attacker). The script will wait
(using the *inotify* API) for a new file to be created in the home directory
(assuming that this is the initiation of a file transfer).
For reproducing perform the following steps:
1. Open a fresh `remote-viewer` connection for the test VM. This will reset
the `task_id` used for file transfers to start to 1.
2. Run the reproducer script in an attacker context as follows:
# replace this path by the actual victim's home directory
VICTIM=/home/victim
attacker$ ./vdagent.py --send-xfer-status 1 --wait-for-file-create $VICTIM
3. Log in as the *victim* user in a graphical session in the VM using the
`remote-viewer` connection started in step 1.
4. Drag-and-drop a larger file (I tested using an 8 megabyte text file) into
the `remote-viewer` window to initiate file transfer.
You should see that the attacker's `vdagent.py` script outputs large parts of
the file transfer to the terminal. The original file transfer will indicate an
error condition without specific details about the problem..
Remember that for each subseqeuent attack attempt you will need to increment
the `task_id` (`--send-xfer-status` parameter) or open a fresh `remote-viewer`
window for the VM, to reset the `task_id` used on the host side.
## c) Possibility to Exhaust File Descriptors in `vdagentd`
`spice-vdagentd` does not apply a limit to the amount of client connections
that can be established via the UNIX domain socket in
`/run/spice-vdagentd/spice-vdagent-sock`. Also existing connections aren't
subject to a timeout or any kind of preconditions for them to stay alive.
Thus it is easy to exhaust the file descriptor limit for the `spice-vdagentd`
process (typically 1024 file descriptors by default, this limit is also
imposed by system calls like `select()`).
Any local user in the virtual machine can open around ~1020 connections to
`spice-vdagentd` and simply keep them open without transmitting any data. The
`spice-vdagentd` will then become unable to open further connections for
legitimate clients or perform other tasks (like opening the serial device, see
section 2.a, or invoking systemd library calls that require opening files).
### Impact
By exhausting file descriptors in `spice-vdagentd` the following effects can
be achieved:
- The attack can prevent legitimate `spice-vdagent` instances from connecting
to the `spice-vdagentd`. SPICE features won't be available to affected
sessions.
- The attack can cause `vdagentd` to exit on error conditions if tuned
carefully. For example, an attacker can exhaust all file descriptors in
`spice-vdagentd` except for one and then wait for a legitimate client from an
active session to connect. This connection attempt will succeed, but the
subsequent attempt to open the serial device (see section 2.a) will fail, and
`spice-vdagentd` will exit. This will then also cause the involved
`spice-vdagent` to exit, because the connection to the system daemon is
lost.
- `spice-vdagentd` will enter a 100 % CPU infinite loop, because it tries to
`accept()` the new connection, which is impossible, but also doesn't close
the listening socket or abort execution.
- This attack vector makes security issue 3.d better exploitable, which will
be explained there in more detail.
### Suggested Fix
- `spice-vdagentd` should enforce a small upper limit of UNIX domain socket
connections that are accepted and maintained in parallel. This will prevent
file descriptor exhaustion for the process.
- `spice-vdagentd` should perform some kind of credibility check on
established connections: if the peer is not connected to any graphical
session then the connection should be terminated again. Multiple connections
from the same session should be terminated again. This already happens, but
only if two agents for the same active session are encountered
(`vdagentd.c:875`). This way local users should not be able to deny the SPICE
service to other local users.
### Reproducer
Using the supplied script `create_vdagent_conns.py` the maximum number of
connections that `spice-vdagentd` can process, can be established. The result
will be that no new user agents can register with the system daemon. A 100 %
CPU loop will occur in `spice-vdagentd`.
## d) UNIX Doman Socket Peer PID Retrieved via `SO_PEERCRED` is Subject to Race Condition
One major security property of `spice-vdagentd` is that it only allows those
clients access to most of the SPICE features (like clipboard, file transfer)
that are currently in an active session according to systemd (see also section
2.b). It is possible for arbitrary local users (like *nobody*) to connect to
`spice-vdagentd` but these connections should not be able to interact with the
host machine, because they don't belong to the active session.
The session check is performed after a new UNIX domain socket connection is
established in `agent_connect()` in `vdagentd.c:937`. The check basically
relies on these two source code lines:
```
pid = vdagent_connection_get_peer_pid(VDAGENT_CONNECTION(conn), &err);
agent_data->session = session_info_session_for_pid(session_info, pid);
```
The peer's PID is obtained via glib's `g_socket_get_credentials` which boils
down to the `SO_PEERCRED` socket option that is supported for UNIX domain
sockets (see `man 7 socket`, `man 7 unix`, `struct ucred`). The man page says
about this:
> The returned credentials are those that were in effect at the time of the call
> to connect(2) or socketpair(2).
This means that there is a race condition between the point in time when a
client performs the `connect()` call to establish a connection with
`spice-vdagentd` and the time `spice-vdagentd` retrieves and checks the PID in
its `agent_connect()` function. The PID in question can already have been
replaced by an unrelated process. Therefore the session that `spice-vdagentd`
associates with this PID might be a different one than the actual peer process
belonged to, when the `connect()` system call was performed.
An attack to exploit the race condition requires the following steps:
1. an attacker can inherit a UNIX domain socket file descriptor to a child
process that performs the `connect()` to `spice-vdagentd` and exits
immediately again, thereby freeing the PID (let's call it the malicious PID)
in the system as soon as the parent process performs a `wait()` on the exited
child process. This malicious PID will now be associated in the kernel with
the `SO_PEERCRED` data returned for the connected UNIX domain socket.
2. now the attacker needs to perform a PID cycle in the system (i.e.
create many useless child processes to cause the maximum PID - typically 32768 -
to be reached in the system and new processes get assigned small PIDs
again). When the PIDs assigned by the kernel are getting close to the
malicious PID, the attacker needs to stop creating child processes and wait
for unrelated processes from other users to come into existence.
3. Once the malicious PID gets reassigned to an unrelated process and the
`agent_connect()` function runs in `spice-vdagentd`, it will retrieve wrong
session information for the existing connection. If the malicious PID gets
reassigned to a process running in the active session, then the connection
that the attacker uses will get access to the SPICE features and can
communicate with the host, although the attacker would otherwise not have
sufficient privileges to do so.
The described race condition is very hard to hit under normal circumstances,
because step 2., the PID cycle, is taking a long time and the
`agent_connect()` function in `spice-vdagentd` is very likely to run before an
unrelated process gets reassigned the malicious PID in question. When combined with
the file descriptor exhaustion security issue described in section 3.c,
however, then this attack will become way more feasible.
This combined attack works like follows:
- Exhaust all file descriptors in `spice-vdagentd` as described in section
3.c.
- Now perform the attack steps 1. and 2. as described previously. What
happens now is that the attacker's UNIX domain socket `connect()` will succeed,
because on kernel level this is still possible. `spice-vdagentd` won't be able
to `accept()` this connection, though, because no more file descriptors are
available to do so. The connection remains pending on the listening socket,
however.
- Now for step 3., once the attacker notices that the malicious PID got
assigned to an unrelated process, he can stop the file descriptor exhaustion
put into place previously, thus making it possible for `spice-vdagentd` to
`accept()` the malicious connection pending in the kernel. Only now will the
`agent_connect()` function run, and it will more reliably determine the
wrong session for the connection.
### Impact
1. A compromised local account with little privileges inside the virtual
machine like *nobody* can try to become the "active agent" for
`spice-vdagentd` for the graphical session of a legitimate local user. If
successful then the attacker can access the host's clipboard contents or
send malicious clipboard content to the host. The attacker can also retrieve
file data from the host (compare section 2.b) or send invalid screen
resolution and display information to the host.
2. The combined attack using the file descriptor exhaustion and the
`SO_PEERCRED` race condition is still not 100 % reliable but it can be
repeated many times to increase chances of success. The only unpredictable
ingredient is victim child processes appearing that get assigned the desired
malicious PID and stay around for long enough for `spice-vdagentd` to pick up the
wrong session information.
3. If the victim's graphical session already runs a legitimate `spice-vdagent`
then a successful attack will trigger an information leak protection logic
in `vdagentd.c:874`. This has the effect of a denial-of-service, because
neither the attacker nor the legitimate user will be able to use the SPICE
features anymore.
4. If the victim's graphical session is not running a `spice-vdagent` then the
attacker can achieve all the effects described in 1.
5. If 3. applies (the victim's is already running `spice-vdagent`) then the
attacker could try to crash the currently running `spice-vdagentd` (see
section 3.c for a possible attack vector). systemd should then restart the
`spice-vdagentd` while the victim's `spice-vdagent` should exit but not be
restarted. After this situation 4) applies.
### Suggested Fix
- Once the file descriptor exhaustion (3.c) is fixed, this attack will be
harder to perform successfully.
- `spice-vdagentd` should not rely solely on the PID information to associate
the peer with a running session. An additional sanity check involving the
peer's UID should at least prevent that a connection from a different user
gets access to the active session context.
### Reproducer
This attack is quite complex and requires the combination of all supplied
programs to succeed. All programs must be placed in the same directory,
because they interact with each other. Perform the following steps:
1. For reduced complexity it is a precondition that an active graphical session
already exists in the VM, but no `spice-vdagent` is running in it. Therefore
log in the "victim" user in a graphical session, kill any `spice-vdagent`
that got started automatically and keep the session open.
2. In the context of an "attacker" user run `create_vdagent_conns.py`:
attacker$ ./create_vdagent_conns.py
Established 1015 active connections to vdagentd.
Waiting for Ctrl-C. Or press ENTER to close 5 sockets.
Wait until the program displays the message seen above. Keep the
program running in this state.
3. Still in the context of the attacker compile and run the C++ program:
attacker$ g++ -O2 socket_pid_attack.c -o socket_pid_attack
attacker$ ./socket_pid_attack
Target UDS PID = ????
Cycled to PID ....
[...]
Closing in to target_pid ????: Got child PID ????
Now waiting for ???? to get reassigned.
This program creates a UNIX domain socket connected to `spice-vdagentd` but
the `connect()` call will have been performed in a short-living child
process, thus freeing the PID the kernel stores in `SO_PEERCRED`. The
program then waits for the malicious PID to be assigned to an unrelated
process before it continues. Keep the program running in this state.
4. In the context of the "victim" user create a number of long running new child
processes in the graphical session. For example something like this:
victim$ for i in `seq 20`; do sleep 1h & done
This simulates new child processes being created in the victim's context to
replace the malicious PID the attacker is waiting for.
5. If successful then you should see in the program from step 3. that
something happened:
PID ??? now exists, but can't read exe: Permission denied
Running './vdagent.py --socket-fd 3 '
Using existing connected socket file descriptor
If this did not work right away then you need to repeat steps 3) and 4)
(rather quickly) until it succeeds.
In the case of success, the `socket_pid_attack` program will have replaced
itself by the `vdagent.py` Python program, which needs to be present in the
same directory. The Python program will block, trying to receive data on the
connected UNIX domain socket, because `spice-vdagentd` can't accept the
connection.
Now terminate the program still running from step 1. via Ctrl-C to free up
the blocked file descriptors in `spice-vdagentd`. The malicious connection
should now be accepted by `spice-vdagentd` and the attacker should have
become the active agent for the victim's graphical session. The additional
output of the program from step 3. should look similar to this:
```
MessageType.VERSION arg1 = 0 arg2 = 0 bytes = 7
b'302e32302e3000'
sending resolution of 1024 768
MessageType.GRAPHICS_DEVICE_INFO arg1 = 0 arg2 = 0 bytes = 4
b'00000000'
MessageType.CLIENT_DISCONNECTED arg1 = 0 arg2 = 0 bytes = 0
MessageType.GRAPHICS_DEVICE_INFO arg1 = 0 arg2 = 0 bytes = 4
b'00000000'
MessageType.GRAPHICS_DEVICE_INFO arg1 = 0 arg2 = 0 bytes = 4
b'00000000'
MessageType.AUDIO_VOLUME_SYNC arg1 = 0 arg2 = 0 bytes = 7
b'01eb0200000000'
MessageType.AUDIO_VOLUME_SYNC arg1 = 0 arg2 = 0 bytes = 7
b'00eb0200000000'
MessageType.CLIPBOARD_RELEASE arg1 = 1 arg2 = 0 bytes = 0
sending clipboard grab request for ClipboardType.SELECTION_PRIMARY
```
If the attacker's connection is not considered to be part of the active
session then the `AUDIO_VOLUME_SYNC` and `GRAPHICS_DEVICE_INFO` messages
will not be received from the `spice-vdagentd`. This can happen if some
other user in the system received the malicious PID or if the PID was not
in existence for long enough. If this is the case repeat steps 3. to 5.
until it succeeds.
6. If the previous steps all succeeded then you should be able to see for
example the clipboard content from the host when a SPICE capable viewer is
used to connect to the virtual machine. The attacker can also send back
"malicious clipboard content" to the host.
# 4) Other Suggestions
## a) fchmod() instead of chmod() for UNIX domain socket
Just a minor suggestion about the `chmod()` call in `vdagentd.c:1223`. If
possible this should be replaced by a call to `fchmod()`, if the file
descriptor can be obtained from the glib functions. If custom, unsafe paths
are used for the UNIX domain socket then symlink attacks might become possible
through the use of `chmod()`.
# 5) CVE Assignments
I think that each of the reported security issues 3.a, 3.b, 3.c and 3.d
warrant CVE assignments.
# 1173749: [IN_PROGRESS] AUDIT-0: EMBARGOED: spice-vdagent: spice-vdagentd.service can be implicitly started by default
# Please enter the new comment. Lines starting with '#' will be ignored
# lines starting with ' #' will be kept
#
Upstream assigned a couple of CVEs and sent me some patches for review. There's no publication date known yet. I will create sub-bugs for each CVE for tracking. Created attachment 843022 [details]
final version of security patches
CRD: 2020-11-03
I will send a prenotification to the linux-distros mailing list for major distributions to be able to fix their packages before general publication. The CRD above is the designated publication date.
@brogers: can you please prepare internal IBS submissions using the patches found in attachment 843022 [details]? Thank you.
(In reply to Matthias Gerstner from comment #18) > CRD: 2020-11-03 > > I will send a prenotification to the linux-distros mailing list for major > distributions to be able to fix their packages before general publication. > The CRD above is the designated publication date. > > @brogers: can you please prepare internal IBS submissions using the patches > found in attachment 843022 [details]? Thank you. Working on it. v0.20 based spice-vdagent package is prepared and basically ready to submit when embargo lifts. v0.19 based spice-vdagent package is being worked on. I never saw a time on the Embaroged Date (today), but I see that the upstream vdagent project git repo has already included these patches. I assume that means the Embargo is lifted now, but I will wait for the security team to indicate so. I've got the openSUSE side of things ready to submit and am evaluating older releases to see exactly what is needed. Quite a bit is different for those older releases so it is taking some time. I do not see the reproducer code attached to this bug report. It may prove helpful in verifying the issue and fix for older releases. Could someone who has it provide it here? (In reply to brogers@suse.com from comment #22) > I never saw a time on the Embaroged Date (today), but I see that the upstream vdagent project git repo has already included these patches. I assume that means the Embargo is lifted now, but I will wait for the security team to indicate so. Yes, thank you for being prudent. We usually don't track exact embargo lifting times since most of the time some upstream person is responsible for actually publishing the information (and in different ways, too). Therefore we wait until we get a notification from upstream or for some other sign of publication before we lift the embargo on our end. I can confirm that the patches are now public in the upstream repository. I will therefore lift the embargo from our related bugs. > I've got the openSUSE side of things ready to submit and am evaluating older > releases to see exactly what is needed. Quite a bit is different for those > older releases so it is taking some time. You can submit the openSUSE updates now. Thank you for covering the maintenance and backports. If you need help with backporting or reviewing patches just say so. > I do not see the reproducer code attached to this bug report. It may prove > helpful in verifying the issue and fix for older releases. Could someone who > has it provide it here? I will attach the tarball to this bug in a jiffy. Created attachment 843289 [details] tarball containing the reproducers for the issues described in the report in comment 15 I published the security report now also on oss-sec [1]. [1]: https://www.openwall.com/lists/oss-security/2020/11/04/1 SUSE-SU-2020:3268-1: An update that solves four vulnerabilities and has one errata is now available. Category: security (important) Bug References: 1173749,1177780,1177781,1177782,1177783 CVE References: CVE-2020-25650,CVE-2020-25651,CVE-2020-25652,CVE-2020-25653 JIRA References: Sources used: SUSE Linux Enterprise Module for Desktop Applications 15-SP2 (src): spice-vdagent-0.19.0-3.3.1 NOTE: This line indicates an update has been released for the listed product(s). At times this might be only a partial fix. If you have questions please reach out to maintenance coordination. openSUSE-SU-2020:1898-1: An update that solves four vulnerabilities and has one errata is now available. Category: security (important) Bug References: 1173749,1177780,1177781,1177782,1177783 CVE References: CVE-2020-25650,CVE-2020-25651,CVE-2020-25652,CVE-2020-25653 JIRA References: Sources used: openSUSE Leap 15.2 (src): spice-vdagent-0.19.0-lp152.2.3.1 Removing the dependency to the VUL-0 bugs. They are now tracked by reactive security. The AUDIT is complete. Closing as FIXED. openSUSE-SU-2021:2614-1: An update that solves four vulnerabilities and has one errata is now available. Category: security (important) Bug References: 1173749,1177780,1177781,1177782,1177783 CVE References: CVE-2020-25650,CVE-2020-25651,CVE-2020-25652,CVE-2020-25653 JIRA References: Sources used: openSUSE Leap 15.3 (src): spice-vdagent-0.21.0-3.3.1 SUSE-SU-2021:2614-1: An update that solves four vulnerabilities and has one errata is now available. Category: security (important) Bug References: 1173749,1177780,1177781,1177782,1177783 CVE References: CVE-2020-25650,CVE-2020-25651,CVE-2020-25652,CVE-2020-25653 JIRA References: Sources used: SUSE Linux Enterprise Module for Desktop Applications 15-SP3 (src): spice-vdagent-0.21.0-3.3.1 NOTE: This line indicates an update has been released for the listed product(s). At times this might be only a partial fix. If you have questions please reach out to maintenance coordination. |