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. --- filesystem/filesystem.go | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'filesystem/filesystem.go') 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 -- cgit v1.2.3