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. |