interfaces/builtin: add location interface #1118

Merged
merged 17 commits into from May 19, 2016

Conversation

Projects
None yet
5 participants
Contributor

ssweeny commented May 3, 2016

Add the location-service interface.

There were no pre-existing AppArmor or SecComp rules for the location-service so I had to write those from scratch, and I expect some cleanup will be needed.

interfaces/builtin/location_service.go
+# gives privileged access to the system.
+# Usage: reserved
+
+ # DBus accesses
@zyga

zyga May 3, 2016

Contributor

Since we're seeing the same dbus rules copy-pasted in various places I was wondering if this should be something we can stick in a function somewhere and reuse. I'd also like to see at least one # comment above them to explain what each of those dbus (...) rules do so that other people don't have to wonder.

interfaces/builtin/location_service.go
+ dbus (receive, send)
+ bus=system
+ path=/
+ interface=org.freedesktop.DBus**,
@zyga

zyga May 3, 2016

Contributor

Why ** and not *?

@ssweeny

ssweeny May 3, 2016

Contributor

I may have cribbed that stanza from bluez

+ }
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(string(snippet), testutil.Contains, "peer=(label=snap.location-service.{app1,app2}),")
@zyga

zyga May 3, 2016

Contributor

This will need small refresh after #1117 lands

interfaces/builtin/location_service.go
+type LocationServiceInterface struct{}
+
+func (iface *LocationServiceInterface) Name() string {
+ return "location-service"
@niemeyer

niemeyer May 3, 2016

Contributor

Let's rename this to simply "location" please, and rename the code accordingly.

@ssweeny

ssweeny May 3, 2016

Contributor

I was on the fence about that. Will do.

interfaces/builtin/location_service.go
+ interface=org.freedesktop.DBus.Properties
+ peer=(label=unconfined),
+
+ # Allow binding the service to the requested connection names
@niemeyer

niemeyer May 3, 2016

Contributor

That seems right to be on the permanent slot. But why do we allow below for the service to be sending/receiving on its own interfaces permanently? Does it need to talk to itself when not connected to another snap? If not, maybe we can constrain these further and only allow the snap to talk to peers that are connected too. Something worth trying.

@ssweeny

ssweeny May 3, 2016

Contributor

Some of the included providers talk to the service over dbus, so L-S does need to talk to itself. It may not need to do so if there are no connected clients, so I'll look into that.

interfaces/builtin/location.go
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member={Request,Release}Name
+ peer=(name=org.freedesktop.DBus),
@jdstrand

jdstrand May 3, 2016

Contributor

Should this use peer=(name=org.freedesktop.DBus, label=unconfined)?

interfaces/builtin/location.go
+ path=/org/freedesktop/DBus
+ interface=org.freedesktop.DBus
+ member=GetConnectionUnixUser
+ peer=(label=unconfined),
@jdstrand

jdstrand May 3, 2016

Contributor

These can be combined like so:
dbus (receive, send) bus=system path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=GetConnectionUnix{ProcessID,User} peer=(label=unconfined),
That said, shouldn't this both just use (send)?

interfaces/builtin/location.go
+ bus=system
+ path=/org/freedesktop/*
+ interface=org.freedesktop.DBus.Properties
+ peer=(label=unconfined),
@jdstrand

jdstrand May 3, 2016

Contributor

Can this path be refined?

interfaces/builtin/location.go
+ dbus (receive, send)
+ bus=system
+ path=/com/ubuntu/location/Service{,/**}
+ interface=com.ubuntu.location.Service*,
@jdstrand

jdstrand May 3, 2016

Contributor

This is pretty broad and says anything can use this (globbed) interface and all paths. It is hard to recommend how to fix since it is so general. I suggest adding peer=(label=@{profile_name}) for these and then add ConnectedSlot rules for server side rules for specific clients for any other rules. In this manner, both sides of the connection are mediated (client to server and server to client).

I know with 15.04 we said that we'd have wide open policy for the service and let the client rules handle things, but with interfaces we can be much more precise. I think I suggested this with either bluez and/or nm, but it doesn't look like it was implemented. Sorry the recommendations are changing a bit but now that we are understanding how permanent slots, connected slots and connected plugs can work together, we should take advantage of it. (not quite sure how to utilize PermanentPlug yet, but we'll see).

Once this is worked out for location service, please follow up on bluez and network-manager.

Thanks!

interfaces/builtin/location.go
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member={Start,Stop}VelocityUpdates,
@jdstrand

jdstrand May 3, 2016

Contributor

Same for all of these.

interfaces/builtin/location.go
+ dbus (receive, send)
+ bus=system
+ path=/com/ubuntu/location/Service{,/**}
+ interface=org.freedesktop.DBus**,
@jdstrand

jdstrand May 3, 2016

Contributor

Please use peer=(label=unconfined) here.

interfaces/builtin/location.go
+
+dbus (send)
+ bus=system
+ peer=(name=com.ubuntu.location.Service, label=unconfined),
@jdstrand

jdstrand May 3, 2016

Contributor

I don't understand this rule. It is too general and the label for unconfined is confusing (the server side should be handled be the previous rule). Is this for dbus-daemon interface and or paths? If so, please be more specific.

interfaces/builtin/location.go
+# Allow all access to location service
+dbus (receive, send)
+ bus=system
+ peer=(label=###SLOT_SECURITY_TAGS###),
@jdstrand

jdstrand May 3, 2016

Contributor

This is saying that the entire location-service API is and always will be ok for the location. I see you said "Allow all access to location service" but I wanted to call this out.

@niemeyer

niemeyer May 3, 2016

Contributor

Yeah, this seems rather dangerous. It assumes we know what will be exposed via this API in the future, which is always a bad bet in terms of security.

interfaces/builtin/location.go
+
+dbus (send)
+ bus=system
+ peer=(name=com.ubuntu.location.Service.Session, label=unconfined),
@jdstrand

jdstrand May 3, 2016

Contributor

I don't understand this one either.

@niemeyer niemeyer changed the title from interfaces: builtin: Add location-service interface to interfaces/builtin: add location interface May 3, 2016

interfaces/builtin/location.go
+recvmsg
+sendmsg
+sendto
+`)
@jdstrand

jdstrand May 3, 2016

Contributor

@zyga - in some ways I feel like it would be convenient if we could have a function for dbus seccomp slot/plug policy that all these snaps could use, since it is just getting copied around. The downside is it make policy audits quite a bit harder.

That should not block this PR.

@zyga

zyga May 4, 2016

Contributor

I agree, I will look at making helpers for well-understood snippets.

interfaces/builtin/location.go
+ <allow send_destination="com.ubuntu.location.Service"/>
+ <allow send_destination="com.ubuntu.location.Service.Session"/>
+ <allow send_interface="com.ubuntu.location.Service"/>
+ <allow send_interface="com.ubuntu.location.Service.Session"/>
@jdstrand

jdstrand May 3, 2016

Contributor

Can you fix the whitespace issues?

Contributor

niemeyer commented May 3, 2016

Several good comments from Jamie. Let's see if we can iron these details out until Jamie is pleased with this interface, and then take the lessons on to bluez and network-manager.

interfaces/builtin/location.go
+ <allow send_destination="com.ubuntu.location.Service"/>
+ <allow send_destination="com.ubuntu.location.Service.Session"/>
+ <allow send_interface="com.ubuntu.location.Service"/>
+ <allow send_interface="com.ubuntu.location.Service.Session"/>
@jdstrand

jdstrand May 3, 2016

Contributor

In addition to the whitespace issues, how this is supposed to work is that the server side binds to com.ubuntu.location.Service and the client side to com.ubuntu.location.Service.Session. Clients talk to com.ubuntu.location.Service and the service can talk to clients via com.ubuntu.location.Service.Session?

If that is accurate, why does PermanentSlotAppArmor allow the server to bind to both? Shouldn't it only allow binding to com.ubuntu.location.Service and the ConnectedPlugAppArmor policy allow binding to com.ubuntu.location.Service.Session? Otherwise, can you elaborate on how this works?

ssweeny added some commits May 5, 2016

Move location service client interaction rules to ConnectedSlot
Move the service rules that are only useful when a client is connected
to a ConnectedSlot snippet.
Contributor

ssweeny commented May 6, 2016

@jdstrand @niemeyer I've rewritten the AppArmor rules to tie more specifically to the l-s API, and moved the rules that are only useful while a client is connected to the ConnectedSlot snippet. Is that more what you were looking for?

interfaces/builtin/location.go
+dbus (receive, send)
+ bus=system
+ path=/
+ interface=org.freedesktop.DBus*,
@jdstrand

jdstrand May 6, 2016

Contributor

If you put 'audit' in front of this rules (ie, 'audit dbus') and use location-service, it will generate a log entry. Can you paste these log entries here? I'm trying to understand what 'label=' should be use here).

@ssweeny

ssweeny May 6, 2016

Contributor

@jdstrand When I did this it added no additional lines to the log, so I tried removing it which had no ill effects. I'm dropping this stanza.

interfaces/builtin/location.go
+ bus=system
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member={Start,Stop}VelocityUpdates,
@jdstrand

jdstrand May 6, 2016

Contributor

Please use quotes when using AARE with dbus rules. Put plainly, use: member="{Start,Stop}VelocityUpdates",

interfaces/builtin/location.go
+ bus=system
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=PropertiesChanged,
@jdstrand

jdstrand May 6, 2016

Contributor

Nice! Note, you can combing many of these: eg, member="Update{Heading,Position,Velocity}"

@jdstrand

jdstrand May 6, 2016

Contributor

Now that we have all of these client rules, we should add peer=(label=###PLUG_SECURITY_TAGS###) for all of these (ie, the corresponding rule to your peer=(label=###SLOT_SECURITY_TAGS###) in locationConnectedPlugAppArmor).

interfaces/builtin/location.go
+ path=/com/ubuntu/location/Service
+ interface=org.freedesktop.DBus.Properties
+ member=Set
+ peer=(label=###SLOT_SECURITY_TAGS###),
@jdstrand

jdstrand May 6, 2016

Contributor

These could be combined with: member="{Get,Set}"

interfaces/builtin/location.go
+ path=/sessions/*
+ interface=com.ubuntu.location.Service.Session
+ member=UpdateVelocity
+ peer=(label=###SLOT_SECURITY_TAGS###),
@jdstrand

jdstrand May 6, 2016

Contributor

These can be combined with: member="Update{Heading,Position,Velocity}"

interfaces/builtin/location.go
+ bus=system
+ path=/
+ interface=org.freedesktop.DBus.ObjectManager
+ peer=(label=unconfined),
@jdstrand

jdstrand May 6, 2016

Contributor

This is probably ok, but I wonder if there are particular methods you are using and that might form a sort of boilerplate policy for all DBus services to ease maintenance.

Contributor

jdstrand commented May 6, 2016

The policy is really shaping up. Thanks!

I'm curious it you have test scripts, etc for this that could perhaps be added to the integration tests. Ie, it would be great to have a client connect to the service and then exercise the API and make sure the policy is correct. This would be great to have for bluez, network-manager, pulseaudio, mir, etc, etc too. :)

ssweeny added some commits May 6, 2016

Contributor

ssweeny commented May 6, 2016

My testing involves installing the snap in a VM (using @zyga's devtools) and running a couple of binaries to test the client/server connection. If that sort of thing is supported in the integration tests then I can add it.

interfaces/builtin/location.go
+
+func (iface *LocationInterface) ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ // FIXME: This doesn't handle multiple plugs
@ssweeny

ssweeny May 6, 2016

Contributor

@zyga I couldn't figure out how this should handle multiple plugs being connected to this slot.

@zyga

zyga May 17, 2016

Contributor

Remember that ConnectedSlotSnippet is called once for each connected (plug, slot) pair. Just return the data specific to a given connection here.

interfaces/builtin/utils.go
+ }
+ buf.WriteByte('"')
+ return buf.Bytes()
+}
@jdstrand

jdstrand May 6, 2016

Contributor

This function is identical to slotAppLabelExpr() except it takes a interfaces.Plug as an argument instead of interfaces.Slot. This code should be shared.

@ssweeny

ssweeny May 6, 2016

Contributor

I decided to make it a separate function in case changes would be required to handle multiple plugs.

interfaces/builtin/location.go
+ old := []byte("###PLUG_SECURITY_TAGS###")
+ new := plugAppLabelExpr(plug)
+ snippet := bytes.Replace(locationConnectedSlotAppArmor, old, new, -1)
+ return snippet, nil
@jdstrand

jdstrand May 6, 2016

Contributor

@zyga - not sure if this was considered when implementing this. There is a 1 slot to many plugs relationship so ConnectedPlug policy is fine to substitute ###SLOT_SECURITY_TAGS### for the slot, but ConnectedSlot policy needs to enumerate all the plugs that are connected to the slot to generate the correct label string for ###PLUG_SECURITY_TAGS###. @ssweeny and I weren't sure how to do that in the current code, if it was planned, etc.

@zyga

zyga May 18, 2016

Contributor

Hmm

This is not doable with the current API. The problem is that we'll get N snippets, not one snippet that understands there are N connections in place.

@zyga

zyga May 18, 2016

Contributor

Thinking about it, the pseudo-code for the process is as follows:

snippets := getAllSnippets(...)
blob := combineSnippets(snippets, "dbus")

Is there something we could do in the combine phase to merge such rules together?

Is there a solution that would not require us to combine this on snapd side and would make it somehow magically work on apparmor side?

EDIT: @jdstrand ^^

@jdstrand

jdstrand May 19, 2016

Contributor

"Is there a solution that would not require us to combine this on snapd side and would make it somehow magically work on apparmor side?"

Yes, not match by label which was what the original patch did. However, I requested this change because snapd is in a position to know all the labels so we can and should be much more precise. In other words, we go through all this trouble to connect a plug to a slot so the policy should fully enforce that as opposed to letting anything connect to the server slot and then only adding client plug rules. This allows us to be most correct and adds layered security (both sides instead of one).

EDIT: with frameworks we had no choice but to only have client rules, but with interfaces we can improve on that.

Contributor

fgimenez commented May 9, 2016

My testing involves installing the snap in a VM (using @zyga's devtools) and running a couple of binaries to test the client/server connection. If that sort of thing is supported in the integration tests then I can add it.

@ssweeny that's a perfect case for an integration test, to get started you can take a look at the readme https://github.com/ubuntu-core/snappy/blob/master/integration-tests/README.md, also the current tests have lots of examples of how things can be done https://github.com/ubuntu-core/snappy/tree/master/integration-tests/tests. Please do not hesitate to ping me or @elopio in case you need any help.

ssweeny added some commits May 16, 2016

Contributor

niemeyer commented May 18, 2016

Indeed, testing to ensure it continues working would be great. @fgimenez can you point @ssweeny to existing tests that check interfaces, specifically?

@jdstrand @zyga Any more comments on the interface or is this ready for merging?

Contributor

ssweeny commented May 18, 2016

@niemeyer @fgimenez once this is merged I can upload the location service snap to the store and write a test based on that.

Contributor

jdstrand commented May 18, 2016

The security policy LGTM now (thanks @zyga for clarifying the point regarding ConnectedSlotSnippet being called for each connection-- it might be worth documenting that in docs/....).

I do want to explicitly call out that compared to network-manager, this bus policy is both very simple and very open. I'm not saying that is a problem though since the interface is not autoconnected and apparmor will mediate unconnected snaps, just doing due diligence. :)

Contributor

niemeyer commented May 19, 2016

Let's please talk about the "very open" question online @jdstrand.

ssweeny added some commits May 19, 2016

Contributor

niemeyer commented May 19, 2016

Going in per discussions online on the channel today.

@ssweeny please don't forget the tests, when you have a moment.

@niemeyer niemeyer merged commit 35e390e into snapcore:master May 19, 2016

4 checks passed

Integration tests Success
Details
autopkgtest Success
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage increased (+0.07%) to 79.62%
Details

@ssweeny ssweeny deleted the ssweeny:location-service-interface branch May 24, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment