interfaces,interfaces/apparmor: convert apparmor code to SecurityBackend #744

Merged
merged 29 commits into from Mar 30, 2016

Conversation

Projects
None yet
4 participants
Contributor

zyga commented Mar 24, 2016

This branch converts the older apparmor support code into something that looks like the new SecurityBackend. It gains a lot of features, most notably, simplicity of the high-level interface,
but also support for old-security and much better test coverage.

Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com

zyga added some commits Mar 24, 2016

interfaces: add naming functions
This patch adds two functions that are going to be used across all
security backends.

``SecurityTag(*snap.AppInfo) string`` returns a tag unique to a specific
application. ``SecurityTagGlob(*snap.Info) string`` returns a glob that
matches all such tags, as long as they belong to the same snap.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: add apparmor security backend
This patch adds the first of four implementations of
``interfaces.SecurityBackend`` - apparmor.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces: remove securityHelper for apparmor
This patch removes the older apparmor support code.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: move test support functions to the end of the file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: use profile rather than aaProfile
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: fix test method names/comments
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: actually check expected test content
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor/apparmor.go
+
+// ProfileName returns the name of apparmor profile for a given application.
+func ProfileName(appInfo *snap.AppInfo) string {
+ return interfaces.SecurityTag(appInfo)
@niemeyer

niemeyer Mar 29, 2016

Contributor

Importing two previously unnecessary packages here just so it can "rename" a function feels like unnecessary boilerplate, in principle.

@zyga

zyga Mar 29, 2016

Contributor

I replaced that with direct call to SecurityTag()

interfaces/apparmor/backend.go
+//
+// This method should be called after changing plug, slots, connections between
+// them or application present in the snap.
+func (b *Backend) Configure(snapInfo *snap.Info, repo *interfaces.Repository, developerMode bool) error {
@niemeyer

niemeyer Mar 29, 2016

Contributor

Nitpick: the developerMode bool should come right after snapInfo, as it's closely associated with it. This will also fix the inconsistency between Configure and CombineSnippets in that regard.

@zyga

zyga Mar 29, 2016

Contributor

Yeah, makes sense, changed.

interfaces/apparmor/backend.go
+}
+
+// SecuritySystem returns the name of the managed security system.
+func (b *Backend) SecuritySystem() interfaces.SecuritySystem {
@niemeyer

niemeyer Mar 29, 2016

Contributor

All these methods feel like unnecessary boilerplate. They're just referring to our own content elsewhere, so why not using the original content instead of giving new names that needs more source code and brain space to keep track of.

@zyga

zyga Mar 29, 2016

Contributor

The reason those methods exist is that I'd like to create a common backend base that then uses them as implementation helper. I don't know if you consider this as worth the effort.

For clarity, the common backend base would then implement Configure() / Deconfigure() once, having access to SecuritySystem(), Directory() and a few others.

@niemeyer

niemeyer Mar 29, 2016

Contributor

We discussed this API last week.

@zyga

zyga Mar 29, 2016

Contributor

We discussed this but this doesn't change that there's something to share among the existing implementations. I you think the mild copy paste there is not something we should fix I can remove those methods.

EDIT: FYI, I'm not arguing on the public high-level interface. This is purely about the private interface that could be shared among all the current backends.

+
+// MockExternalCommands mocks and returns MockCmd for each of the external
+// commands used in this package.
+func MockExternalCommands(c *check.C) map[string]*testutil.MockCmd {
@niemeyer

niemeyer Mar 29, 2016

Contributor

Why do we need this here? Doesn't feel like it's doing anything relevant.

@zyga

zyga Mar 29, 2016

Contributor

So that we can mock apparmor parser away in a consistent way. Upcoming udev backend also uses the same method. I can just mock it directly in tests if you prefer it that way.

@niemeyer

niemeyer Mar 29, 2016

Contributor

Yes, please. It has no reason to be in export_test.go, has much more logic than a trivial call to MockCommand, and is less flexible since as soon as you want more than exit 0 this won't work.

@zyga

zyga Mar 30, 2016

Contributor

Removed in #763

interfaces/apparmor/template.go
// http://bazaar.launchpad.net/~ubuntu-security/ubuntu-core-security/trunk/view/head:/data/apparmor/templates/ubuntu-core/16.04/default
-const defaultAppArmorTemplate = `
+const realDefaultTemplate = `
@niemeyer

niemeyer Mar 29, 2016

Contributor

Why isn't that simply

var defaultTemplate = `
...

?

@zyga

zyga Mar 29, 2016

Contributor

I wanted to keep the real template, that cannot be mocked, in a constant for reference.

@niemeyer

niemeyer Mar 29, 2016

Contributor

This const is not ever ever used besides to assign to defaultTemplate. No benefit.

@zyga

zyga Mar 29, 2016

Contributor

Changed

@@ -44,3 +46,17 @@ func WrapperNameForApp(snapName, appName string) string {
func SecurityTagForApp(snapName, appName string) string {
return fmt.Sprintf("%s.snap", WrapperNameForApp(snapName, appName))
}
+
+// SecurityTag returns application-specific security tag.
@niemeyer

niemeyer Mar 29, 2016

Contributor

Both this and the above function claim to offer an app-specific security tag, and they disagree about how it should look like.

We also need to get rid of WrapperNameForApp. This is not the place this convention should be defined.. (we're handling interfaces here).

@zyga

zyga Mar 29, 2016

Contributor

SecurityTagForApp and everything else that doesn't use snap.Info is deprecated. It gets removed with the last backend.

@niemeyer

niemeyer Mar 29, 2016

Contributor

Please replace the docs for both functions with:

// DEPRECATED: Remove after backends are converted to SecurityBackend.
@zyga

zyga Mar 29, 2016

Contributor

Ack, done.

interfaces/apparmor/backend_test.go
+ "###PROFILEATTACH### (attach_disconnected) {\n" +
+ "}\n")
+ defer restore()
+ for _, scenario := range []struct {
@niemeyer

niemeyer Mar 29, 2016

Contributor

This for loop needs real love so it becomes readable.

The whole content should be out of this function and into the top-level, such complex types should not be defined inline, the slice should be out of here as well, the strings should have their content de-dupped, etc.

Let's please be a bit more caring about how our code looks.

@zyga

zyga Mar 29, 2016

Contributor

I did my best to simplify this but I kept the strings as there are sadly each unique. Have a look if I can make anything else better.

interfaces/apparmor/backend_test.go
+
+func (s *backendSuite) TestCombineSnippets(c *C) {
+ snapInfo, err := snap.InfoFromSnapYaml([]byte(`
+name: SNAP
@niemeyer

niemeyer Mar 29, 2016

Contributor

This string should be defined only once and reused, instead of inlining it everytime. We should also avoid using such strings that break the indentation of the function. It makes reading much harder.

@zyga

zyga Mar 29, 2016

Contributor

Done

interfaces/apparmor/backend_test.go
+
+func (s *backendSuite) TestUpdatingSnapToOneWithMoreApps(c *C) {
+ const before = `
+name: samba
@niemeyer

niemeyer Mar 29, 2016

Contributor

Please define these strings only once and out of the function.

@zyga

zyga Mar 29, 2016

Contributor

I did a pass that removes most of those but actually leaves this pair and a similar (but swapped) pair in TestUpdatingSnapTOOneWithFewerApps since they are unique to those tests. I'll do a second pass that makes those shared as well.

@zyga

zyga Mar 29, 2016

Contributor

Done

interfaces/apparmor/backend.go
+ }
+ // Unload removed profiles
+ for _, baseName := range removed {
+ // XXX: This depends on FileName() and ProfileName() returning the same
@niemeyer

niemeyer Mar 29, 2016

Contributor

What about killing FileName and ProfileName and using a single function everywhere?

@zyga

zyga Mar 29, 2016

Contributor

That's fine too. I was trying to be explicit. If we don't want to ever use different profile name and different file name those can be merged.

@niemeyer

niemeyer Mar 29, 2016

Contributor

"Ever" is a very long time that goes past our lives. There are three functions here: SecurityTag, ProfileName, FileName. Why do we have three functions that do nothing but return the same value that has exactly the same purpose, and that would actually break logic if diverged? (!!!)

@zyga

zyga Mar 29, 2016

Contributor

FileName and ProfileName can^H could change separately. I don't argue that they should, I'm just explaining what the reasoning was behind this.

EDIT: given the coupling between profile name and filename where we keep the profile I'm now convinced. I'll get rid of the extra names.

interfaces/apparmor/backend.go
+ // XXX: This depends on FileName() and ProfileName() returning the same
+ // value. This is true since both of those use SecurityTag().
+ profile := Profile{Name: baseName}
+ err := profile.Unload()
@niemeyer

niemeyer Mar 29, 2016

Contributor

Why is this not UnloadProfile(name), same as LoadProfile?

@zyga

zyga Mar 29, 2016

Contributor

This part needs some cleanup/consideration of how/if we want to scan all loaded apparmor profiles. Earlier it seemed we do want to scan loaded profiles. This gave rise of the Profile struct. Now I'm not so sure. The only point of that struct is to convey profile name and enforcement mode together. If we don't need this information the API can be simplified.

@niemeyer

niemeyer Mar 29, 2016

Contributor

The best is to go the opposite way, simplify first, make it complex if necessary.

@zyga

zyga Mar 29, 2016

Contributor

Agreed.

@zyga

zyga Mar 29, 2016

Contributor

I've simplified the API around this to work with simple strings.

+ s := make([][]byte, 0, len(snippets[appInfo.Name])+2)
+ s = append(s, b.aaHeader(appInfo, developerMode))
+ s = append(s, snippets[appInfo.Name]...)
+ s = append(s, []byte("}\n"))
@niemeyer

niemeyer Mar 29, 2016

Contributor

That feels strange.. Where's the opening one? Why are we opening and closing in separate places?

@zyga

zyga Mar 29, 2016

Contributor

The opening one is in the header. We could split this out but that would mean we'd have to parse the template more (template header is non-trivial). I don't think it's worth the effort given the complexity and the fact that just chopping the trailing } gets us what we want.

@niemeyer

niemeyer Mar 29, 2016

Contributor

Okay.

+ s = append(s, b.aaHeader(appInfo, developerMode))
+ s = append(s, snippets[appInfo.Name]...)
+ s = append(s, []byte("}\n"))
+ fileContent := bytes.Join(s, []byte("\n"))
@niemeyer

niemeyer Mar 29, 2016

Contributor

The logic here is excessively wasteful: allocate a slice of slices to append slices to reallocate a slice to then join the slices. Let's please do it all in one shot: allocate once with the final length, write the final content into it.

@zyga

zyga Mar 29, 2016

Contributor

Hmm, how can I do this in one go? I need to do have []snippet{header, rest..., footer} but this is not valid go syntax.

NOTE: The slice has the right capacity (so there is no re-allocation of s).

@niemeyer

niemeyer Mar 29, 2016

Contributor

It's okay, I take that back. What you are doing is fine and I'm pedantic. Sorry.

Contributor

niemeyer commented Mar 29, 2016

First pass is done.. the change seems a good one, but it's a bit large, and consequently ended up with a largeish review. Sorry about that.

@niemeyer niemeyer added the Reviewed label Mar 29, 2016

Contributor

zyga commented Mar 29, 2016

Thanks for the review. I replied to some of the comments inline. I'll do a pass at the code and ack all individual comments next.

zyga added some commits Mar 29, 2016

interfaces/apparmor: remove ProfileName, use SecurityTag directly
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces: pass developer mode flag closer to snap info
This patch changes SecurityBackend.Configure() to pass developerMode
right after snapInfo.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: share common yaml in tests
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: de-dupe last inline test YAMLs
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces: mark WrapperNameForApp and SecurityTagForApp as deprecated
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: unify API for loading/unloading/listing profiles
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: remove now-obsolete comment
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: remove untrue comment on ObserveChanges
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: tweak comment on Backend
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: remove realDefaultTemplate
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: move long scenario content
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

@zyga zyga removed the Reviewed label Mar 29, 2016

zyga added some commits Mar 29, 2016

interfaces/apparmor: remove SecuritySystem()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: remove FileName() and FileGlob()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: remove Directory()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: make observeChanges() private
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: make combineSnippets private
This patch makes combineSnippets private. To make this happen several
changes to tests had to be made. Most of the test changes are related to
correctly installing/removeing snaps with a interfaces within each test.
Tests for combineSnippets were changed to observe the on-disk state
instead of the snippets in-flight.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: tweak comment
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Mar 29, 2016

This is ready for another review

interfaces/apparmor/backend.go
+ if err != nil {
+ return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapInfo.Name, err)
+ }
+ err = b.observeChanges(changed, removed)
@pedronis

pedronis Mar 29, 2016

Contributor

toggleProfiles now that is private?

@zyga

zyga Mar 29, 2016

Contributor

Why toggle? It's not like this is always on-off back-forth kind of toggle.

@pedronis

pedronis Mar 29, 2016

Contributor

@zyga that was strawman, but observeChanges is really not ideal as a name, also why not have two functions one for the unload part and one for the load/reload

@zyga

zyga Mar 29, 2016

Contributor

Yeah, I could do that. Good idea

interfaces/apparmor: split observeChanges into two functions
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor/backend_test.go
+@{APP_VERSION}="1"
+@{INSTALL_DIR}="{/snaps,/gadget}"
+profile "snap.samba.smbd" (attach_disconnected,complain) {
+snippet
@niemeyer

niemeyer Mar 29, 2016

Contributor

Again, can we please kill the duplication in these snippets? The actual relevant difference in them is 5 lines, total! We don't need all 34 here. For instance:

content: commonPrefix + `
...
@zyga

zyga Mar 30, 2016

Contributor

Ah, sorry I didn't think of this. Done

+ "###PROFILEATTACH### (attach_disconnected) {\n" +
+ "}\n")
+ defer restore()
+ for _, scenario := range combineSnippetsScenarios {
@niemeyer

niemeyer Mar 29, 2016

Contributor

Thanks, much nicer.

+// In addition, the set of variables listed here interacts with old-security
+// interface since there the base template is provided by a particular 3rd
+// party snap, not by snappy.
+func legacyVariables(appInfo *snap.AppInfo) string {
@niemeyer

niemeyer Mar 29, 2016

Contributor

These two functions should use bytes.Buffer values:

var buf bytes.Buffer
fmt.Fprintf(&buf, ...)
fmt.Fprintf(&buf, ...)
return buf.String()

(or return buf.Bytes(), depending on how that's used)

@zyga

zyga Mar 30, 2016

Contributor

Done

+ text = strings.TrimRight(defaultTemplate, "\n}")
+ // TODO: switch to modernVariables() after the default template is
+ // compatible with them.
+ text = strings.Replace(text, "###VAR###\n", legacyVariables(appInfo), 1)
@niemeyer

niemeyer Mar 29, 2016

Contributor

Rather than building it just to call replace, can't we simply pass the arguments in as usual?

Same below.

+ }
+ text = strings.Replace(text, "###PROFILEATTACH###",
+ fmt.Sprintf("profile \"%s\"", interfaces.SecurityTag(appInfo)), 1)
+ return []byte(text)
@niemeyer

niemeyer Mar 29, 2016

Contributor

Why are we working with strings above if the end goal is a []byte? Much easier to work with a bytes.Buffer all along and return the final bytes array with buf.Bytes(). You can even pass the bytes.Buffer into legacyVariables/etc for easily cooking the end result at once, instead of manipulating immutable strings everywhere.

@zyga

zyga Mar 30, 2016

Contributor

Good point, I changed everything to use a buffer.

zyga added some commits Mar 30, 2016

interfaces/apparmor: abbreviate test scenarios
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: use bytes.Buffer in legacyVariables()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: simplify some formatting
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/apparmor: use bytes.Buffer in modernVariables()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

@niemeyer niemeyer merged commit 9dd1702 into snapcore:master Mar 30, 2016

3 of 4 checks passed

Integration tests 66 tests run, 0 skipped, 1 failed.
Details
autopkgtest Success No test results found.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage decreased (-0.5%) to 76.436%
Details
+//
+// Snappy creates apparmor profiles for each application (for each snap)
+// present in the system. Upon each execution of ubuntu-core-launcher, the
+// profile is attached to the running process. Prior to that the profile must
@jdstrand

jdstrand Mar 30, 2016

Contributor

Minor nitpick-- the profile isn't attached to the process so much as the process is launched under the profile.

@zyga

zyga Mar 30, 2016

Contributor

Reworded in 1be14a9

+// "apparmor_parser".
+//
+// Each apparmor profile contains a simple <header><content><footer> structure.
+// The header specified an identifier that is relevant to the kernel. The
@jdstrand

jdstrand Mar 30, 2016

Contributor

Please use "The header specifies the profile name that the launcher will use to launch a process under this profile."

@zyga

zyga Mar 30, 2016

Contributor

Reworded in 7752275

+// Each apparmor profile contains a simple <header><content><footer> structure.
+// The header specified an identifier that is relevant to the kernel. The
+// identifier can be either the full path of the executable or an abstract
+// identifier not related to the executable name.
@jdstrand

jdstrand Mar 30, 2016

Contributor

I'm not sure why you are discussing binary attachment here, but since you are, you should say that snappy only utilizes the "abstract identifier".

@zyga

zyga Mar 30, 2016

Contributor

Removed in earlier patches. I'm inclined to add the note about abstract identifier so that the next person that comes along to look at this won't have to do that much digging.

@zyga

zyga Mar 30, 2016

Contributor

Edited in ec37dd4

+// identifier not related to the executable name.
+//
+// The actual profiles are stored in /var/lib/snappy/apparmor/profiles.
+// This directory is also hard-coded in ubuntu-core-launcher.
@jdstrand

jdstrand Mar 30, 2016

Contributor

The launcher doesn't care about /var/lib/snappy/apparmor/profiles because it doesn't touch the profile files-- it references the profile name of a profile that is already loaded into the kernel. ubuntu-core-launcher does care about the seccomp directory, /var/lib/snappy/seccomp/profiles, which is perhaps what you were thinking?

@zyga

zyga Mar 30, 2016

Contributor

That's right, the path is only relevant to the systemd unit that loads those on boot. Corrected in 434301b

+// This directory is also hard-coded in ubuntu-core-launcher.
+//
+// NOTE: A systemd job (TODO: specify which) loads all snappy-specific apparmor
+// profiles into the kernel during the boot process.
@jdstrand

jdstrand Mar 30, 2016

Contributor

This is 'apparmor.service'

@zyga

zyga Mar 30, 2016

Contributor

Spliced in 3992639 -- thanks

+// non-fatal to the offending application process.
+//
+// This method should be called after changing plug, slots, connections between
+// them or application present in the snap.
@jdstrand

jdstrand Mar 30, 2016

Contributor

Also on install, right?

@zyga

zyga Mar 30, 2016

Contributor

Yes though I didn't really mention that. This part is coming up next (~tomorrow-ish)

+ // file called "snap.sambda.smbd" was removed
+ _, err := os.Stat(profile)
+ c.Check(os.IsNotExist(err), Equals, true)
+ // apparmor_parser was was used to unload the profile
@jdstrand

jdstrand Mar 30, 2016

Contributor

'was was'

@zyga

zyga Mar 30, 2016

Contributor

Fixed in 4a5e1e5

+ // and empty lines are avoided as those can be discarded in the future.
+ "#include <tunables/global>\n",
+ "/tmp/ r,\n",
+ "/sys/class/ r,\n",
@jdstrand

jdstrand Mar 30, 2016

Contributor

/sys/class/ is perhaps brittle. I'm hoping this will go away with interfaces. The tunables/global and /tmp/ should be fine, but note if we change the spacing on '/tmp/ r,\n', it will fail the test (not a blocker, just pointing out it is brittle). A test for the ###PROFILEATTACH### replacement would be good though.

@jdstrand

jdstrand Mar 30, 2016

Contributor

I see that the ###PROFILEATTACH### replacement tests are down below.

@zyga

zyga Mar 30, 2016

Contributor

I'll keep this as-is as I hope we'll keep this up-to-date when working on the actual template text.

+ c.Assert(err, IsNil)
+ // Our custom template was used
+ c.Assert(string(data), testutil.Contains, "FOO")
+ // Custom profile can rely on legacy variables
@jdstrand

jdstrand Mar 30, 2016

Contributor

Why are this referred to as "legacy variables"? These are apparmor profile variables that are still in use in our policy.

@zyga

zyga Mar 30, 2016

Contributor

Because they originate from 15.04 and we'll probably simplify things for 16.04 so that we use just the concepts of snap name, app name and security tag. This is still open for discussion, I just included it here. As a second reason "legacy variables" are always used for old-security since it has to be compatible with earlier releases.

+)
+
+// legacyVariablees returns text defining some apparmor variables that work
+// with legacy apparmor templates.
@jdstrand

jdstrand Mar 30, 2016

Contributor

Why "legacy" here? These variables are in use by interfaces/apparmor/template.go and we should continue to use them to keep the implementation clean and make maintenance easier.

@zyga

zyga Mar 30, 2016

Contributor

Replied above.

+//
+// In addition, the set of variables listed here interacts with old-security
+// interface since there the base template is provided by a particular 3rd
+// party snap, not by snappy.
@jdstrand

jdstrand Mar 30, 2016

Contributor

I'm not sure why you are referring to old-security base templates here. AppArmor variables are "a good thing" regardless of using the old old-security system or the new interfaces system.

@zyga

zyga Mar 30, 2016

Contributor

I was referring to old-security because those variables need to be maintained for old-security to work. Without old-security any set of variables can be used (AFAIK, perhaps I'm wrong) as long as they are changed in sync with template.go.

@jdstrand

jdstrand Mar 30, 2016

Contributor

"I was referring to old-security because those variables need to be maintained for old-security to work. Without old-security any set of variables can be used (AFAIK, perhaps I'm wrong) as long as they are changed in sync with template.go."

I see, ok that context helps a lot. With old-security there needs to be coordination between ubuntu-core-security and snappy, without old-security, everything is contained within snappy (and as you said, coordinated with template.go).

+ fmt.Fprintf(&buf, "@{APP_ID_DBUS}=\"%s\"\n",
+ dbus.SafePath(fmt.Sprintf("%s.%s_%s_%s",
+ appInfo.Snap.Name, appInfo.Snap.Developer, appInfo.Name, appInfo.Snap.Version)))
+ // XXX: How is this different from APP_ID_DBUS?
@jdstrand

jdstrand Mar 30, 2016

Contributor

APP_ID was previously defined as '<snap><appname><version>'. So the apparmor variables were:
APP_PKGNAME=<snap>
APP_APPNAME=<appname>
APP_VERSION=<version>

In this manner, APP_ID_DBUS was '<snap><appname><version>' translated to a dbus string, and APP_PKGNAME_DBUS was '<snap>' translated to a dbus string.

@zyga

zyga Mar 30, 2016

Contributor

Thanks for explaining this

+// @{APP_NAME}=app.Name
+// @{APP_SECURITY_TAG}=app.SecurityTag()
+// @{SNAP_NAME}=app.SnapName
+//
@jdstrand

jdstrand Mar 30, 2016

Contributor

This seems simple but needs to be thought out and what variables are culled or added directly affects security policy and interactions. For example, APP_VERSION is removed in your straw man, but we previously said that apps should only have read access to other versions' data directories-- do we add APP_REVISION or revisit the decision on versioned data dirs? APP_*_DBUS is gone and would need to be replaced with something in the interface for dbus.

Let's leave all that for a future commit and proper discussion.

@zyga

zyga Mar 30, 2016

Contributor

Agreed.

+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "@{APP_NAME}=\"%s\"\n", appInfo.Name)
+ fmt.Fprintf(&buf, "@{APP_SECURITY_TAG}=\"%s\"\n", interfaces.SecurityTag(appInfo))
+ fmt.Fprintf(&buf, "@{SNAP_NAME}=\"%s\"\n", appInfo.Snap.Name)
@jdstrand

jdstrand Mar 30, 2016

Contributor

Introducing these now confuses policy since nothing in policy references these variables. I don't even know why we are exposes APP_SECURITY_TAG-- what is that? I suspect it is the profile name, but that is unneeded since apparmor already has a special @{profile_name} variable that the parser automatically creates.

I would prefer all but INSTALL_DIR be removed until this is properly choreographed with template.go and all the builtin/ policy.

@zyga

zyga Mar 30, 2016

Contributor

I feel I should have left that part out to separate the discussion of what to have for 16.04 and what we have in the code today. Your remarks are valid.

Contributor

jdstrand commented Mar 30, 2016

In general I only suggested comment changes or clarified language. The one thing I'd like to see removed are all the modern apparmor variables in template_vars.go except INSTALL_DIR. We should instead coordinate changes to template_vars.go with template.go and builtin/* in the same commit.

Before we add modern variables and update the policy, I'm strongly in favor of focusing on getting the existing policy all working, applied and converting 15.04 frameworks to 16.04 interfaces first.

Contributor

zyga commented Mar 30, 2016

I've proposed all the comment changes in #765

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