QubesOS / qubes-issues

The Qubes OS Project issue tracker
https://www.qubes-os.org/doc/issue-tracking/
529 stars 46 forks source link

Feature: Trusted stream for webcam input #2079

Open tasket opened 8 years ago

tasket commented 8 years ago

Create a uni-directional (flowing from non-networked webcam vm) webcam stream that is sanitized in much the same way as static images or pdfs. Or, more accurately, similar to microphone input.

This could show up as a device Attach/Detach option in appvm context menus alongside the microphone, and would enable videoconferencing sessions with trusted services and peers. Ultimately, this feature would help enable an important PC use case: Telecommuting and conferencing with video and window streams.

Technical: Even though re-compression of the stream would have to occur (probably in the vm running the conferencing app) this should be feasible today if resolution and frame rate are kept at a moderate level. Bounds-checking will have an added dimension: Frame rate. If the stream is pushing more than a certain percentage over a set frame rate for the last n seconds, receiving vm will drop excess frames.

marmarek commented 8 years ago

In theory it is good idea. In practice it probably will fail on performance. In 3.2 we've got USB passthrough. When used for webcam (raw USB packets, most likely compressed) it already results in very high CPU usage. If some additional processing would be added (for example converting to "simple representation"), almost for sure it would be too slow.

But if that performance problem would be solved somehow, it would be much better for video conferences than full USB passthrough.

This wouldn't solve privacy problem completely (sys-usb still would be able to sniff all the video stream, and later leak it through some other USB device). But this problem is very hard to solve (if possible at all) with the current hardware (lack of encrypted videostream from webcams, lack of secure way of isolating single USB device).

tasket commented 8 years ago

Yes, today's announcement is what gave me the idea because the security risk still exists with USB passthrough.

I've seen how re-encoding streams in real time can work even in a laptop appvm. It may drop frames, but its not at all terrible. Firefox extensions that can screen-grab video players are a good example: https://www.downloadhelper.net

It may even be the case that PCI passthrough for GPUs becomes more stable and thus enables a sanitized video stream to be efficiently re-encoded in real time.

tasket commented 8 years ago

Discussion thread at qubes-devel.

nothingmuch commented 8 years ago

I found this:

https://github.com/umlaeute/v4l2loopback

For my use case, work hangouts in google chrome, this might be enough because it uses V4L2 (https://src.chromium.org/viewvc/chrome/trunk/src/media/video/capture/linux/video_capture_device_linux.cc)

At least in principle it should be possible to capture video input in sys-usb (without even demuxing, let alone decoding), and expose it as an opaque data stream to the appvm instead of as a USB device, and feed it into the loopback video driver in the appvm's userspace. It might even have less overhead than USB forwarding, if it uses buffered IO and avoids treating the data stream as anything more than binary data.

Note, I'm not really familiar with V4L so please assume I have no clue what I'm talking about.

stiell commented 7 years ago

USB passthrough did not work for me, so I've tried an approach similar to that described by @nothingmuch and can confirm that it works. I used ffmpeg on sys-usb to feed webcam input to a Qubes RPC pipe going to the appvm, where it would be decoded by ffmpeg and fed to a v4l2loopback device.

marmarek commented 7 years ago

@stiell do you care to share the scrips?

stiell commented 7 years ago

Instructions moved here from #2594:

Here are the steps I took to let an appvm, here destvm, use a webcam connected as /dev/video0 in sys-usb.

In the template for destvm

Add /etc/qubes-rpc/local.VideoLoopback:

read size pixfmt
ffmpeg -s "$size" -f rawvideo -pix_fmt "$pixfmt" -i - -f v4l2 \
    /dev/video0

In destvm

v4l2loopback needs to be installed. Clone the source repository:

git clone https://github.com/umlaeute/v4l2loopback.git
cd v4l2loopback

Check out a signed release. You might want to perform the signature verification on a different VM where you keep your public keyring.

git tag -v v0.10.0
# Should show a valid signature from B65019C47F7A36F8, which is in the
# strong set.
git checkout 9e2be44eba154cbcf58ad5bc73d30360080bd8c9
# Same hash as in the output of the git tag -v command above.

Compile the code. You may have to install some build dependencies first. You may also have to change the VM kernel to match the version of kernel-devel.

sudo dnf install make kernel-devel gcc
make

Load the module. I couldn't find a good way to install the module, as the device backing /lib/modules/* is read-only. Therefore just load the dependencies manually and then use insmod. Firefox and Cheese need exclusive_caps=Y, otherwise they won't recognise the device.

sudo modprobe videodev
sudo insmod v4l2loopback.ko exclusive_caps=Y

In dom0

Add /etc/qubes-rpc/policy/local.VideoLoopback:

sys-usb destvm allow

In sys-usb

Add ./videoloopbackclient. You may have to change the size and pixfmt variables depending on what your device supports.

#!/bin/bash
size=640x480
pixfmt=yuyv422
echo "$size" "$pixfmt"
ffmpeg -f v4l2 -input_format "$pixfmt" -video_size "$size" \
    -i /dev/video0 -codec copy -f rawvideo -

Then run chmod +x ./videoloopbackclient.

Start feeding video from sys-usb to the device in destvm with:

qrexec-client-vm destvm local.VideoLoopback ./videoloopbackclient
olekli commented 5 years ago

Thanks for sharing those instructions!

On my system using ffmpeg-qrexec stream is roughly the same overhead as using USB forwarding. ffmepg does seem to have a slight latency though. But it's barely noticeable and I doubt it will be an issue for video conferencing.

Issues remaining are: (1) Need to use HVM to have the kernel module. I believe this could be fixed by providing the right kernel through dom0, right? (2) The webcam will constantly stream while connected to a VM. This will result in a slight overhead (like 25% CPU usage on i7-8650U) and the webcam's LED will be on.

That last point I'm actually starting to see as a feature. The webcam's LED indicator will tell you that it is connected to a VM as a warning that the VM could start streaming video any time. You usually wouldn't want to have the stream connected for longer than you really use it. With USB forwarding there is a bigger risk of forgetting that your camera is connected to some VM.

There is also the advantage that the target VM will always have a valid video device available. So accepting a call on Skype while the webcam is not connected isn't a problem. You can simply connect the stream while the call is ongoing.

Furthermore this could be part of a solution for screensharing where you can switch between a stream from your webcam and one from x11grab.