interfaces/mount: add support for parsing x-snapd.{mode,uid,gid}= #3965

Merged
merged 22 commits into from Oct 25, 2017

Conversation

Projects
None yet
5 participants
Contributor

zyga commented Sep 26, 2017

This branch adds support for parsing three additional fstab options that are
specific to snapd's layout feature. The three options in combination shall
allow snap-update-ns to create the correct mount point on demand.

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

zyga added some commits Sep 26, 2017

interfaces/mount: reserve x-snapd- prefix for internal options
This patch adds a new reserved prefix for fstab-like mount entries. Like
systemd and udisks before it, the x-snapd- prefix can be used to convey
useful data that is not intended to be consumed by the kernel.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount: parse x-snapd-mode= mount option
This patch add support function for parsing x-snapd-mode= mount option
out of the fstab-like mount profiles. It is there to support a feature
of snapd mount layouts where snapd can create mount directory
automatically. The directory needs to have a specific mode and
ownership. This patch caters for the mode aspect.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount: parse x-snapd-user= mount option
This patch add support function for parsing x-snapd-user= mount option
out of the fstab-like mount profiles. It is there to support a feature
of snapd mount layouts where snapd can create mount directory
automatically. This patch caters for the user owner aspect.

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

@zyga zyga requested a review from mvo5 Sep 26, 2017

interfaces/mount: parse x-snapd-group= mount option
This patch add support function for parsing x-snapd-group= mount option
out of the fstab-like mount profiles. It is there to support a feature
of snapd mount layouts where snapd can create mount directory
automatically. This patch caters for the group owner aspect.

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

zyga commented Sep 26, 2017

Drat, I used golang 1.8-only library. Let me improve that.

Contributor

zyga commented Sep 28, 2017

This will be improved once #3966 lands

zyga added some commits Oct 2, 2017

interfaces/mount: port and rename XSnapdGroup
This patch ports the os/user.LookupGroup to osutil.FindGid which works
on golang 1.6. In addition rename the function and data names to match.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
interfaces/mount: port and rename XSnapdUser
This patch ports the os/user.LookupUser to osutil.FindUid which is
similar to FindGid that we already have to ues. In addition rename the
function and data names to match.

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

@zyga zyga changed the title from interfaces/mount: add support for parsing x-snapd-{mode,user,group}= to interfaces/mount: add support for parsing x-snapd-mkdir-{mode,uid,gid}= Oct 2, 2017

Contributor

zyga commented Oct 2, 2017

This should now work on older version of golang and has streamlined API that's more clear about the purpose.

interfaces/mount: rename XSnapdMode to XSnapdMkdirMode
This is just for consistency with other methods.

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

Looks good overall, some quick feedback, will take another look later.

interfaces/mount/entry.go
@@ -192,8 +195,63 @@ func OptsToFlags(opts []string) (flags int, err error) {
case "strictatime":
flags |= syscall.MS_STRICTATIME
default:
- return 0, fmt.Errorf("unsupported mount option: %q", opt)
+ if !strings.HasPrefix(opt, "x-snapd-") {
@stolowski

stolowski Oct 2, 2017

Contributor

Why do we accept x-snapd-* instead of only the well-defined ones?

@zyga

zyga Oct 2, 2017

Contributor

Just future proofing. I can make this an explicit list but not sure if we need that.

interfaces/mount/entry.go
+ return uid, nil
+ }
+ }
+ return uid, nil
@stolowski

stolowski Oct 2, 2017

Contributor

I think what you did below in XSnapdMkdirGid returning (0, nil) in such case is better and more readable.

@zyga

zyga Oct 2, 2017

Contributor

Thanks, I'll make that happen.

interfaces/mount/entry.go
+ gid, err = osutil.FindGid(kv[1])
+ if err != nil {
+ // The error message is not very useful so just skip it.
+ return gid, fmt.Errorf("cannot resolve group name %q", kv[1])
@stolowski

stolowski Oct 2, 2017

Contributor

Looking at osutil.FindGid (in particular at strconv.ParseUint) it's not totally clear that gid will be sane in case of error. I think it would make sense to play safe and return (0, err) here.

Same comment applies to FindUid above.

@zyga

zyga Oct 2, 2017

Contributor

Ack, I'll change that

interfaces/mount: tweak manner of returning
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

zyga commented Oct 3, 2017

Hmm, it seems we now cannot build snapd without cgo. Let me rethink this branch.

Contributor

zyga commented Oct 3, 2017

Aha, I figured out a way to make this work. I just need to move this to snap-update-ns which is already using cgo and where this limitation does not apply. Fortunately I have a PR for parts of this already.

zyga added some commits Oct 5, 2017

cmd/snap-update-ns: move new entry methods here
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

codecov-io commented Oct 5, 2017

Codecov Report

Merging #3965 into master will increase coverage by 0.03%.
The diff coverage is 93.87%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3965      +/-   ##
==========================================
+ Coverage   75.77%   75.81%   +0.03%     
==========================================
  Files         433      434       +1     
  Lines       37293    37341      +48     
==========================================
+ Hits        28259    28309      +50     
+ Misses       7059     7057       -2     
  Partials     1975     1975
Impacted Files Coverage Δ
interfaces/mount/entry.go 64.28% <100%> (+0.64%) ⬆️
cmd/snap-update-ns/entry.go 93.47% <93.47%> (ø)
overlord/snapstate/snapstate.go 80.29% <0%> (+0.24%) ⬆️
overlord/ifacestate/helpers.go 60.26% <0%> (+0.66%) ⬆️

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 9871f86...4e08ce2. Read the comment docs.

Contributor

zyga commented Oct 5, 2017

Oh, I still have one issue on golang 1.6 - src/github.com/snapcore/snapd/cmd/snap-update-ns/entry_test.go:92: undefined: user.LookupGroup -- l'll fix this imminently.

zyga added some commits Oct 5, 2017

cmd/snap-update-ns: don't use Lookup{User,Group}
The LookupGroup is not available in golang 1.6 and we have a replacement
already so let's use it.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: use x-snapd.foo rather than x-snapd-foo
This is recommended by the mount(8)

   X-*    All options prefixed with "X-" are interpreted as comments or as
	  userspace application-specific options. These options are not stored
	  in the user space (e.g. mtab file), nor sent to the mount.type
	  helpers nor to the mount(2) system call. The suggested format is X-
          appname.option.

   x-*    The same as X-* options, but stored permanently in the user space. It
	  means the options are also available for umount or another operations.
	  Note that maintain mount options in user space is tricky, because
	  it's necessary use libmount based tools and there is no guarantee
	  that the options will be always available (for example after a move
          mount operation or in unshared namespace).

	  Note that before util-linux v2.30 the x-* options have not been
	  maintained by libmount and stored in user space (functionality was
	  the same as have X-* now), but due to growing number of use-cases
	  (in initrd, systemd etc.) the functionality have been extended to
	  keep existing fstab configurations usable without a change.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-update-ns: drop the word mkdir from APIs
It's not strictly speaking just for mkdir and it's too verbose.

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

@zyga zyga changed the title from interfaces/mount: add support for parsing x-snapd-mkdir-{mode,uid,gid}= to interfaces/mount: add support for parsing x-snapd.{mode,uid,gid}= Oct 5, 2017

interfaces/mount: skip prefix x-snapd.
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

Thanks for addressing my previous comments. Please add test checks for sane uid/gid on error, and then +1.

cmd/snap-update-ns/entry_test.go
+ // Unknown group names are invalid.
+ e = &mount.Entry{Options: []string{"x-snapd.gid=.bogus"}}
+ _, err = update.XSnapdGid(e)
+ c.Assert(err, ErrorMatches, `cannot resolve group name ".bogus"`)
@stolowski

stolowski Oct 5, 2017

Contributor

Can you also add a check that the returned gid is 0 on error? Same for uid test above.

@zyga

zyga Oct 5, 2017

Contributor

Sure, done.

cmd/snap-update-ns: test that uid/gid is 0 on error
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

@zyga zyga requested a review from jdstrand Oct 11, 2017

Looks good, some nitpicks inside but no blocker or anything.

+}
+
+// XSnapdUid returns the user associated with x-snapd-user mount option. If
+// the mode is not specified explicitly then a default "root" use is
@mvo5

mvo5 Oct 16, 2017

Collaborator

Maybe: then a default "0" (root) id is returned ? Or use->user at least :)

@zyga

zyga Oct 16, 2017

Contributor

Aha, fixed :)

+}
+
+// XSnapdGid returns the user associated with x-snapd-user mount option. If
+// the mode is not specified explicitly then a default "root" use is
@mvo5

mvo5 Oct 16, 2017

Collaborator

Same suggestion as above.

@zyga

zyga Oct 16, 2017

Contributor

Fixed

cmd/snap-update-ns/entry_test.go
+ c.Assert(uid, Equals, uint64(0))
+
+ // User is parsed from the x-snapd-user= option.
+ daemonUid, err := osutil.FindUid("daemon")
@mvo5

mvo5 Oct 16, 2017

Collaborator

(nitpick) I would this below the XSnapUid() to make it more obvious that this is part of the "check" part of the "prepare, run, check" part of the test. Or maybe add a small helper findUid(c *C, name string) to avoid having to deal with error?

@zyga

zyga Oct 16, 2017

Contributor

+1

cmd/snap-update-ns/entry_test.go
+ c.Assert(gid, Equals, uint64(0))
+
+ // Group is parsed from the x-snapd-group= option.
+ daemonGid, err := osutil.FindGid("daemon")
@mvo5

mvo5 Oct 16, 2017

Collaborator

Same nitpick as above for the TestXSnapUid.

@zyga

zyga Oct 16, 2017

Contributor

Done

Contributor

zyga commented Oct 16, 2017

Done, tests will fail until #4048 is merged though.

Looks fine overall. Approving in the interest of time, but please see the inline comments for a couple things to consider and comment changes.

cmd/snap-update-ns/entry.go
+ if strings.HasPrefix(opt, "x-snapd.mode=") {
+ kv := strings.SplitN(opt, "=", 2)
+ var mode os.FileMode
+ n, err := fmt.Sscanf(kv[1], "%o", &mode)
@jdstrand

jdstrand Oct 24, 2017

Contributor

The Sscanf here is fine but I wonder if it would be more robust with a regex to validate the input?

@zyga

zyga Oct 25, 2017

Contributor

Good idea, done with 3821749

cmd/snap-update-ns/entry.go
+ for _, opt := range e.Options {
+ if strings.HasPrefix(opt, "x-snapd.uid=") {
+ kv := strings.SplitN(opt, "=", 2)
+ uid, err = osutil.FindUid(kv[1])
@jdstrand

jdstrand Oct 24, 2017

Contributor

This and XsnapGid do not support specifying by uid number (ie, x-snapd.uid=123 will fail). If this is intentional, can you please add a comment?

@zyga

zyga Oct 25, 2017

Contributor

Interesting. Since numbers are not valid user or group names we could extend this code to just return that number directly. I don't think we need this just yet but it's a natural extension to how this could work.

@zyga

zyga Oct 25, 2017

Contributor

On second thought I implemented this now in c3ec78e

cmd/snap-update-ns/entry.go
+ kv := strings.SplitN(opt, "=", 2)
+ uid, err = osutil.FindUid(kv[1])
+ if err != nil {
+ // The error message is not very useful so just skip it.
@jdstrand

jdstrand Oct 24, 2017

Contributor

I guess you mean 'The error message from FindUid is not very useful so just skip it?` Also see XSnapGid.

@zyga

zyga Oct 25, 2017

Contributor

Done in dd29313

cmd/snap-update-ns/entry.go
+ if err != nil {
+ // The error message is not very useful so just skip it.
+ return 0, fmt.Errorf("cannot resolve user name %q", kv[1])
+ }
@jdstrand

jdstrand Oct 24, 2017

Contributor

The code will return '0' as the uid if it can't find the uid, which seems to be papering over the error. Perhaps return math.MaxUint64? So long as consumers always check the error, not a blocker.

@zyga

zyga Oct 25, 2017

Contributor

Changed in 2359d31

interfaces/mount/entry_test.go
@@ -161,4 +161,10 @@ func (s *entrySuite) TestOptsToFlags(c *C) {
c.Assert(flags, Equals, syscall.MS_RDONLY|syscall.MS_NODEV|syscall.MS_NOSUID)
_, err = mount.OptsToFlags([]string{"bogus"})
c.Assert(err, ErrorMatches, `unsupported mount option: "bogus"`)
+ // The x-snapd-prefix is reserved for non-kernel parameters that do not
+ // translate to kernel level mount flags. This is similar to systemd or
+ // udisks use fstab options to convey additional data.
@jdstrand

jdstrand Oct 24, 2017

Contributor

s/udisks use/udisks that use/

@zyga

zyga Oct 25, 2017

Contributor

Done in af52b4f

zyga added some commits Oct 25, 2017

interfaces/mount: correct grammar
Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
cmd/snap-update-ns: use math.MaxUint64 for error values
Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
cmd/snap-update-ns: clarify which error is vague
Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
cmd/snap-update-ns: support numeric uid/gid values
Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
cmd/snap-update-ns: validate user/group/mode with regexp
Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>
cmd/snap-update-ns: switch to nobody/nogroup
Daemon is not so portable actually.

Signed-off-by: Zygmunt Krynicki <me@zygoon.pl>

@zyga zyga merged commit b6a22f8 into snapcore:master Oct 25, 2017

3 of 7 checks passed

artful-amd64 autopkgtest running
Details
artful-i386 autopkgtest running
Details
xenial-i386 autopkgtest running
Details
zesty-amd64 autopkgtest running
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
xenial-amd64 autopkgtest finished (success)
Details
xenial-ppc64el autopkgtest finished (success)
Details

@zyga zyga deleted the zyga:feature/mount-entry-attrs branch Oct 25, 2017

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