Skip to content

mount-control: step 2#10739

Merged
mvo5 merged 3 commits intocanonical:masterfrom
mardy:mount-control-2
Dec 8, 2021
Merged

mount-control: step 2#10739
mvo5 merged 3 commits intocanonical:masterfrom
mardy:mount-control-2

Conversation

@mardy
Copy link
Copy Markdown
Contributor

@mardy mardy commented Sep 6, 2021

This is the second part of the mount-control saga: this adds the interface itself and a spread test.

The full (draft) MR is here, whereas the first part (which this branch depends on) is #10653.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Sep 6, 2021

Codecov Report

Merging #10739 (6f8fc34) into master (9ade0e2) will increase coverage by 0.11%.
The diff coverage is 98.79%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #10739      +/-   ##
==========================================
+ Coverage   78.21%   78.32%   +0.11%     
==========================================
  Files         916      919       +3     
  Lines      103800   104430     +630     
==========================================
+ Hits        81187    81800     +613     
- Misses      17520    17533      +13     
- Partials     5093     5097       +4     
Flag Coverage Δ
unittests 78.32% <98.79%> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
interfaces/builtin/mount_control.go 98.13% <98.13%> (ø)
interfaces/utils/path_patterns.go 100.00% <100.00%> (ø)
osutil/synctree.go 76.41% <0.00%> (-2.84%) ⬇️
daemon/api_model.go 75.83% <0.00%> (-0.84%) ⬇️
daemon/api_connections.go 93.04% <0.00%> (-0.54%) ⬇️
overlord/snapstate/snapstate.go 83.00% <0.00%> (-0.24%) ⬇️
overlord/devicestate/devicemgr.go 78.14% <0.00%> (-0.07%) ⬇️
gadget/gadget.go 89.86% <0.00%> (ø)
asserts/database.go 81.17% <0.00%> (ø)
interfaces/udev/spec.go 91.07% <0.00%> (ø)
... and 26 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9ade0e2...6f8fc34. Read the comment docs.

@mardy mardy force-pushed the mount-control-2 branch 2 times, most recently from 50fa4b6 to cdb82f3 Compare September 14, 2021 08:13
@mvo5 mvo5 added the Needs security review Can only be merged once security gave a :+1: label Sep 14, 2021
@pedronis pedronis added the Needs Samuele review Needs a review from Samuele before it can land label Sep 14, 2021
@mardy mardy marked this pull request as ready for review September 14, 2021 12:04
@pedronis pedronis self-requested a review September 14, 2021 13:05
Copy link
Copy Markdown
Contributor

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did a first pass, some comments

Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
Comment thread interfaces/utils/path_patterns.go Outdated
Comment thread interfaces/utils/path_patterns.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
@anonymouse64 anonymouse64 self-requested a review September 17, 2021 17:26
@mardy mardy force-pushed the mount-control-2 branch 2 times, most recently from 4a45cdd to 802c540 Compare September 21, 2021 06:09
Comment thread interfaces/utils/path_patterns.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to get @jrjohansen to give this function a once-over.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how faithful does the conversion from aa globbing to re need to be? The conversion does not appear to be correct in some cases

Copy link
Copy Markdown
Contributor

@alexmurray alexmurray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few places that worry me so I would like to see some more validation of various things like the filesystem types and some more tests added to try and make sure we can avoid snaps trying to abuse this interface.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add type validation (this could be similar to option validation where items are checked against an allow-list) so that we can ensure the generated apparmor profile cannot have malicious content inserted into it, ie if a type was specified as: auto) options=() path/to/malicious/content /var/lib/snapd/hostfs/...,\n mount fstype=( - then I think currently this could allow a snap to mount over parts of the root file-system or some other trusted location, or they could inject other apparmor policy bits as well to gain additional accesses.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a simple regular expression for alphanumeric characters, instead of a full list of possible options. This should address the security issue you raised, while remaining open to support any FS type. Please let me know, if you see a reason for an explicit list.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/utils/path_patterns_test.go Outdated
Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
@mardy mardy force-pushed the mount-control-2 branch 4 times, most recently from f062c0d to 33dd45b Compare September 27, 2021 11:55
Copy link
Copy Markdown
Contributor

@alexmurray alexmurray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/utils/path_patterns_test.go Outdated
Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
@alexmurray alexmurray removed the Needs security review Can only be merged once security gave a :+1: label Sep 30, 2021
@pedronis pedronis self-requested a review September 30, 2021 08:16
@mardy mardy mentioned this pull request Sep 30, 2021
Copy link
Copy Markdown
Contributor

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

the slot-side base declaration needs some changes.

some happy paths are not hit by unit tests

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
@pedronis pedronis self-requested a review October 5, 2021 09:02
Copy link
Copy Markdown
Contributor

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked at the unit tests, but I have some thoughts :-)

let me know if you have any questions about my proposals, but the main problem I see right now is that we allow any filesystem type when we should be at least denying some specific filesystems that could be easily abused with this interface otherwise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this unit test

Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
Comment thread tests/lib/snaps/test-snapd-mount-control/meta/snap.yaml Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit torn on this function, on the one hand, this interface is super-privileged so nothing will be uploadable to the store to be released without approval, but on the other hand, we've seen many instances of using system-files where a user declares something super wildly permissive and finds that it "just works" locally during development and goes to upload only to find that we actually don't encourage/allow/condone/permit that sort of usage of system-files, and many days I find myself wishing that whomever used system-files this way would have been warned during development that what they are doing is not encouraged or in many ways supported.

So on the one hand, I'm looking ahead and thinking of how people could abuse this when all they need to have to make this work locally is to have an absolute path that is clean, but on the other hand there may be legitimate use cases for mounting /sys/fs/kernel/give/me/all/your/secrets to /snap/foo/current/not-your-secrets.txt and we don't want to have to push out an update to snapd to allow this at the last minute like we have had to for other interfaces.

Also, I think system-files is uniquely more likely to be abused since it is about the single most frustrating aspect of apparmor confinement for snaps - arbitrary file access, whereas this interface is about arbitrary mount access which is not nearly as common of a requirement as arbitrary file access.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned below, this is not enough, we should be disallowing certain kinds of filesystems from being mounted

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I've added one more check

Comment thread interfaces/utils/path_patterns.go Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless I am reading this wrong, character class within an alrenation is not handled correctly. eg {[,],} -> ([|]|) when it should be ([,]|)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works correctly, it actually produces ^([,]|)$; I've added a unit test for this now.

Comment thread interfaces/utils/path_patterns.go Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't looks wrong for the convertion when in a char class as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't understand what you mean here. Maybe the most practical approach is if you tell me some example patterns to test, and we see what this code produces for them?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so I have been through this 3 separate times now trying to see what I thought I was seeing before, and I don't see it. I think this is good

Comment thread interfaces/utils/path_patterns.go Outdated
Comment thread interfaces/utils/path_patterns.go Outdated
@mardy mardy force-pushed the mount-control-2 branch 4 times, most recently from 84921ed to f59ae19 Compare October 11, 2021 14:19
@alexmurray
Copy link
Copy Markdown
Contributor

Hmm I wonder about fuse since this is done in userspace and hence a snap itself would have to provide this implementation so could this then be used to cause issues in the kernel or to other users of that file-system if it were malicious? Perhaps until we have a good use-case for snaps wanting to use mount-control with fuse we should remove that? Otherwise LGTM!

@mardy
Copy link
Copy Markdown
Contributor Author

mardy commented Oct 22, 2021

Hmm I wonder about fuse since this is done in userspace and hence a snap itself would have to provide this implementation so could this then be used to cause issues in the kernel or to other users of that file-system if it were malicious? Perhaps until we have a good use-case for snaps wanting to use mount-control with fuse we should remove that? Otherwise LGTM!

Makes sense. Removed!

@anonymouse64 anonymouse64 self-requested a review October 25, 2021 12:18
Copy link
Copy Markdown
Contributor

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this needs more work around validating what/where and perhaps needs a fundamental rethinking about what sort of strings we want to accept in what/where.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment on lines 269 to 312
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we have an allow list, it is sort of unnecessary to have the regexp too, but I think it's fine to leave in

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control_test.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
@anonymouse64 anonymouse64 self-requested a review November 16, 2021 00:19
@pedronis pedronis self-requested a review November 23, 2021 09:52
Copy link
Copy Markdown
Contributor

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did another pass, some questions

Comment thread interfaces/utils/path_patterns.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why /media ? I think in principle we want to allow / and control what is perimtted in terms of absolute targets in the snap-declaration?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we also prevent $ from appearing multiple times?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pedronis I assume by "allow / and ..." you mean to allow arbitrary absolute paths and not to allow mounting something at "/" exactly which would be very weird and break many things?

Assuming you meant absolute paths, maybe where should be something like:

	whereRegexp = regexp.MustCompile(`^(/[^\$"@]+|\$SNAP_DATA|\$SNAP_COMMON)[^\$"@]*$`)

which will disallow "/" or any other string starting with an env var (except $SNAP_DATA or $SNAP_COMMON), but otherwise allow anything underneath $SNAP_DATA or $SNAP_COMMON, as well as disallowing any other env vars in the string, any @ or any ". It also disallows $SNAP_DATA/$SNAP_DATA

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I meant any absolute path (at this level)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dollar sign is not dangerous (AppArmor wouldn't treat it specially), but it sounds so suspicious that I think it's fine to disallow it.

I would suggest using a slightly simpler regexp:

whereRegexp = regexp.MustCompile(`^(\$SNAP_COMMON|\$SNAP_DATA)?/[^\$"@]+$`)

The only practical difference from Ian's is that this disallows having just $SNAP_COMMON or $SNAP_DATA as the target, but requires $SNAP_DATA/something, which looks a reasonable restriction to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see a use case behind where: $SNAP_DATA where a snap wants it's entire data dir to be located on some other partition than the main writable partition on it, but I suppose we could enable that use case when folks ask for it.

@pedronis what do you think of @mardy's proposal?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with the simplified proposal.

Copy link
Copy Markdown
Contributor

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall looking really close, I have a few testing suggestions and some questions about the parsing code, also see the suggestion from @pedronis too

Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Errorf(`mount-control "what" attribute is invalid: must start with / and not contain special characters`)
return fmt.Errorf(`mount-control "what" attribute is invalid: must start with /, $SNAP_DATA, or $SNAP_COMMON and not contain special characters`)

though the message is getting rather long now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll accept the suggestion and remove the "is invalid:" bit to save some characters

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but I don't see the suggestion accepted? the original error message I commented on is still in the diff (unless this is another github UI bug?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it's because I changed it in a different way: I think you accidentally commented on this one, thinking that it was about the "where" attribute. But this error is on the "what" attribute, for which we don't have the $SNAP_DATA or $SNAP_COMMON restriction.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/utils/path_patterns_test.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whatever the result of the ^ and $ question I asked above is, we should have those covered in tests here either in the happy paths or in the unhappy paths

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it not work to define this in the environment section?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does :-) Updated.

Comment thread tests/main/interfaces-mount-control/task.yaml Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also just have a check which exits the test if os.query is-opensuse-tumbleweed is true before doing these checks, it would make the nested if's here a bit more readable/less indented

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed; updated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also have negative cases for the options not matching and for the filesystem not matching?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added!

@anonymouse64 anonymouse64 self-requested a review November 29, 2021 15:08
Copy link
Copy Markdown
Contributor

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for all the changes, I left a few suggestions, but we can take those in followups since this PR is essentially ready to go I think, let's land it :-)

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but I don't see the suggestion accepted? the original error message I commented on is still in the diff (unless this is another github UI bug?)

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this error message shouldn't mention /media anymore

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops! Fixed.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment thread interfaces/builtin/mount_control.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there isn't a usage of counting the number of mount entries in follow up PR's, I have a slight preference for this to be a boolean instead as it's ever so slightly more readable to do:

	hasMountEntries := false
	err := enumerateMounts(plug, func(mountInfo *MountInfo) error {
		hasMountEntries = true
		return validateMountInfo(mountInfo)
	})
	if err != nil {
		return err
	}

	if !hasMountEntries {
		return mountAttrTypeError
	}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC it won't be used. Updated.

Comment thread interfaces/builtin/mount_control.go Outdated
Comment on lines 414 to 415
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is unexpected to happen, can you make this an internal error?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what an "internal error" is; I just added "internal error:" at the beginning of the message :-)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's exactly what I meant, just add "internal error" to the start of the error message 😄

Comment thread interfaces/builtin/mount_control_test.go Outdated
Copy link
Copy Markdown
Contributor

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last commit 6f8fc3458bdcc15b37e3e74e88b0716cbd14ea77 looks good to me, but there is now a conflict

@mardy
Copy link
Copy Markdown
Contributor Author

mardy commented Dec 8, 2021

last commit 6f8fc34 looks good to me, but there is now a conflict

It's because of the merge of the kernel-module-load interface. I've now rebased the branch and squashed most commits, let's see how it goes :-)

@mvo5 mvo5 merged commit eec64b4 into canonical:master Dec 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Samuele review Needs a review from Samuele before it can land

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants