Desktop interfaces moving forward

Today, desktop applications can use the unity7 or x11 interfaces or both. The original idea behind these was that

  1. they were transitional interfaces for legacy user session environments and
  2. unity7 only could run on x11, so it duplicated the X policy so developers need only specify ‘unity7’

The original idea is we would add interfaces for unity8, mir, wayland, gnome-shell, etc. Because of the time in which snapd involved (ie, we didn’t quite know where we were going: wayland, mir, unity8, gnome-shell, etc) the unity7 interface became a catchall for ‘legacy’ desktop security policy.

In working with this policy and examining the current landscape, I think we should rethink our current plans. Since it is reasonable to assume that most developers want their snaps to work on as many desktops as possible and because we want to provide a path towards a future with non-transitional, secure desktop policy, I propose we:

  • group all contemporary Desktop Environment default policy into a new desktop interface. Contemporary DE’s are defined to include those that can run without X. The policy shall be defined to be anything that can be reasonably confined[1] with access to common services (eg, gmenu). This interface will be autoconnected
  • display server policy shall not be duplicated in the desktop interface. Instead, snap developers specify which display server the snap is expected to work. In practice, they might plugs: [ desktop, mir, wayland, x11 ]. This is reasonable since developers would need to program their applications to work under different display servers and this declares where the snap is expected to work
  • break out accessibility into desktop-accessibility instead of having it included in desktop. a11y was not designed for application isolation and allows sniffing and injecting input events. The deficiencies of a11y were recently acknowledged within GNOME and, aiui, flatpaks currently can’t access the accessibility bus. We will allow specifying it as (possibly manually connected)[2] interface but as the security story improves upstream wrt accessibility, we can always add it to the desktop policy
  • continue to have legacy DE policy in the unity7 interface, including duplicated x11 policy so that existing snaps continue to work like always

With the above, we strive for desktop to be non-transitional, safe security policy and only add safe accesses to it. Unsafe/transitional accesses are broken out into other interfaces, like desktop-accessibility and password-manager-service. Since applications need to be coded to work with different display servers and because we want users to be able to disconnect x11, display servers are also in their own interfaces instead of duplicated in the desktop interface.

snapcraft.yaml wanting to target today’s legacy DEs remains unchanged[3]:

apps:
  foo:
    plugs:
    - unity7
    - x11

snapcraft.yaml for applications that want to add the new contemporary DE policy to their existing legacy DE policy simply add desktop and optionally desktop-accessibility and wayland:

apps:
  foo:
    plugs:
    - unity7
    - x11
    - desktop
    - desktop-accessibility
    - wayland

The above allows the snap to work everywhere, but the security-conscious user running a wayland desktop can snap disconnect foo:x11 && sudo snap disconnect foo:unity7.

snapcraft.yaml for applications expected to work only on contemporary DEs (eg, gnome-shell, plasma, sway) that may have an X fallback (eg, gnome-shell, plasma) simply adds the new desktop and desktop-accessibility interfaces:

apps:
  foo:
    plugs:
    - desktop
    - desktop-accessibility
    - wayland
    - x11

The above allows the snap to work under X or Wayland, but the security-conscious user can snap disconnect foo:x11. In the future, when X11 is gone snap developers just drop x11.

I believe the approach outlined in this topic allows us to remain compatible with all existing snaps, have reasonable snapcraft.yaml declarations for snap developers, provides a path forward for non-transitional and secure desktop policy and at the same time allows users to experiment today with disconnecting transitional policy.

[1] reasonably confined because it is not expected that every desktop DBus session service is currently coded with application isolation in mind. In other words, some things are still transitioning
[2] we could consider this an auto-connectable transitional interface (eg, like gsettings). Because it is broken out into its own interface, a security-conscious user could always disconnect it.
[3] as it happens, even though unity7 duplicates the policy in x11, most developers specify both (another reason to not duplicate with the new interfaces)

3 Likes

@niemeyer and @jamesh - when you get a chance, can you review/comment on this?

That plan sounds great. It’s sort of where we were going towards as you mentioned, but adding that new desktop interface to the mix will greatly simplify the problem in terms of implementation and understanding.

The one thing which might be worth changing is calling desktop-accessibility simply as accessibility, similar to the other interfaces in this group. Do you see a reason for the explicit prefix in that case.

No. I think accessibility is better. I can’t really think of anything like that for cli/server installs so seems fine. I’ll update the PR.

1 Like

My main concern of splitting up the interfaces is that developers may only enable the interfaces that they personally need to get the app working.

I am particularly concerned about splitting off accessibility: GTK apps generally have some level of accessibility support by default, and we’d be cutting that off by default. From a social perspective I’d prefer if the path of least resistance resulted in making the app usable to all.

I agree that the way a11y was exposed to the unity7 interface is too open. I guess it’s time to dig in to the what D-Bus calls are made over the a11y bus exactly, and whether we can have a confined app present itself in such a way that an unconfined a11y tool can control it.

As for display server access, I think splitting them out sounds like a good idea. It would be good if we could have Snapcraft do some form of linting to suggest people include both the wayland and x11 interfaces together with desktop though so the snaps are future proofed. This would also provide a way to ratchet down X11 access in future releases. Perhaps something like the following:

  1. autoconnect both x11 and wayland
  2. autoconnect wayland, and only autoconnect x11 if not used with wayland
  3. only autoconnect wayland
  4. stop providing x11 slot on core snap

This way we could incrementally tighten things up while keeping 16.04 working.

I looked at the DBus calls before proposing this and the policy is here:
https://github.com/snapcore/snapd/pull/3719/files#diff-ab80baef68f0be37c567f9a89723373cR32

From reading the policy you can see that it has a wide open ‘receive’ rule from any unconfined process using the accessibility bus. The problem is in the send rules and the way the API is designed, it uses integers rather than security labels for sending requests to a11y which means AppArmor can’t protect against attacks on the API (it can’t map the a11y application identifier to the security label). I did not write a POC to demonstrate how it could be abused because it is clear that the API today cannot be safely mediated and through discussions on the AppArmor mailing lists recently[1]:

“In the case of universal access technologies, we briefly looked at the
AT-SPI accessibility bus during a GTK/Flatpak hackfest, and came to the
conclusion that it is terrifying - it’s an ideal place to put a keylogger,
or take control of windows outside the sandbox. That’s why Flatpak does
not give access to that bus. If we are going to have a11y that works for
sandboxed apps and does not fundamentally undermine security, it will
have to be designed for the purpose by someone who understands both the
security model and the needs of a11y. At a minimum, it would need a
concept of more- and less-privileged peers on the bus, which it
currently lacks.”

I then tested a11y in gnome-shell under confinement and also used the check-a11y tool from https://www.freedesktop.org/wiki/Accessibility/AT-SPI2/ to see what typical accesses are, and it was clear that wide access is required for a11y to work. It is of course possible to modify a11y to be a trusted helper and either adjust its API or have it perform LSM checks at strategic points, but even if this was upstreamable, it would not be available to all distros any time soon and we would need this transitional interface.

All combined, I decided to not pursue creating a crippled accessibility interface but instead to implement a fully functional interface that could be disconnected. Because of the nature of interfaces, it is not possible to disconnect parts of the interface[2].

Specifically to this point: “My main concern of splitting up the interfaces is that developers may only enable the interfaces that they personally need to get the app working.” I don’t think this will be a problem in practice for several reasons:

  • as part of this work I plan to write a forum ‘doc’ topic on the subject, with example yaml and discussion of when to use what. This doc will suggest to always plugs both desktop and accessibility (formerly desktop-accessibility).
  • if the developer forgets to plug the accessibility interface (or it is disconnected), when running the application, there will be denials logged just as part of application startup[3]. When putting an application in strict mode, one necessarily must look at the logs to see what interfaces to plug, so the need for the interface is discoverable[4]
  • snapcraft (parts) could reinforce what to add. Today the desktop part has a list of things to add to ‘plugs’. This can be updated to include desktop and accessibility
  • when upstream has reworked the a11y system to be safe, we will simply add it to desktop, leaving accessibility as a legacy transitional interface like x11
  • if a developer forgets to add the interface and someone reports the bug to the develoepr, it is trivial for the developer to add accessibility to the plugs of the snap to fix the bug
  • if the above points aren’t enough, we can add a check to the review tools to warn if accessibility is not specified with desktop (note, this strongly enforces they always be used together because not specifying accessibility would trigger a manual review in the store. I don’t recommend this)

[1]https://lists.ubuntu.com/archives/apparmor/2017-August/010943.html
[2]it is actually possible via attributes (see the docker snap), but this is opt-in by the developer and is much more complicated than simply adding the interface to plugs
[3]apparmor="DENIED" operation="dbus_method_call" bus="accessibility" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="Hello" mask="send" name="org.freedesktop.DBus" pid=9841 label="snap.gedit.gedit" peer_label="unconfined"
[4]snappy-debug will suggest the interface too, once parsing DBus rules is supported by the tool

This makes a lot of sense and is along the lines of what I was thinking too.

This topic is part of the continued tension between usability and confinement. The path of least resistance and least trouble is to make everything wide open and accessible to everyone. That’s why we have classic confinement in place. This path is also the one that leads to no protection to the system and to the user.

If we find a way to enable accessibility in a confined way, then obviously that’s the best outcome. If we can’t confine it properly, then we need to make a decision about whether to split it out, or whether to not split anything at all. Splitting x11 from wayland for safety and then making the application widely exposed via a different API won’t help much.

Thanks for looking into this. Again, that would be the best outcome.

That sounds like an argument about whether or not the accessibility framework should be exposed to confined apps. But here we’re talking about whether it should be in its own interface or merged into the main desktop interface. And if we decide to autoconnect the accessibility interface, we’re in pretty much the same situation as if it was in desktop: the only difference is that developers can now accidentally make their app unaccessible.

I’m not sure what the best solution is, but I think it’d be good to have a solid rationale for whatever we decide. Even if we go for separate interfaces in the short term, I think it would be good to aim to add “secure next gen a11y” to the desktop interface in the future.

I gave the rationale: you are right that in practice there is no difference for most people if we auto-connect them than if we had them in the desktop interface to begin with. The point is to move to a future world where a desktop snap doesn’t need any unsafe accesses-- keeping desktop as safe as we can and having additional transitional interfaces on the side until we get there is a step towards that. If it (a11y, but the same applies to desktop-input) is in the desktop interface, there is no way to move forward and remove unsafe accesses without breaking applications.

If it is separate:

  • we can add to desktop the future safe accesses for accessibility and desktop-input
  • people can choose to experiment with accessibility and desktop-input as disconnected interfaces, thus helping us make sure desktop is solid. This happens to provide immediate benefit today for security-conscious users that opt into it
  • we ensure compatibility going forward. As desktop evolves and has safe a11y and input methods, snap developers on a stable series (ie, series 16) can choose to remove accessibility and desktop-input during that series, without having to wait for a future series 18 or 20 to remove the unsafe accesses from the desktop interface. Snaps that are slow to change continue to work fine

I also mentioned that through documentation, snapcraft parts, snappy-debug, etc, etc we can make this easy for snap developers. The typical user will not need to understand any of this.

2 Likes

From https://github.com/snapcore/snapd/pull/3719#issuecomment-325010569:

"Ok, Gustavo and I talked about this with James’ comments in mind. The plan of action is:

  • create the ‘desktop’ interface that contains only safe accesses (ie, what is proposed)
  • create a ‘desktop-legacy’ interface that is auto-connected today that contains accessibility and input methods
  • adjust the snapcraft desktop part to suggest adding these interfaces

What this allows is:

  • any snaps that currently use unity7, x11, etc continue to work without modification
  • for snaps that add desktop and desktop-legacy
    • they get support for gnome-shell, plasma, sway, etc
    • we’ll add safe accesses to the desktop interface as they arrive (eg, portals, upstream ibus changes, etc) and snaps benefit without modification of snapcraft.yaml
    • we have the opportunity to add other unsafe accesses to the ‘desktop-legacy’ catch-all interface in case there are other services/etc that should be added and snaps benefit without modification of snapcraft.yaml
    • sometime in the future, when ‘desktop’ has everything a desktop snap reasonably needs, we’ll make desktop-legacy, x11 and unity7 manually connected (not necessarily at the same time). This will allow snaps using standard toolkits to continue to work without needing to update their snapcraft.yaml (ie, they may continue to plugs both, but only ‘desktop’ is auto-connected). Snaps legitimately needing desktop-legacy can have a snap declartation for it
    • security-conscious people and developers improving desktop security can experiment with disconnecting ‘desktop-legacy’ today"