Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device "self-identity oriented" assignment #9325

Open
1 of 2 tasks
piotrbartman opened this issue Jun 24, 2024 · 6 comments
Open
1 of 2 tasks

Device "self-identity oriented" assignment #9325

piotrbartman opened this issue Jun 24, 2024 · 6 comments
Assignees
Labels
C: core P: major Priority: major. Between "default" and "critical" in severity. T: enhancement Type: enhancement. A new feature that does not yet exist or improvement of existing functionality.

Comments

@piotrbartman
Copy link
Member

piotrbartman commented Jun 24, 2024

Introduction

Currently, we can make one assignment of a selected port to a single VM in two ways:

  1. Using identity='any', which means that anything plugged into the designated port will be automatically attached to the VM, as it has been functioning thus far.
  2. Using the identity of the currently plugged device, in which case automatic attachment will only occur if the device presents itself in the same way.

Proposed enhancement

  • The ability to assign multiple different devices, so that if either of them is plugged into a specific port, automatic attachment occurs.
  • Automatically attach any device that presents itself as some type such as mass storage etc., and is plugged into a specific port.

More:

QubesOS/qubes-core-admin#579 (review)

The value to a user, and who that user might be

Increased security (less error-prone manual clicking/typing) and user convenience.

TODO

  • Handling of USB bus number changes is still not implemented. Check the parent PCI device (?)
  • Handle block devices ident (which is not persistent).
@piotrbartman piotrbartman added T: enhancement Type: enhancement. A new feature that does not yet exist or improvement of existing functionality. P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. labels Jun 24, 2024
@rocodes
Copy link

rocodes commented Jun 24, 2024

It will be great to have some autoattach controls :) Right now on SecureDrop Workstation we hack together some autoattach behaviour via udev rules, but it's a blunt instrument - I'm chiming in after a nudge from marek in case any of this info about our use-case is helpful.

  • On a per-vm basis, we'd like to be able to completely disable autoattaching, and separately, have the option to to disable any kind of peripheral attachment for a given qube (that last request may be more relevant to @marmarta 's work with the Devices widget and the underlying rpc policies but maybe it's relevant to mention here too). There are some qubes where autoattach is fine/desired; there are some where we wouldn't want autoattach but we would want the ability to manually attach certain USBs because the manual attachment option is a second layer of user confirmation; and there are some qubes that shouldn't allow any peripherals to attach at all.
  • With the per-port autoattach: In our context, two devices could have the exact same "profile" (eg single-partition encrypted mass storage device) but one could be trusted and one could be untrusted. So we'd theoretically be a good candidate for the per-port configuration as a way to help distinguish those devices ... assuming we could still configure it carefully and/or disable it if we are too worried about user error. The mental model that "all usb ports are not created equal" is uncommon, particularly for our users (journalists), so we would want the difference in using the two ports to be one of convenience, not of security, which is where the restrictions I mentioned in the previous bullet come in.

Some last notes about user feedback:

  • We implemented the udev "autoattach" in SDW after users found the USB attachment process confusing
  • However, even with a version of autoattach where we pre-attach the correct device to the correct qube for the user and present a GUI wizard telling them what to do, we have still had reports of users manually detaching the USB drive from the correct qube and attaching it to a different (wrong) qube. So the UX/mental model will always be a factor for a certain segment of users, even when the attach process is automated.

Hope this information is helpful!

@andrewdavidwong andrewdavidwong added P: major Priority: major. Between "default" and "critical" in severity. and removed P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. labels Jun 25, 2024
@marmarta
Copy link
Member

On the specific USB port side, the problem is that if you don't limit attaching to a specific USB port, we can have a huge security issue - devices can lie about their identity, a USB hub complicates things etc. I think the security team had a lot of opinions on why we can't have "any port" here.

@piotrbartman piotrbartman self-assigned this Jun 25, 2024
@piotrbartman
Copy link
Member Author

piotrbartman commented Jun 29, 2024

Proposal: Device Assignment Policy

For now, a device is represented by the pair (backend-vm, ident), which aligns more with a Port. In the user's mental model, we equate a Device with what is plugged into the Port. The issue is that only (backend-vm, ident) can be trusted, while all information about the device is obtained from the Device itself, which is less trustworthy.

Proposed solution:

A set of rules as follows:

frontend-vm    backend-vm    devclass    port_id    device    action

Allowed Values::

*-vm:

  • explicit vm name, e.g., sys-usb
  • * wildcard
  • [tag]

devclass:

  • *, usb, block, pci, etc.

port_id:

  • name with wildcards, e.g., sd* or 3-[0-1]

device (self_identity):

  • <vendor_id>:<product_id>:<serial if any>:<interface1interface2...>
  • vendor_id: Full ID or *
  • product_id: Full ID or *
  • serial: serial, empty string, or *. Empty string means the device does not have a serial number, and we do not accept any.
  • interface: in the form x******, where x corresponds to devclass (u, p, b, t, ?, *, ), followed by 6 hex characters. Each character can be hex or wildcard. Multiple interfaces can be used one after another, without spaces. The order is significant but should it be (?). Alternatively, * can be used to accept all interfaces in any number.

action:

  • required: The device is required to start the frontend-vm and will be automatically attached. Requires specifying frontend-vm and backend-vm by explicit VM name.
  • auto: The device will be automatically attached if available at the start of frontend-vm or if plugged in later. It can be detached and reattached at any time. Requires specifying frontend-vm and backend-vm by explicit VM name.
  • allow (default): The device can be manually attached to the frontend-vm at any time when it is running.
  • deny: The device cannot be attached to this frontend-vm.

Pros:

  • Easily create a VM (type VAULT) to which external devices cannot be accidentally attached.
  • Automatically attach all mass-data devices to a specific VM.

Security Level Comparison to the Current Level:

Possible attack: A device can pose as a trusted device and be set to auto-attach to a sensitive VM.

  • This must be a deliberate attack: someone must spoof the serial number of the chosen device, having had access to it.
  • The attack is impossible if ident = * is not used for sensitive VMs.

Additionally, device interfaces are checked, so auto-attach limited to mass data could be even safer than manual configuration. When a user plugs in a pendrive with a keyboard interface, it will not be automatically attached, whereas an unaware user might miss this and manually attach the device.

This proposal still introduces some risk, but less than using a USB keyboard.

More granural Security Control:

my-vm    sys-usb    usb    1-1.1    *:*:*:u08*    auto
my-vm    *          *      *        *:*:*:u03*    deny

This policy automatically attaches only devices declaring mass data type to my-vm, but not multimedia devices. It will not allow attaching input devices like keyboards/mice. In the current model, if the user mixes up ports, which is likely, auto-attach has no more safeguards.

Using automation is practically safer than relying on manual configuration.
For applications based on QubesOS, this will allow easy system configuration, increasing user resilience.

@marmarta
Copy link
Member

marmarta commented Jul 1, 2024

I think I like it, although I'm already thinking about how non-simple it's going to be to expose simple GUI config options :D But that's my problem - this looks like good backend.

@marmarek
Copy link
Member

marmarek commented Jul 1, 2024

Proposed solution:

A set of rules as follows:

I think I'm missing some higher level context. Currently device assignments are stored in DeviceAssignment objects, attached to appropriate QubesVm objects (related to the frontent qube). How this proposal maps to the current API? Or does it abandon the objects idea completely? If so, how various actions like attach/detach/assign etc are going to work? By editing the file (with some API?) and then backed doing diff and figure out what should change? Or maybe existing methods would edit rules you propose here (how does it map then?). For example, if you add an "auto" rule for device that is already present in the system (and frontend qube is running), should it automatically get attached immediately?

The proposed idea for rules (especially actions and identity properties) as a concept looks fine, but there should be some connection to the current model. And here, I'm not sure if the idea of a single flat table as the user-facing (or even an API) approach is a good one. We'll run into various issues regarding presenting this to users, rules ordering (especially when changed both by the users manually, and using some CLI/GUI tools) etc. Maybe a better approach would be to still consider this in terms of objects attached to appropriate qube (either frontend or backend, may depend on the rule?) possibly at the cost of some flexibility. But then, we may have cases where not having explicit rules order will be a problem, especially in case of conflicting rules ("allow only specific device and deny all others" or "deny specific class of devices but allow others"). This could be solved with rules (objects attached to VMs) having a priority (a number). That said, it feels like re-introducing weaker version of rules order, compared to the flat table giving full ordering...

To put this all in other words: I think the flat table you propose gives too much flexibility, that will make supposedly simple cases (like "click here to always attach this device to qube X") significantly harder due to potential interaction with other rules. We had this problem before already, twice (firewall, and qrexec policy). And in both cases it ended up with GUI tools more or less giving up if user added any non-default rule manually (in case of firewall, it literally tells you to go to CLI and disables any kind of editing; in case of qrexec, it complains about the custom rules, and depending where you put them, warns you they will get removed if you continue). I'd like to avoid this situation with this API...

Maybe we should start with collecting use cases we want to support? Do you have a list like this already somewhere? If not, here are some ideas (partially based on earlier comments here):

  1. Deny attaching any device to particular qube
  2. Automatically attach a specific device plugged into a specific port to a specific qube
  3. Same as 2, but refuse to start a qube if device is not available in the system
  4. Allow attaching only device of a specific class to a qube, deny others
  5. Allow attaching only specific device to a qube, but don't do that automatically (might be useful if you have 2+ qubes with a rule for such device).
  6. Allow attaching a device to a specific qube only if it's plugged into a specific port
  7. Same as 6 but with auto-attach (not sure about this one...)

I'm probably missing many cases...

@piotrbartman
Copy link
Member Author

Ok, I see the problem. I agree that reducing the flexibility of the solution would be the best approach.

Currently, when a device is connected, we rely on information from the qubes.xml file. If we assign the same port to two different VMs and both are running, the device connected to that port will be attached to the VM that appears earlier in app.domains. This is unintuitive. The problem here is clarity and lack of control. We want the user to easily check in one place what is connected to what, and which VMs cannot have anything attached. Such a table can be generated as read-only for quick viewing, and can also be stored in a file for better performance, which, in principle, should not be manually edited like qubes.xml. Changes should still be made via qvm-device.

Let's introduce the following restrictions:

  1. frontend-vm must be explicitly specified. This will maintain the concept that assignment connects a device/port with a qube. The key difference underneath is the separation of port and device.

  2. The deny list can be moved to a separate table. This is additional functionality. It will significantly reduce the complexity of the rules. Deny will "override" auto-attach and will not allow the device to be connected if any rule matches. Deny can be bypassed with the --force flag during attach. For simplicity, we can limit this to interface dependencies (which include devclass), meaning we may want to prevent devices of a certain type from being connected, e.g., no:

    (a) devices at all (this does not apply to PCI devices since they cannot be connected manually anyway),

    (b) USB devices,

    (c) mass data/HID type devices,

    (d) USB mass data type devices,

    (e) etc.

    I do not see a use case for not connecting specific devices. We can also have interface + port.

  3. allow can be removed, as it is just the default behavior.

  4. auto-attach and required assignments should assign a port or specific device. Auto-attaching based on a device interface or a class need to be discussed.

Algorithm

So, the mechanism would work as follows:
After connecting a device, the rule table would be checked line by line, and the first match would be considered. If the VM from this match cannot accept the device because it is turned off or the device is excluded by the denied list, the next rows are checked.

This method might not be super intuitive, but it meets the basic needs:

  • We can predict which VM something will be automatically connected to.
  • Thanks to denied rules we can easily stop auto-attach to a VM. It is important to note that such an exception might cause attachment to another VM, but there must be a preceding rule for that.
  • When trying to add a rule, it will be possible to check if it conflicts with others and warn the user.

We need add command to change the rule no.

How this proposal maps to the current API?

Assignment is still tied to the frontend. It should be considered of as a request from frontend-vm to attach a device with specific parameters.

By editing the file (with some API?) and then backed doing diff and figuring out what should change?

We can introduce a new file or keep all this information in qubes.xml as it is now. Now we have such table hidden in qubes.xml. The file would be updated by qvm-device and loaded only during VM startup/device connection.

For example, if you add an "auto" rule for a device that is already present in the system (and frontend qube is running), should it automatically get attached immediately?

No, we will maintain the current behavior.

Tables

Modified tables can looks as follows (it is hidden in qubes.xml for now):

Auto-attach rules:

rule no.    frontend-vm    backend-vm:port_id    device    action    options

rule no.:

  • auto generated rule number. First is the most important. The new rule will get next available number.

frontend-vm:

  • specific vm.

backend-vm:port_id:

  • specific backend-vm:port_id or any.

device:

  • specific device identity or any

action:

  • auto-attach or required.

options:

  • attach options.

Device attachemnt restriction:

frontend-vm    interfaces

frontend-vm:

  • specific vm.

interfaces:

  • coma seperated interfaces like in original.

Interfaces can be easily translated to user-language like: mouse, keyboard, mass-data. From the point of GUI it can be represented as tree, where the user can choose which nodes/branches are allowed or not:

frontend-vm-1
   all
    |-pci
    |  |- ...
    |-usb
    |  |-HID
    |  |  |-mouse
    |  |  |-keyborad
    |  |  |-other```
    |  |- ...
    |- ...
frontend-vm-2
   all
    |- ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: core P: major Priority: major. Between "default" and "critical" in severity. T: enhancement Type: enhancement. A new feature that does not yet exist or improvement of existing functionality.
Projects
Status: In review
Development

No branches or pull requests

5 participants