From 07d744068d437b09d7a07975e88e18440f5db2f3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 27 Jan 2020 20:16:35 -0800 Subject: filesystem: don't overwrite existing protector links When adding a protector to a policy, don't unconditionally overwrite the protector link, because it may already exist. Instead, if it already exists and points to the mount, just use it. If it already exists and points to the wrong place, return an error. Also add a bool to the return value of AddLinkedProtector() so that callers can check whether the link was newly created or not. --- actions/policy.go | 2 +- filesystem/filesystem.go | 37 ++++++++++++++++++++++++++++--------- filesystem/filesystem_test.go | 12 +++++++++++- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/actions/policy.go b/actions/policy.go index 41e108e..9d644c1 100644 --- a/actions/policy.go +++ b/actions/policy.go @@ -315,7 +315,7 @@ func (policy *Policy) AddProtector(protector *Protector) error { // to it on the policy's filesystem. if policy.Context.Mount != protector.Context.Mount { log.Printf("policy on %s\n protector on %s\n", policy.Context.Mount, protector.Context.Mount) - err := policy.Context.Mount.AddLinkedProtector( + _, err := policy.Context.Mount.AddLinkedProtector( protector.Descriptor(), protector.Context.Mount) if err != nil { return err diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 9bae72b..e0ef110 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -393,24 +393,43 @@ func (m *Mount) AddProtector(data *metadata.ProtectorData) error { } // AddLinkedProtector adds a link in this filesystem to the protector metadata -// in the dest filesystem. -func (m *Mount) AddLinkedProtector(descriptor string, dest *Mount) error { +// in the dest filesystem, if one doesn't already exist. On success, the return +// value is a nil error and a bool that is true iff the link is newly created. +func (m *Mount) AddLinkedProtector(descriptor string, dest *Mount) (bool, error) { if err := m.CheckSetup(); err != nil { - return err + return false, err } // Check that the link is good (descriptor exists, filesystem has UUID). if _, err := dest.GetRegularProtector(descriptor); err != nil { - return err + return false, err + } + + linkPath := m.linkedProtectorPath(descriptor) + + // Check whether the link already exists. + existingLink, err := ioutil.ReadFile(linkPath) + if err == nil { + existingLinkedMnt, err := getMountFromLink(string(existingLink)) + if err != nil { + return false, err + } + if existingLinkedMnt != dest { + return false, errors.Wrapf(ErrFollowLink, "link %q points to %q, but expected %q", + linkPath, existingLinkedMnt.Path, dest.Path) + } + return false, nil + } + if !os.IsNotExist(err) { + return false, err } // Right now, we only make links using UUIDs. - link, err := makeLink(dest, "UUID") + var newLink string + newLink, err = makeLink(dest, "UUID") if err != nil { - return dest.err(err) + return false, dest.err(err) } - - path := m.linkedProtectorPath(descriptor) - return m.err(m.writeDataAtomic(path, []byte(link))) + return true, m.err(m.writeDataAtomic(linkPath, []byte(newLink))) } // GetRegularProtector looks up the protector metadata by descriptor. This will diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index b85ead5..4bed96a 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -351,9 +351,19 @@ func TestLinkedProtector(t *testing.T) { } // Add the link to the second filesystem - if err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil { + var isNewLink bool + if isNewLink, err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil { t.Fatal(err) } + if !isNewLink { + t.Fatal("Link was not new") + } + if isNewLink, err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil { + t.Fatal(err) + } + if isNewLink { + t.Fatal("Link was new") + } // Get the protector though the second system _, err = fakeMnt.GetRegularProtector(protector.ProtectorDescriptor) -- cgit v1.2.3