diff options
author | Brian Geffon <bgeffon@google.com> | 2018-12-04 14:31:08 -0800 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-12-04 14:32:03 -0800 |
commit | 82719be42e636f86780d21b01e10ecb2c9a25e53 (patch) | |
tree | 1c635cae30683e3cdc13a497cf529063ed7f56dc /pkg | |
parent | adafc08d7cee594ea94abefbedf67ea315922550 (diff) |
Max link traversals should be for an entire path.
The number of symbolic links that are allowed to be followed
are for a full path and not just a chain of symbolic links.
PiperOrigin-RevId: 224047321
Change-Id: I5e3c4caf66a93c17eeddcc7f046d1e8bb9434a40
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/sentry/fs/copy_up_test.go | 3 | ||||
-rw-r--r-- | pkg/sentry/fs/host/fs.go | 3 | ||||
-rw-r--r-- | pkg/sentry/fs/host/fs_test.go | 3 | ||||
-rw-r--r-- | pkg/sentry/fs/inode_overlay_test.go | 3 | ||||
-rw-r--r-- | pkg/sentry/fs/mount_test.go | 10 | ||||
-rw-r--r-- | pkg/sentry/fs/mounts.go | 22 | ||||
-rw-r--r-- | pkg/sentry/fs/mounts_test.go | 6 | ||||
-rw-r--r-- | pkg/sentry/fs/ramfs/tree_test.go | 3 | ||||
-rw-r--r-- | pkg/sentry/kernel/kernel.go | 6 | ||||
-rw-r--r-- | pkg/sentry/kernel/task_context.go | 2 | ||||
-rw-r--r-- | pkg/sentry/loader/elf.go | 2 | ||||
-rw-r--r-- | pkg/sentry/loader/loader.go | 10 | ||||
-rw-r--r-- | pkg/sentry/socket/unix/unix.go | 6 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_file.go | 11 | ||||
-rw-r--r-- | pkg/sentry/syscalls/linux/sys_thread.go | 3 |
15 files changed, 57 insertions, 36 deletions
diff --git a/pkg/sentry/fs/copy_up_test.go b/pkg/sentry/fs/copy_up_test.go index 64f030f72..fcba14ed4 100644 --- a/pkg/sentry/fs/copy_up_test.go +++ b/pkg/sentry/fs/copy_up_test.go @@ -166,7 +166,8 @@ func makeOverlayTestFiles(t *testing.T) []*overlayTestFile { // Walk to all of the files in the overlay, open them readable. for _, f := range files { - d, err := mns.FindInode(ctx, mns.Root(), mns.Root(), f.name, 0) + maxTraversals := uint(0) + d, err := mns.FindInode(ctx, mns.Root(), mns.Root(), f.name, &maxTraversals) if err != nil { t.Fatalf("failed to find %q: %v", f.name, err) } diff --git a/pkg/sentry/fs/host/fs.go b/pkg/sentry/fs/host/fs.go index fec890964..54cbb94f9 100644 --- a/pkg/sentry/fs/host/fs.go +++ b/pkg/sentry/fs/host/fs.go @@ -170,7 +170,8 @@ func installWhitelist(ctx context.Context, m *fs.MountNamespace, paths []string) current := paths[i][:j] // Lookup the given component in the tree. - d, err := m.FindLink(ctx, root, nil, current, maxTraversals) + remainingTraversals := uint(maxTraversals) + d, err := m.FindLink(ctx, root, nil, current, &remainingTraversals) if err != nil { log.Warningf("populate failed for %q: %v", current, err) continue diff --git a/pkg/sentry/fs/host/fs_test.go b/pkg/sentry/fs/host/fs_test.go index e69559aac..44db61ecd 100644 --- a/pkg/sentry/fs/host/fs_test.go +++ b/pkg/sentry/fs/host/fs_test.go @@ -150,7 +150,8 @@ func allPaths(ctx context.Context, t *testing.T, m *fs.MountNamespace, base stri root := m.Root() defer root.DecRef() - d, err := m.FindLink(ctx, root, nil, base, 1) + maxTraversals := uint(1) + d, err := m.FindLink(ctx, root, nil, base, &maxTraversals) if err != nil { t.Logf("FindLink failed for %q", base) return paths, err diff --git a/pkg/sentry/fs/inode_overlay_test.go b/pkg/sentry/fs/inode_overlay_test.go index bba20da14..acdb2b4f8 100644 --- a/pkg/sentry/fs/inode_overlay_test.go +++ b/pkg/sentry/fs/inode_overlay_test.go @@ -324,7 +324,8 @@ func TestCacheFlush(t *testing.T) { for _, fileName := range []string{upperFileName, lowerFileName} { // Walk to the file. - dirent, err := mns.FindInode(ctx, root, nil, fileName, 0) + maxTraversals := uint(0) + dirent, err := mns.FindInode(ctx, root, nil, fileName, &maxTraversals) if err != nil { t.Fatalf("FindInode(%q) failed: %v", fileName, err) } diff --git a/pkg/sentry/fs/mount_test.go b/pkg/sentry/fs/mount_test.go index a1c9f4f79..269d6b9da 100644 --- a/pkg/sentry/fs/mount_test.go +++ b/pkg/sentry/fs/mount_test.go @@ -115,8 +115,10 @@ func TestMountSourceParentChildRelationship(t *testing.T) { "/waldo", } + var maxTraversals uint for _, p := range paths { - d, err := mm.FindLink(ctx, rootDirent, nil, p, 0) + maxTraversals = 0 + d, err := mm.FindLink(ctx, rootDirent, nil, p, &maxTraversals) if err != nil { t.Fatalf("could not find path %q in mount manager: %v", p, err) } @@ -164,7 +166,8 @@ func TestMountSourceParentChildRelationship(t *testing.T) { } // "foo" mount should have two children: /foo/bar, and /foo/qux. - d, err := mm.FindLink(ctx, rootDirent, nil, "/foo", 0) + maxTraversals = 0 + d, err := mm.FindLink(ctx, rootDirent, nil, "/foo", &maxTraversals) if err != nil { t.Fatalf("could not find path %q in mount manager: %v", "/foo", err) } @@ -185,7 +188,8 @@ func TestMountSourceParentChildRelationship(t *testing.T) { } // "waldo" mount should have no submounts or children. - waldo, err := mm.FindLink(ctx, rootDirent, nil, "/waldo", 0) + maxTraversals = 0 + waldo, err := mm.FindLink(ctx, rootDirent, nil, "/waldo", &maxTraversals) if err != nil { t.Fatalf("could not find path %q in mount manager: %v", "/waldo", err) } diff --git a/pkg/sentry/fs/mounts.go b/pkg/sentry/fs/mounts.go index 7c5348cce..f6f7be0aa 100644 --- a/pkg/sentry/fs/mounts.go +++ b/pkg/sentry/fs/mounts.go @@ -350,7 +350,7 @@ func (mns *MountNamespace) Unmount(ctx context.Context, node *Dirent, detachOnly // // Precondition: root must be non-nil. // Precondition: the path must be non-empty. -func (mns *MountNamespace) FindLink(ctx context.Context, root, wd *Dirent, path string, maxTraversals uint) (*Dirent, error) { +func (mns *MountNamespace) FindLink(ctx context.Context, root, wd *Dirent, path string, remainingTraversals *uint) (*Dirent, error) { if root == nil { panic("MountNamespace.FindLink: root must not be nil") } @@ -419,7 +419,7 @@ func (mns *MountNamespace) FindLink(ctx context.Context, root, wd *Dirent, path // // See resolve for reference semantics; on err next // will have one dropped. - current, err = mns.resolve(ctx, root, next, maxTraversals) + current, err = mns.resolve(ctx, root, next, remainingTraversals) if err != nil { return nil, err } @@ -439,15 +439,15 @@ func (mns *MountNamespace) FindLink(ctx context.Context, root, wd *Dirent, path // FindInode is identical to FindLink except the return value is resolved. // //go:nosplit -func (mns *MountNamespace) FindInode(ctx context.Context, root, wd *Dirent, path string, maxTraversals uint) (*Dirent, error) { - d, err := mns.FindLink(ctx, root, wd, path, maxTraversals) +func (mns *MountNamespace) FindInode(ctx context.Context, root, wd *Dirent, path string, remainingTraversals *uint) (*Dirent, error) { + d, err := mns.FindLink(ctx, root, wd, path, remainingTraversals) if err != nil { return nil, err } // See resolve for reference semantics; on err d will have the // reference dropped. - return mns.resolve(ctx, root, d, maxTraversals) + return mns.resolve(ctx, root, d, remainingTraversals) } // resolve resolves the given link. @@ -458,14 +458,14 @@ func (mns *MountNamespace) FindInode(ctx context.Context, root, wd *Dirent, path // If not successful, a reference is _also_ dropped on the node and an error // returned. This is for convenience in using resolve directly as a return // value. -func (mns *MountNamespace) resolve(ctx context.Context, root, node *Dirent, maxTraversals uint) (*Dirent, error) { +func (mns *MountNamespace) resolve(ctx context.Context, root, node *Dirent, remainingTraversals *uint) (*Dirent, error) { // Resolve the path. target, err := node.Inode.Getlink(ctx) switch err { case nil: // Make sure we didn't exhaust the traversal budget. - if maxTraversals == 0 { + if *remainingTraversals == 0 { target.DecRef() return nil, syscall.ELOOP } @@ -481,7 +481,7 @@ func (mns *MountNamespace) resolve(ctx context.Context, root, node *Dirent, maxT defer node.DecRef() // See above. // First, check if we should traverse. - if maxTraversals == 0 { + if *remainingTraversals == 0 { return nil, syscall.ELOOP } @@ -492,7 +492,8 @@ func (mns *MountNamespace) resolve(ctx context.Context, root, node *Dirent, maxT } // Find the node; we resolve relative to the current symlink's parent. - d, err := mns.FindInode(ctx, root, node.parent, targetPath, maxTraversals-1) + *remainingTraversals-- + d, err := mns.FindInode(ctx, root, node.parent, targetPath, remainingTraversals) if err != nil { return nil, err } @@ -544,7 +545,8 @@ func (mns *MountNamespace) ResolveExecutablePath(ctx context.Context, wd, name s defer root.DecRef() for _, p := range paths { binPath := path.Join(p, name) - d, err := mns.FindInode(ctx, root, nil, binPath, linux.MaxSymlinkTraversals) + traversals := uint(linux.MaxSymlinkTraversals) + d, err := mns.FindInode(ctx, root, nil, binPath, &traversals) if err == syserror.ENOENT || err == syserror.EACCES { // Didn't find it here. continue diff --git a/pkg/sentry/fs/mounts_test.go b/pkg/sentry/fs/mounts_test.go index cc7c32c9b..2f7a1710f 100644 --- a/pkg/sentry/fs/mounts_test.go +++ b/pkg/sentry/fs/mounts_test.go @@ -77,7 +77,8 @@ func TestFindLink(t *testing.T) { {"bar", foo, "/foo/bar"}, } { wdPath, _ := tc.wd.FullName(root) - if d, err := mm.FindLink(ctx, root, tc.wd, tc.findPath, 0); err != nil { + maxTraversals := uint(0) + if d, err := mm.FindLink(ctx, root, tc.wd, tc.findPath, &maxTraversals); err != nil { t.Errorf("FindLink(%q, wd=%q) failed: %v", tc.findPath, wdPath, err) } else if got, _ := d.FullName(root); got != tc.wantPath { t.Errorf("FindLink(%q, wd=%q) got dirent %q, want %q", tc.findPath, wdPath, got, tc.wantPath) @@ -95,7 +96,8 @@ func TestFindLink(t *testing.T) { {"foo", foo}, } { wdPath, _ := tc.wd.FullName(root) - if _, err := mm.FindLink(ctx, root, tc.wd, tc.findPath, 0); err == nil { + maxTraversals := uint(0) + if _, err := mm.FindLink(ctx, root, tc.wd, tc.findPath, &maxTraversals); err == nil { t.Errorf("FindLink(%q, wd=%q) did not return error", tc.findPath, wdPath) } } diff --git a/pkg/sentry/fs/ramfs/tree_test.go b/pkg/sentry/fs/ramfs/tree_test.go index d5567d9e1..54df2143c 100644 --- a/pkg/sentry/fs/ramfs/tree_test.go +++ b/pkg/sentry/fs/ramfs/tree_test.go @@ -70,7 +70,8 @@ func TestMakeDirectoryTree(t *testing.T) { defer mm.DecRef() for _, p := range test.subdirs { - if _, err := mm.FindInode(ctx, root, nil, p, 0); err != nil { + maxTraversals := uint(0) + if _, err := mm.FindInode(ctx, root, nil, p, &maxTraversals); err != nil { t.Errorf("%s: failed to find node %s: %v", test.name, p, err) break } diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 17425e656..cb61e27f1 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -634,10 +634,11 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, args.Root = nil // Grab the working directory. + remainingTraversals := uint(args.MaxSymlinkTraversals) wd := root // Default. if args.WorkingDirectory != "" { var err error - wd, err = k.mounts.FindInode(ctx, root, nil, args.WorkingDirectory, args.MaxSymlinkTraversals) + wd, err = k.mounts.FindInode(ctx, root, nil, args.WorkingDirectory, &remainingTraversals) if err != nil { return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err) } @@ -656,7 +657,8 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, } // Create a fresh task context. - tc, err := k.LoadTaskImage(ctx, k.mounts, root, wd, args.MaxSymlinkTraversals, args.Filename, args.Argv, args.Envv, k.featureSet) + remainingTraversals = uint(args.MaxSymlinkTraversals) + tc, err := k.LoadTaskImage(ctx, k.mounts, root, wd, &remainingTraversals, args.Filename, args.Argv, args.Envv, k.featureSet) if err != nil { return nil, 0, err } diff --git a/pkg/sentry/kernel/task_context.go b/pkg/sentry/kernel/task_context.go index 45b8d2b04..aaff309f0 100644 --- a/pkg/sentry/kernel/task_context.go +++ b/pkg/sentry/kernel/task_context.go @@ -142,7 +142,7 @@ func (t *Task) Stack() *arch.Stack { // * argv: Binary argv // * envv: Binary envv // * fs: Binary FeatureSet -func (k *Kernel) LoadTaskImage(ctx context.Context, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, filename string, argv, envv []string, fs *cpuid.FeatureSet) (*TaskContext, error) { +func (k *Kernel) LoadTaskImage(ctx context.Context, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals *uint, filename string, argv, envv []string, fs *cpuid.FeatureSet) (*TaskContext, error) { // Prepare a new user address space to load into. m := mm.NewMemoryManager(k) defer m.DecUsers(ctx) diff --git a/pkg/sentry/loader/elf.go b/pkg/sentry/loader/elf.go index 9b1e81dc9..385ad0102 100644 --- a/pkg/sentry/loader/elf.go +++ b/pkg/sentry/loader/elf.go @@ -610,7 +610,7 @@ func loadInterpreterELF(ctx context.Context, m *mm.MemoryManager, f *fs.File, in // // Preconditions: // * f is an ELF file -func loadELF(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, fs *cpuid.FeatureSet, f *fs.File) (loadedELF, arch.Context, error) { +func loadELF(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals *uint, fs *cpuid.FeatureSet, f *fs.File) (loadedELF, arch.Context, error) { bin, ac, err := loadInitialELF(ctx, m, fs, f) if err != nil { ctx.Infof("Error loading binary: %v", err) diff --git a/pkg/sentry/loader/loader.go b/pkg/sentry/loader/loader.go index d1417c4f1..69a090844 100644 --- a/pkg/sentry/loader/loader.go +++ b/pkg/sentry/loader/loader.go @@ -55,7 +55,7 @@ func readFull(ctx context.Context, f *fs.File, dst usermem.IOSequence, offset in // installed in the Task FDMap. The caller takes ownership of both. // // name must be a readable, executable, regular file. -func openPath(ctx context.Context, mm *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, name string) (*fs.Dirent, *fs.File, error) { +func openPath(ctx context.Context, mm *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals *uint, name string) (*fs.Dirent, *fs.File, error) { if name == "" { ctx.Infof("cannot open empty name") return nil, nil, syserror.ENOENT @@ -136,9 +136,9 @@ const ( // * arch.Context matching the binary arch // * fs.Dirent of the binary file // * Possibly updated argv -func loadPath(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, fs *cpuid.FeatureSet, filename string, argv, envv []string) (loadedELF, arch.Context, *fs.Dirent, []string, error) { +func loadPath(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, remainingTraversals *uint, fs *cpuid.FeatureSet, filename string, argv, envv []string) (loadedELF, arch.Context, *fs.Dirent, []string, error) { for i := 0; i < maxLoaderAttempts; i++ { - d, f, err := openPath(ctx, mounts, root, wd, maxTraversals, filename) + d, f, err := openPath(ctx, mounts, root, wd, remainingTraversals, filename) if err != nil { ctx.Infof("Error opening %s: %v", filename, err) return loadedELF{}, nil, nil, nil, err @@ -163,7 +163,7 @@ func loadPath(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespac switch { case bytes.Equal(hdr[:], []byte(elfMagic)): - loaded, ac, err := loadELF(ctx, m, mounts, root, wd, maxTraversals, fs, f) + loaded, ac, err := loadELF(ctx, m, mounts, root, wd, remainingTraversals, fs, f) if err != nil { ctx.Infof("Error loading ELF: %v", err) return loadedELF{}, nil, nil, nil, err @@ -196,7 +196,7 @@ func loadPath(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespac // Preconditions: // * The Task MemoryManager is empty. // * Load is called on the Task goroutine. -func Load(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, fs *cpuid.FeatureSet, filename string, argv, envv []string, extraAuxv []arch.AuxEntry, vdso *VDSO) (abi.OS, arch.Context, string, error) { +func Load(ctx context.Context, m *mm.MemoryManager, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals *uint, fs *cpuid.FeatureSet, filename string, argv, envv []string, extraAuxv []arch.AuxEntry, vdso *VDSO) (abi.OS, arch.Context, string, error) { // Load the binary itself. loaded, ac, d, argv, err := loadPath(ctx, m, mounts, root, wd, maxTraversals, fs, filename, argv, envv) if err != nil { diff --git a/pkg/sentry/socket/unix/unix.go b/pkg/sentry/socket/unix/unix.go index 334169372..4379486cf 100644 --- a/pkg/sentry/socket/unix/unix.go +++ b/pkg/sentry/socket/unix/unix.go @@ -266,7 +266,8 @@ func (s *SocketOperations) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error { subPath = "/" } var err error - d, err = t.MountNamespace().FindInode(t, root, cwd, subPath, fs.DefaultTraversalLimit) + remainingTraversals := uint(fs.DefaultTraversalLimit) + d, err = t.MountNamespace().FindInode(t, root, cwd, subPath, &remainingTraversals) if err != nil { // No path available. return syserr.ErrNoSuchFile @@ -314,7 +315,8 @@ func extractEndpoint(t *kernel.Task, sockaddr []byte) (transport.BoundEndpoint, // Find the node in the filesystem. root := t.FSContext().RootDirectory() cwd := t.FSContext().WorkingDirectory() - d, e := t.MountNamespace().FindInode(t, root, cwd, path, fs.DefaultTraversalLimit) + remainingTraversals := uint(fs.DefaultTraversalLimit) + d, e := t.MountNamespace().FindInode(t, root, cwd, path, &remainingTraversals) cwd.DecRef() root.DecRef() if e != nil { diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index 89d21dd98..37c90f6fd 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -92,10 +92,11 @@ func fileOpOn(t *kernel.Task, dirFD kdefs.FD, path string, resolve bool, fn func root := t.FSContext().RootDirectory() // Lookup the node. + remainingTraversals := uint(linux.MaxSymlinkTraversals) if resolve { - d, err = t.MountNamespace().FindInode(t, root, rel, path, linux.MaxSymlinkTraversals) + d, err = t.MountNamespace().FindInode(t, root, rel, path, &remainingTraversals) } else { - d, err = t.MountNamespace().FindLink(t, root, rel, path, linux.MaxSymlinkTraversals) + d, err = t.MountNamespace().FindLink(t, root, rel, path, &remainingTraversals) } root.DecRef() if wd != nil { @@ -312,7 +313,8 @@ func createAt(t *kernel.Task, dirFD kdefs.FD, addr usermem.Addr, flags uint, mod fileFlags.LargeFile = true // Does this file exist already? - targetDirent, err := t.MountNamespace().FindInode(t, root, d, name, linux.MaxSymlinkTraversals) + remainingTraversals := uint(linux.MaxSymlinkTraversals) + targetDirent, err := t.MountNamespace().FindInode(t, root, d, name, &remainingTraversals) var newFile *fs.File switch err { case nil: @@ -997,7 +999,8 @@ func mkdirAt(t *kernel.Task, dirFD kdefs.FD, addr usermem.Addr, mode linux.FileM } // Does this directory exist already? - f, err := t.MountNamespace().FindInode(t, root, d, name, linux.MaxSymlinkTraversals) + remainingTraversals := uint(linux.MaxSymlinkTraversals) + f, err := t.MountNamespace().FindInode(t, root, d, name, &remainingTraversals) switch err { case nil: // The directory existed. diff --git a/pkg/sentry/syscalls/linux/sys_thread.go b/pkg/sentry/syscalls/linux/sys_thread.go index 9eed613a1..c12693ee2 100644 --- a/pkg/sentry/syscalls/linux/sys_thread.go +++ b/pkg/sentry/syscalls/linux/sys_thread.go @@ -103,7 +103,8 @@ func Execve(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal defer wd.DecRef() // Load the new TaskContext. - tc, err := t.Kernel().LoadTaskImage(t, t.MountNamespace(), root, wd, linux.MaxSymlinkTraversals, filename, argv, envv, t.Arch().FeatureSet()) + maxTraversals := uint(linux.MaxSymlinkTraversals) + tc, err := t.Kernel().LoadTaskImage(t, t.MountNamespace(), root, wd, &maxTraversals, filename, argv, envv, t.Arch().FeatureSet()) if err != nil { return 0, nil, err } |