skills/types: add bool-file #462

Merged
merged 19 commits into from Feb 11, 2016

Conversation

Projects
None yet
5 participants
Contributor

zyga commented Feb 8, 2016

This patch adds the "bool-file" skill type. Boolean files can be used to
represent LEDs and GPIOs as files that react to writes of "0" or "1".

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

zyga added some commits Feb 8, 2016

skills/types: add bool-type
This patch adds the "bool-file" skill type. Boolean files can be used to
represent LEDs and GPIOs as files that react to writes of "0" or "1".

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Add the missing common.go file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types/bool_file.go
+// BoolFileType is the type of all the bool-file skills.
+type BoolFileType struct{}
+
+// String() returns the same value as Name().
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

The name of the method here includes () which the others do not

skills/types/bool_file.go
+ return t.Name()
+}
+
+// Name returns the name of the bool-file type (always "bool-file").
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

No need for always "boo-file" ?

skills/types/bool_file.go
+ // To provide GPIOs we need extra permissions to export/unexport and to
+ // set the direction of each pin.
+ if t.isGPIO(skill) {
+ snippet := []byte(`
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

Maybe have this []byte defined at the top of the function instead of inside the switch statement?

skills/types/bool_file.go
+ return nil, nil
+ case skills.SecuritySeccomp:
+ return nil, nil
+ case skills.SecurityDBus:
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

Could perhaps have:

case skills.SecuritySeccomp, skills.SecurityDBus:
    return nil, nil
skills/types/bool_file_test.go
+}
+
+// BoolFileType
+
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

Empty line

skills/types/bool_file_test.go
+ `skill slot is not of type "bool-file"`)
+}
+
+func (s *BoolFileTypeSuite) TestSlotSecuritySnippet(c *C) {
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

There's a lot happening in this test, maybe break it into 2: 1 testing error conditions and 1 testing the happy path?

skills/types/common.go
+var evalSymlinks = filepath.EvalSymlinks
+
+// MockEvalSymlinks replaces the path/filepath.EvalSymlinks function used inside the caps package.
+func MockEvalSymlinks(test *testutil.BaseTest, fn func(string) (string, error)) {
@stevenwilkin

stevenwilkin Feb 8, 2016

Member

This test helper will end up in the build, can it go inside a *_test.go file?

Member

elopio commented Feb 8, 2016

retest this please

I worry that these paths are hardcoded instead of declarative via a file that the snappy command would parse. Rules need to change for various reasons and hardcoding them this way means that maintenance of policy is considerably more difficult. Furthermore, having rules hard-coded in the snappy codebase makes it extremely difficult to audit the policy. Much better IMO would be to treat these skill types that need security policy like the old school caps-- each type gets a corresponding security policy file that can be maintained separately from the snappy source.

Is /sys/class/gpio/import valid? I had not seen this. I had seen /sys/class/gpio/unexport.

I suspect that these rules are too lenient. The skill is called 'bool-file' but these rules will allow changing the 'direction' on all gpio pins (files) rather than the file that is specified. I thought the way this was supposed to work was that these would be per pin as opposed to all pins. I also suspect that these won't be enough permissions and other accesses in /sys/class/gpio or elsewhere will be needed. Eg, I think I've seen others needing things like /sys/devices/gpio1/..., but I'm not a gpio expert.

Owner

zyga replied Feb 9, 2016

We've selected hardcoding to explore how capabilities/skills will work out in practice. We can consider moving to external files later but for now this is the agreed direction.

I've corrected import (it should be unexport), thanks for spotting that!

The "bool-file" skill has two sides. The provider of the skill can indeed change the direction of each GPIO (so that it can set it to out). Note that the consumer (user) of the skill (the skill slot) only gets write permission to the value of the particular pin it was granted so it cannot mess up other GPIOs. In this design the provider is like a GPIO manager so it has broader access (it can expose any GPIO). Consumers are more limited.

As for needing more permissions, let's try and see. It is always easier to add more :)

Re hardcoding> I guess if that is the decision, that is 'ok' for now, but I strongly feel this is going to be a maintenance burden and something we'll want to address before 16.04 is released. I also worry if we continue hardcoding we will be entrenched.

Thank you for explaining the two sides for the skill-- I forgot this point in reviewing the merge since it didn't jump out at me that this would happen. Since this is the case and since this is implied but not completely clear unless reviewing more of the code, can you add a test case for the consumer side to make sure it has the specific pin in security policy instead of the glob? That way we can futureproof ourselves against side-effects on this security-sensitive code.

Re more permissions: sure :)

This only allows write. I suspect 'r' is also desired and perhaps 'k' (locking). I'm not sure why 'l' (hard linking) is needed, but it is probably ok.

Owner

zyga replied Feb 9, 2016

Ah, I didn't know that l is hard-linking. I indeed wanted locking.

As for reading, yeah, I'll add that back. For a moment I was treating bool files as "sinks" but I don't think we need to get there yet.

This allows '..' (though not '../').

Owner

zyga replied Feb 9, 2016

Thanks for spotting this, would [^/.]+ be okay? (then again it excludes `name.with.dot``)

[^/.]+ is not quite right I don't think unless we can be 100% sure that '.' is not a valid character for these. You could add a second check to see if '../' is present if that would be easier.

zyga added some commits Feb 9, 2016

skills/types: tweak comment
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: tweak comment
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: move variable to top of a function
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: shorten switch cases
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: remove useless comment
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: chop tests into smaller chunks
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: don't put test code into non-test builds
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: correct /sys/class/gpio/import to unexport
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: disallow hard-linking of files related to bool-file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: allow bool-file consumers to read the file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: allow bool-file consumers to lock the file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Feb 9, 2016

I've addressed every single comment made. Please have a 2nd look.

NOTE: please don't merge this unless @jdstrand gives it a +1.

+ "^/sys/class/gpio/gpio[0-9]+/value$")
+var boolFileAllowedPathPatterns = []*regexp.Regexp{
+ // The brightness of standard LED class device
+ regexp.MustCompile("^/sys/class/leds/[^/]+/brightness$"),
@jdstrand

jdstrand Feb 9, 2016

Contributor

Please add a check for '../' in the path

@zyga

zyga Feb 9, 2016

Contributor

Done

+ gpioSnippet := []byte(`
+/sys/class/gpio/export rw,
+/sys/class/gpio/unexport rw,
+/sys/class/gpio/gpio[0-9]+/direction rw,
@jdstrand

jdstrand Feb 9, 2016

Contributor

Ok, but I reiterate my concerns regarding maintainability, auditability and getting entrenched with hard-coding.

+ if err != nil {
+ return nil, fmt.Errorf("cannot compute skill slot security snippet: %v", err)
+ }
+ return []byte(fmt.Sprintf("%s rwk,\n", path)), nil
@jdstrand

jdstrand Feb 9, 2016

Contributor

Looks fine.

skills/types/bool_file_test.go
+ }, PanicMatches, "skill is not sanitized")
+}
+
+func (s *BoolFileTypeSuite) TestSkillSecuritySnippetUnusedSecurtySystems(c *C) {
@jdstrand

jdstrand Feb 9, 2016

Contributor

Typo: 'Securty'

@zyga

zyga Feb 9, 2016

Contributor

Fixed, thanks :)

+ snippet, err = s.t.SlotSecuritySnippet(s.ledSkill, skills.SecurityApparmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, DeepEquals, []byte(
+ "(dereferenced)/sys/class/leds/input27::capslock/brightness rwk,\n"))
@jdstrand

jdstrand Feb 9, 2016

Contributor

Can we add an additional check here to make sure that SkillSecuritySnippet doesn't end up in SlotSecuritySnippet's output to make sure we futureproof ourselves from accidentally giving too many permissions to the slot?

@zyga

zyga Feb 9, 2016

Contributor

Done, can you check if that is what you had on your mind? Look at TestSlotSecurityDoesNotContainSkillSecurity

@jdstrand

jdstrand Feb 10, 2016

Contributor

TestSlotSecurityDoesNotContainSkillSecurity looks good.

zyga added some commits Feb 9, 2016

skills/types: ensure that bool-file path is not using ..
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: fix typo Securty
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: add extra sanity checks for bool-file
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Feb 9, 2016

Please have another look.

skills/types/bool_file.go
+ }
+ if strings.Contains(path, "..") {
+ return fmt.Errorf("bool-file path cannot contain %q", "..")
+ }
@jdstrand

jdstrand Feb 10, 2016

Contributor

Looks good.

@chipaca

chipaca Feb 11, 2016

Member

why aren't we passing path through filepath.Clean?

@zyga

zyga Feb 11, 2016

Contributor

Because I'm a noob. Fixed now.

+ skillSnippet, err = s.t.SkillSecuritySnippet(s.gpioSkill, skills.SecurityApparmor)
+ c.Assert(err, IsNil)
+ // Ensure that we don't accidentally give skill-side permissions to slot-side.
+ c.Assert(bytes.Contains(slotSnippet, skillSnippet), Equals, false)
@jdstrand

jdstrand Feb 10, 2016

Contributor

Based on https://golang.org/pkg/bytes/#Contains, this looks great. Thanks!

Contributor

jdstrand commented Feb 10, 2016

Just so it doesn't get lost in comments, I'd like to reiterate my concerns regarding maintainability, auditability and getting entrenched with hard-coding the rules, but understand that is what was decided for the initial direction.

+1

+}
+
+func (t *BoolFileType) dereferencedPath(skill *skills.Skill) (string, error) {
+ if path, ok := skill.Attrs["path"].(string); ok {
@chipaca

chipaca Feb 11, 2016

Member

As far as I can tell here skill.Attrs["path"] can come from "outside" (as skill is passed in unchanged from an exported function), so you need filepath.Clean here again, don't you?

@zyga

zyga Feb 11, 2016

Contributor

Fixed

Edit: though in practice those are sysfs symlinks but fixed anyway.

+}
+
+// isGPIO checks if a given bool-file skill refers to a GPIO pin.
+func (t *BoolFileType) isGPIO(skill *skills.Skill) bool {
@chipaca

chipaca Feb 11, 2016

Member

and here

@zyga

zyga Feb 11, 2016

Contributor

Fixed, thanks :)

zyga added some commits Feb 11, 2016

skills/types: use filepath.Clean()
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
skills/types: use filepath.Clean() (more)
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

@zyga zyga changed the title from skills/types: add bool-type to skills/types: add bool-file Feb 11, 2016

zyga added a commit that referenced this pull request Feb 11, 2016

@zyga zyga merged commit 6c4bb71 into snapcore:master Feb 11, 2016

3 checks passed

Integration tests Success 60 tests run, 0 skipped, 0 failed.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls Coverage increased (+0.7%) to 69.992%
Details

@zyga zyga deleted the zyga:bool-file-skill branch Mar 8, 2016

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