Copy up parent when binding UDS on overlayfs

Overlayfs was expecting the parent to exist when bind(2)
was called, which may not be the case. The fix is to copy
the parent directory to the upper layer before binding
the UDS.

There is not good place to add tests for it. Syscall tests
would be ideal, but it's hard to guarantee that the
directory where the socket is created hasn't been touched
before (and thus copied the parent to the upper layer).
Added it to runsc integration tests for now. If it turns
out we have lots of these kind of tests, we can consider
moving them somewhere more appropriate.

PiperOrigin-RevId: 251954156
This commit is contained in:
Fabricio Voznika
2019-06-06 16:45:51 -07:00
committed by Shentubot
parent b3f104507d
commit 02ab1f187c
5 changed files with 55 additions and 9 deletions
+1 -1
View File
@@ -805,7 +805,7 @@ func (d *Dirent) Bind(ctx context.Context, root *Dirent, name string, data trans
var childDir *Dirent
err := d.genericCreate(ctx, root, name, func() error {
var e error
childDir, e = d.Inode.Bind(ctx, name, data, perms)
childDir, e = d.Inode.Bind(ctx, d, name, data, perms)
if e != nil {
return e
}
+2 -2
View File
@@ -220,9 +220,9 @@ func (i *Inode) Rename(ctx context.Context, oldParent *Dirent, renamed *Dirent,
}
// Bind calls i.InodeOperations.Bind with i as the directory.
func (i *Inode) Bind(ctx context.Context, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) {
func (i *Inode) Bind(ctx context.Context, parent *Dirent, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) {
if i.overlay != nil {
return overlayBind(ctx, i.overlay, name, data, perm)
return overlayBind(ctx, i.overlay, parent, name, data, perm)
}
return i.InodeOperations.Bind(ctx, i, name, data, perm)
}
+6 -6
View File
@@ -398,14 +398,14 @@ func overlayRename(ctx context.Context, o *overlayEntry, oldParent *Dirent, rena
return nil
}
func overlayBind(ctx context.Context, o *overlayEntry, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) {
func overlayBind(ctx context.Context, o *overlayEntry, parent *Dirent, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) {
if err := copyUp(ctx, parent); err != nil {
return nil, err
}
o.copyMu.RLock()
defer o.copyMu.RUnlock()
// We do not support doing anything exciting with sockets unless there
// is already a directory in the upper filesystem.
if o.upper == nil {
return nil, syserror.EOPNOTSUPP
}
d, err := o.upper.InodeOperations.Bind(ctx, o.upper, name, data, perm)
if err != nil {
return nil, err
+1
View File
@@ -8,6 +8,7 @@ go_test(
srcs = [
"exec_test.go",
"integration_test.go",
"regression_test.go",
],
embed = [":integration"],
tags = [
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package integration
import (
"strings"
"testing"
"gvisor.googlesource.com/gvisor/runsc/test/testutil"
)
// Test that UDS can be created using overlay when parent directory is in lower
// layer only (b/134090485).
//
// Prerequisite: the directory where the socket file is created must not have
// been open for write before bind(2) is called.
func TestBindOverlay(t *testing.T) {
if err := testutil.Pull("ubuntu:trusty"); err != nil {
t.Fatal("docker pull failed:", err)
}
d := testutil.MakeDocker("bind-overlay-test")
cmd := "nc -l -U /var/run/sock& sleep 1 && echo foobar-asdf | nc -U /var/run/sock"
got, err := d.RunFg("ubuntu:trusty", "bash", "-c", cmd)
if err != nil {
t.Fatal("docker run failed:", err)
}
if want := "foobar-asdf"; !strings.Contains(got, want) {
t.Fatalf("docker run output is missing %q: %s", want, got)
}
defer d.CleanUp()
}