mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
@@ -1,21 +0,0 @@
|
||||
load("//tools:defs.bzl", "go_library")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
go_library(
|
||||
name = "fsbridge",
|
||||
srcs = [
|
||||
"bridge.go",
|
||||
"vfs.go",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/fspath",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/memmap",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
)
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2020 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 fsbridge provides common interfaces to bridge between VFS1 and VFS2
|
||||
// files.
|
||||
// TODO(gvisor.dev/issue/1624): Delete this package.
|
||||
package fsbridge
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// File provides a common interface to bridge between VFS1 and VFS2 files.
|
||||
type File interface {
|
||||
// PathnameWithDeleted returns an absolute pathname to vd, consistent with
|
||||
// Linux's d_path(). In particular, if vd.Dentry() has been disowned,
|
||||
// PathnameWithDeleted appends " (deleted)" to the returned pathname.
|
||||
PathnameWithDeleted(ctx context.Context) string
|
||||
|
||||
// ReadFull read all contents from the file.
|
||||
ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error)
|
||||
|
||||
// ConfigureMMap mutates opts to implement mmap(2) for the file.
|
||||
ConfigureMMap(context.Context, *memmap.MMapOpts) error
|
||||
|
||||
// Type returns the file type, e.g. linux.S_IFREG.
|
||||
Type(context.Context) (linux.FileMode, error)
|
||||
|
||||
// IncRef increments reference.
|
||||
IncRef()
|
||||
|
||||
// DecRef decrements reference.
|
||||
DecRef(ctx context.Context)
|
||||
}
|
||||
|
||||
// Lookup provides a common interface to open files.
|
||||
type Lookup interface {
|
||||
// OpenPath opens a file.
|
||||
OpenPath(ctx context.Context, path string, opts vfs.OpenOptions, remainingTraversals *uint, resolveFinal bool) (File, error)
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
// Copyright 2020 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 fsbridge
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/fspath"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// VFSFile implements File interface over vfs.FileDescription.
|
||||
//
|
||||
// +stateify savable
|
||||
type VFSFile struct {
|
||||
file *vfs.FileDescription
|
||||
}
|
||||
|
||||
var _ File = (*VFSFile)(nil)
|
||||
|
||||
// NewVFSFile creates a new File over fs.File.
|
||||
func NewVFSFile(file *vfs.FileDescription) File {
|
||||
return &VFSFile{file: file}
|
||||
}
|
||||
|
||||
// PathnameWithDeleted implements File.
|
||||
func (f *VFSFile) PathnameWithDeleted(ctx context.Context) string {
|
||||
root := vfs.RootFromContext(ctx)
|
||||
defer root.DecRef(ctx)
|
||||
|
||||
vfsObj := f.file.VirtualDentry().Mount().Filesystem().VirtualFilesystem()
|
||||
name, _ := vfsObj.PathnameWithDeleted(ctx, root, f.file.VirtualDentry())
|
||||
return name
|
||||
}
|
||||
|
||||
// ReadFull implements File.
|
||||
func (f *VFSFile) ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
var total int64
|
||||
for dst.NumBytes() > 0 {
|
||||
n, err := f.file.PRead(ctx, dst, offset+total, vfs.ReadOptions{})
|
||||
total += n
|
||||
if err == io.EOF && total != 0 {
|
||||
return total, io.ErrUnexpectedEOF
|
||||
} else if err != nil {
|
||||
return total, err
|
||||
}
|
||||
dst = dst.DropFirst64(n)
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// ConfigureMMap implements File.
|
||||
func (f *VFSFile) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
|
||||
return f.file.ConfigureMMap(ctx, opts)
|
||||
}
|
||||
|
||||
// Type implements File.
|
||||
func (f *VFSFile) Type(ctx context.Context) (linux.FileMode, error) {
|
||||
stat, err := f.file.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return linux.FileMode(stat.Mode).FileType(), nil
|
||||
}
|
||||
|
||||
// IncRef implements File.
|
||||
func (f *VFSFile) IncRef() {
|
||||
f.file.IncRef()
|
||||
}
|
||||
|
||||
// DecRef implements File.
|
||||
func (f *VFSFile) DecRef(ctx context.Context) {
|
||||
f.file.DecRef(ctx)
|
||||
}
|
||||
|
||||
// FileDescription returns the FileDescription represented by f. It does not
|
||||
// take an additional reference on the returned FileDescription.
|
||||
func (f *VFSFile) FileDescription() *vfs.FileDescription {
|
||||
return f.file
|
||||
}
|
||||
|
||||
// fsLookup implements Lookup interface using fs.File.
|
||||
//
|
||||
// +stateify savable
|
||||
type vfsLookup struct {
|
||||
mntns *vfs.MountNamespace
|
||||
|
||||
root vfs.VirtualDentry
|
||||
workingDir vfs.VirtualDentry
|
||||
}
|
||||
|
||||
var _ Lookup = (*vfsLookup)(nil)
|
||||
|
||||
// NewVFSLookup creates a new Lookup.
|
||||
func NewVFSLookup(mntns *vfs.MountNamespace, root, workingDir vfs.VirtualDentry) Lookup {
|
||||
return &vfsLookup{
|
||||
mntns: mntns,
|
||||
root: root,
|
||||
workingDir: workingDir,
|
||||
}
|
||||
}
|
||||
|
||||
// OpenPath implements Lookup.
|
||||
//
|
||||
// remainingTraversals is not configurable, all callers are using the
|
||||
// default anyways.
|
||||
func (l *vfsLookup) OpenPath(ctx context.Context, pathname string, opts vfs.OpenOptions, _ *uint, resolveFinal bool) (File, error) {
|
||||
vfsObj := l.root.Mount().Filesystem().VirtualFilesystem()
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
path := fspath.Parse(pathname)
|
||||
pop := &vfs.PathOperation{
|
||||
Root: l.root,
|
||||
Start: l.workingDir,
|
||||
Path: path,
|
||||
FollowFinalSymlink: resolveFinal,
|
||||
}
|
||||
if path.Absolute {
|
||||
pop.Start = l.root
|
||||
}
|
||||
fd, err := vfsObj.OpenAt(ctx, creds, pop, &opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &VFSFile{file: fd}, nil
|
||||
}
|
||||
@@ -87,7 +87,6 @@ go_library(
|
||||
"//pkg/log",
|
||||
"//pkg/refs",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/fsimpl/lock",
|
||||
"//pkg/sentry/inet",
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/safemem"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -967,7 +966,7 @@ func (s *exeSymlink) Getlink(ctx context.Context, _ *vfs.Mount) (vfs.VirtualDent
|
||||
}
|
||||
defer exec.DecRef(ctx)
|
||||
|
||||
vd := exec.(*fsbridge.VFSFile).FileDescription().VirtualDentry()
|
||||
vd := exec.VirtualDentry()
|
||||
vd.IncRef()
|
||||
return vd, "", nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ go_library(
|
||||
"//pkg/fspath",
|
||||
"//pkg/hostarch",
|
||||
"//pkg/memutil",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/fsimpl/tmpfs",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/fspath"
|
||||
"gvisor.dev/gvisor/pkg/memutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
@@ -128,7 +127,7 @@ func CreateTask(ctx context.Context, name string, tc *kernel.ThreadGroup, mntns
|
||||
return nil, err
|
||||
}
|
||||
m := mm.NewMemoryManager(k, k, k.SleepForAddressSpaceActivation)
|
||||
m.SetExecutable(ctx, fsbridge.NewVFSFile(exe))
|
||||
m.SetExecutable(ctx, exe)
|
||||
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
config := &kernel.TaskConfig{
|
||||
|
||||
@@ -306,7 +306,6 @@ go_library(
|
||||
"//pkg/secio",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/device",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/fsimpl/lock",
|
||||
"//pkg/sentry/fsimpl/mqfs",
|
||||
|
||||
@@ -47,7 +47,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/fspath"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/pipefs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/timerfd"
|
||||
@@ -660,7 +659,7 @@ type CreateProcessArgs struct {
|
||||
// File is a passed host FD pointing to a file to load as the init binary.
|
||||
//
|
||||
// This is checked if and only if Filename is "".
|
||||
File fsbridge.File
|
||||
File *vfs.FileDescription
|
||||
|
||||
// Argvv is a list of arguments.
|
||||
Argv []string
|
||||
@@ -839,7 +838,6 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
||||
}
|
||||
defer wd.DecRef(ctx)
|
||||
}
|
||||
opener := fsbridge.NewVFSLookup(mntns, root, wd)
|
||||
fsContext := NewFSContext(root, wd, args.Umask)
|
||||
|
||||
tg := k.NewThreadGroup(args.PIDNamespace, NewSignalHandlers(), linux.SIGCHLD, args.Limits)
|
||||
@@ -856,7 +854,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
||||
args.File = nil
|
||||
case args.File != nil:
|
||||
// If File is set, take the File provided directly.
|
||||
args.Filename = args.File.PathnameWithDeleted(ctx)
|
||||
args.Filename = args.File.MappedName(ctx)
|
||||
default:
|
||||
// Otherwise look at Argv and see if the first argument is a valid path.
|
||||
if len(args.Argv) == 0 {
|
||||
@@ -871,7 +869,8 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
|
||||
// Create a fresh task context.
|
||||
remainingTraversals := args.MaxSymlinkTraversals
|
||||
loadArgs := loader.LoadArgs{
|
||||
Opener: opener,
|
||||
Root: root,
|
||||
WorkingDir: wd,
|
||||
RemainingTraversals: &remainingTraversals,
|
||||
ResolveFinal: true,
|
||||
Filename: args.Filename,
|
||||
|
||||
@@ -67,7 +67,6 @@ package kernel
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/mm"
|
||||
"gvisor.dev/gvisor/pkg/sentry/seccheck"
|
||||
pb "gvisor.dev/gvisor/pkg/sentry/seccheck/points/points_go_proto"
|
||||
@@ -92,7 +91,7 @@ func (*execStop) Killable() bool { return true }
|
||||
//
|
||||
// Preconditions: The caller must be running Task.doSyscallInvoke on the task
|
||||
// goroutine.
|
||||
func (t *Task) Execve(newImage *TaskImage, argv, env []string, executable fsbridge.File, pathname string) (*SyscallControl, error) {
|
||||
func (t *Task) Execve(newImage *TaskImage, argv, env []string, executable *vfs.FileDescription, pathname string) (*SyscallControl, error) {
|
||||
// We can't clearly hold kernel package locks while stat'ing executable.
|
||||
if seccheck.Global.Enabled(seccheck.PointExecve) {
|
||||
mask, info := getExecveSeccheckInfo(t, argv, env, executable, pathname)
|
||||
@@ -303,7 +302,7 @@ func (t *Task) promoteLocked() {
|
||||
oldLeader.exitNotifyLocked(false)
|
||||
}
|
||||
|
||||
func getExecveSeccheckInfo(t *Task, argv, env []string, executable fsbridge.File, pathname string) (seccheck.FieldSet, *pb.ExecveInfo) {
|
||||
func getExecveSeccheckInfo(t *Task, argv, env []string, executable *vfs.FileDescription, pathname string) (seccheck.FieldSet, *pb.ExecveInfo) {
|
||||
fields := seccheck.Global.GetFieldSet(seccheck.PointExecve)
|
||||
info := &pb.ExecveInfo{
|
||||
Argv: argv,
|
||||
@@ -311,21 +310,19 @@ func getExecveSeccheckInfo(t *Task, argv, env []string, executable fsbridge.File
|
||||
}
|
||||
if executable != nil {
|
||||
info.BinaryPath = pathname
|
||||
if vfs2bridgeFile, ok := executable.(*fsbridge.VFSFile); ok {
|
||||
if fields.Local.Contains(seccheck.FieldSentryExecveBinaryInfo) {
|
||||
statOpts := vfs.StatOptions{
|
||||
Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID,
|
||||
if fields.Local.Contains(seccheck.FieldSentryExecveBinaryInfo) {
|
||||
statOpts := vfs.StatOptions{
|
||||
Mask: linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID,
|
||||
}
|
||||
if stat, err := executable.Stat(t, statOpts); err == nil {
|
||||
if stat.Mask&(linux.STATX_TYPE|linux.STATX_MODE) == (linux.STATX_TYPE | linux.STATX_MODE) {
|
||||
info.BinaryMode = uint32(stat.Mode)
|
||||
}
|
||||
if stat, err := vfs2bridgeFile.FileDescription().Stat(t, statOpts); err == nil {
|
||||
if stat.Mask&(linux.STATX_TYPE|linux.STATX_MODE) == (linux.STATX_TYPE | linux.STATX_MODE) {
|
||||
info.BinaryMode = uint32(stat.Mode)
|
||||
}
|
||||
if stat.Mask&linux.STATX_UID != 0 {
|
||||
info.BinaryUid = stat.UID
|
||||
}
|
||||
if stat.Mask&linux.STATX_GID != 0 {
|
||||
info.BinaryGid = stat.GID
|
||||
}
|
||||
if stat.Mask&linux.STATX_UID != 0 {
|
||||
info.BinaryUid = stat.UID
|
||||
}
|
||||
if stat.Mask&linux.STATX_GID != 0 {
|
||||
info.BinaryGid = stat.GID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +253,6 @@ func (t *Task) traceExecEvent(image *TaskImage) {
|
||||
|
||||
// traceExecEvent function may be called before the task goroutine
|
||||
// starts, so we must use the async context.
|
||||
name := file.PathnameWithDeleted(t.AsyncContext())
|
||||
name := file.MappedName(t.AsyncContext())
|
||||
trace.Logf(t.traceContext, traceCategory, "exec: %s", name)
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ go_library(
|
||||
"//pkg/context",
|
||||
"//pkg/cpuid",
|
||||
"//pkg/errors/linuxerr",
|
||||
"//pkg/fspath",
|
||||
"//pkg/hostarch",
|
||||
"//pkg/log",
|
||||
"//pkg/rand",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/limits",
|
||||
"//pkg/sentry/loader/vdsodata",
|
||||
|
||||
+12
-12
@@ -28,10 +28,10 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/limits"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/mm"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
@@ -238,7 +238,7 @@ func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) {
|
||||
|
||||
// mapSegment maps a phdr into the Task. offset is the offset to apply to
|
||||
// phdr.Vaddr.
|
||||
func mapSegment(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, phdr *elf.ProgHeader, offset hostarch.Addr) error {
|
||||
func mapSegment(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, phdr *elf.ProgHeader, offset hostarch.Addr) error {
|
||||
// We must make a page-aligned mapping.
|
||||
adjust := hostarch.Addr(phdr.Vaddr).PageOffset()
|
||||
|
||||
@@ -286,7 +286,7 @@ func mapSegment(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, phdr
|
||||
mopts.MappingIdentity.DecRef(ctx)
|
||||
}
|
||||
}()
|
||||
if err := f.ConfigureMMap(ctx, &mopts); err != nil {
|
||||
if err := fd.ConfigureMMap(ctx, &mopts); err != nil {
|
||||
ctx.Infof("File is not memory-mappable: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -405,7 +405,7 @@ type loadedELF struct {
|
||||
// It does not load the ELF interpreter, or return any auxv entries.
|
||||
//
|
||||
// Preconditions: f is an ELF file.
|
||||
func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, info elfInfo, sharedLoadOffset hostarch.Addr) (loadedELF, error) {
|
||||
func loadParsedELF(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, info elfInfo, sharedLoadOffset hostarch.Addr) (loadedELF, error) {
|
||||
first := true
|
||||
var start, end hostarch.Addr
|
||||
var interpreter string
|
||||
@@ -445,7 +445,7 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, in
|
||||
}
|
||||
|
||||
path := make([]byte, phdr.Filesz)
|
||||
_, err := f.ReadFull(ctx, usermem.BytesIOSequence(path), int64(phdr.Off))
|
||||
_, err := fd.ReadFull(ctx, usermem.BytesIOSequence(path), int64(phdr.Off))
|
||||
if err != nil {
|
||||
// If an interpreter was specified, it should exist.
|
||||
ctx.Infof("Error reading PT_INTERP path: %v", err)
|
||||
@@ -542,7 +542,7 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, in
|
||||
continue
|
||||
}
|
||||
|
||||
if err := mapSegment(ctx, m, f, &phdr, offset); err != nil {
|
||||
if err := mapSegment(ctx, m, fd, &phdr, offset); err != nil {
|
||||
ctx.Infof("Failed to map PT_LOAD segment: %+v", phdr)
|
||||
return loadedELF{}, err
|
||||
}
|
||||
@@ -580,8 +580,8 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, in
|
||||
// Preconditions:
|
||||
// - f is an ELF file.
|
||||
// - f is the first ELF loaded into m.
|
||||
func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSet, f fsbridge.File) (loadedELF, *arch.Context64, error) {
|
||||
info, err := parseHeader(ctx, f)
|
||||
func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSet, fd *vfs.FileDescription) (loadedELF, *arch.Context64, error) {
|
||||
info, err := parseHeader(ctx, fd)
|
||||
if err != nil {
|
||||
ctx.Infof("Failed to parse initial ELF: %v", err)
|
||||
return loadedELF{}, nil, err
|
||||
@@ -606,7 +606,7 @@ func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSe
|
||||
// PIELoadAddress tries to move the ELF out of the way of the default
|
||||
// mmap base to ensure that the initial brk has sufficient space to
|
||||
// grow.
|
||||
le, err := loadParsedELF(ctx, m, f, info, ac.PIELoadAddress(l))
|
||||
le, err := loadParsedELF(ctx, m, fd, info, ac.PIELoadAddress(l))
|
||||
return le, ac, err
|
||||
}
|
||||
|
||||
@@ -617,8 +617,8 @@ func loadInitialELF(ctx context.Context, m *mm.MemoryManager, fs cpuid.FeatureSe
|
||||
// It does not return any auxv entries.
|
||||
//
|
||||
// Preconditions: f is an ELF file.
|
||||
func loadInterpreterELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.File, initial loadedELF) (loadedELF, error) {
|
||||
info, err := parseHeader(ctx, f)
|
||||
func loadInterpreterELF(ctx context.Context, m *mm.MemoryManager, fd *vfs.FileDescription, initial loadedELF) (loadedELF, error) {
|
||||
info, err := parseHeader(ctx, fd)
|
||||
if err != nil {
|
||||
if linuxerr.Equals(linuxerr.ENOEXEC, err) {
|
||||
// Bad interpreter.
|
||||
@@ -638,7 +638,7 @@ func loadInterpreterELF(ctx context.Context, m *mm.MemoryManager, f fsbridge.Fil
|
||||
|
||||
// The interpreter is not given a load offset, as its location does not
|
||||
// affect brk.
|
||||
return loadParsedELF(ctx, m, f, info, 0)
|
||||
return loadParsedELF(ctx, m, fd, info, 0)
|
||||
}
|
||||
|
||||
// loadELF loads args.File into the Task address space.
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
@@ -37,9 +37,9 @@ const (
|
||||
)
|
||||
|
||||
// parseInterpreterScript returns the interpreter path and argv.
|
||||
func parseInterpreterScript(ctx context.Context, filename string, f fsbridge.File, argv []string) (newpath string, newargv []string, err error) {
|
||||
func parseInterpreterScript(ctx context.Context, filename string, fd *vfs.FileDescription, argv []string) (newpath string, newargv []string, err error) {
|
||||
line := make([]byte, interpMaxLineLength)
|
||||
n, err := f.ReadFull(ctx, usermem.BytesIOSequence(line), 0)
|
||||
n, err := fd.ReadFull(ctx, usermem.BytesIOSequence(line), 0)
|
||||
// Short read is OK.
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
if err == io.EOF {
|
||||
|
||||
+31
-16
@@ -27,10 +27,10 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/cpuid"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/fspath"
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/rand"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/mm"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
@@ -55,18 +55,21 @@ type LoadArgs struct {
|
||||
// Filename is the path for the executable.
|
||||
Filename string
|
||||
|
||||
// File is an open fs.File object of the executable. If File is not
|
||||
// nil, then File will be loaded and Filename will be ignored.
|
||||
// File is an open FD of the executable. If File is not nil, then File will
|
||||
// be loaded and Filename will be ignored.
|
||||
//
|
||||
// The caller is responsible for checking that the user can execute this file.
|
||||
File fsbridge.File
|
||||
File *vfs.FileDescription
|
||||
|
||||
// Opener is used to open the executable file when 'File' is nil.
|
||||
Opener fsbridge.Lookup
|
||||
// Root is the current filesystem root.
|
||||
Root vfs.VirtualDentry
|
||||
|
||||
// WorkingDir is the current working directory.
|
||||
WorkingDir vfs.VirtualDentry
|
||||
|
||||
// If AfterOpen is not nil, it is called after every successful call to
|
||||
// Opener.OpenPath().
|
||||
AfterOpen func(f fsbridge.File)
|
||||
AfterOpen func(f *vfs.FileDescription)
|
||||
|
||||
// CloseOnExec indicates that the executable (or one of its parent
|
||||
// directories) was opened with O_CLOEXEC. If the executable is an
|
||||
@@ -91,7 +94,7 @@ type LoadArgs struct {
|
||||
// installed in the Task FDTable. The caller takes ownership of both.
|
||||
//
|
||||
// args.Filename must be a readable, executable, regular file.
|
||||
func openPath(ctx context.Context, args LoadArgs) (fsbridge.File, error) {
|
||||
func openPath(ctx context.Context, args LoadArgs) (*vfs.FileDescription, error) {
|
||||
if args.Filename == "" {
|
||||
ctx.Infof("cannot open empty name")
|
||||
return nil, linuxerr.ENOENT
|
||||
@@ -106,23 +109,35 @@ func openPath(ctx context.Context, args LoadArgs) (fsbridge.File, error) {
|
||||
Flags: linux.O_RDONLY,
|
||||
FileExec: true,
|
||||
}
|
||||
f, err := args.Opener.OpenPath(ctx, args.Filename, opts, args.RemainingTraversals, args.ResolveFinal)
|
||||
vfsObj := args.Root.Mount().Filesystem().VirtualFilesystem()
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
path := fspath.Parse(args.Filename)
|
||||
pop := &vfs.PathOperation{
|
||||
Root: args.Root,
|
||||
Start: args.WorkingDir,
|
||||
Path: path,
|
||||
FollowFinalSymlink: args.ResolveFinal,
|
||||
}
|
||||
if path.Absolute {
|
||||
pop.Start = args.Root
|
||||
}
|
||||
fd, err := vfsObj.OpenAt(ctx, creds, pop, &opts)
|
||||
if err != nil {
|
||||
return f, err
|
||||
return nil, err
|
||||
}
|
||||
if args.AfterOpen != nil {
|
||||
args.AfterOpen(f)
|
||||
args.AfterOpen(fd)
|
||||
}
|
||||
return f, nil
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// checkIsRegularFile prevents us from trying to execute a directory, pipe, etc.
|
||||
func checkIsRegularFile(ctx context.Context, file fsbridge.File, filename string) error {
|
||||
t, err := file.Type(ctx)
|
||||
func checkIsRegularFile(ctx context.Context, fd *vfs.FileDescription, filename string) error {
|
||||
stat, err := fd.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t != linux.ModeRegular {
|
||||
if t := linux.FileMode(stat.Mode).FileType(); t != linux.ModeRegular {
|
||||
ctx.Infof("%q is not a regular file: %v", filename, t)
|
||||
return linuxerr.EACCES
|
||||
}
|
||||
@@ -157,7 +172,7 @@ const (
|
||||
// - arch.Context64 matching the binary arch
|
||||
// - fs.Dirent of the binary file
|
||||
// - Possibly updated args.Argv
|
||||
func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, *arch.Context64, fsbridge.File, []string, error) {
|
||||
func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, *arch.Context64, *vfs.FileDescription, []string, error) {
|
||||
for i := 0; i < maxLoaderAttempts; i++ {
|
||||
if args.File == nil {
|
||||
var err error
|
||||
|
||||
+1
-1
@@ -182,7 +182,6 @@ go_library(
|
||||
"//pkg/safecopy",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/futex",
|
||||
"//pkg/sentry/kernel/shm",
|
||||
@@ -191,6 +190,7 @@ go_library(
|
||||
"//pkg/sentry/pgalloc",
|
||||
"//pkg/sentry/platform",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sync",
|
||||
"//pkg/sync/locking",
|
||||
"//pkg/usermem",
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
// Dumpability describes if and how core dumps should be created.
|
||||
@@ -129,7 +129,7 @@ func (mm *MemoryManager) SetAuxv(auxv arch.Auxv) {
|
||||
//
|
||||
// An additional reference will be taken in the case of a non-nil executable,
|
||||
// which must be released by the caller.
|
||||
func (mm *MemoryManager) Executable() fsbridge.File {
|
||||
func (mm *MemoryManager) Executable() *vfs.FileDescription {
|
||||
mm.metadataMu.Lock()
|
||||
defer mm.metadataMu.Unlock()
|
||||
|
||||
@@ -144,15 +144,15 @@ func (mm *MemoryManager) Executable() fsbridge.File {
|
||||
// SetExecutable sets the executable.
|
||||
//
|
||||
// This takes a reference on d.
|
||||
func (mm *MemoryManager) SetExecutable(ctx context.Context, file fsbridge.File) {
|
||||
func (mm *MemoryManager) SetExecutable(ctx context.Context, fd *vfs.FileDescription) {
|
||||
mm.metadataMu.Lock()
|
||||
|
||||
// Grab a new reference.
|
||||
file.IncRef()
|
||||
fd.IncRef()
|
||||
|
||||
// Set the executable.
|
||||
orig := mm.executable
|
||||
mm.executable = file
|
||||
mm.executable = fd
|
||||
|
||||
mm.metadataMu.Unlock()
|
||||
|
||||
|
||||
+2
-2
@@ -44,10 +44,10 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/safemem"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/pgalloc"
|
||||
"gvisor.dev/gvisor/pkg/sentry/platform"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
// MapsCallbackFunc has all the parameters required for populating an entry of /proc/[pid]/maps.
|
||||
@@ -226,7 +226,7 @@ type MemoryManager struct {
|
||||
// is not nil, it holds a reference on the Dirent.
|
||||
//
|
||||
// executable is protected by metadataMu.
|
||||
executable fsbridge.File
|
||||
executable *vfs.FileDescription
|
||||
|
||||
// aioManager keeps track of AIOContexts used for async IOs. AIOManager
|
||||
// must be cloned when CLONE_VM is used.
|
||||
|
||||
@@ -79,7 +79,6 @@ go_library(
|
||||
"//pkg/rand",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsbridge",
|
||||
"//pkg/sentry/fsimpl/eventfd",
|
||||
"//pkg/sentry/fsimpl/host",
|
||||
"//pkg/sentry/fsimpl/iouringfs",
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsbridge"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/mm"
|
||||
@@ -141,7 +140,7 @@ func Prctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
}
|
||||
|
||||
// Set the underlying executable.
|
||||
t.MemoryManager().SetExecutable(t, fsbridge.NewVFSFile(file))
|
||||
t.MemoryManager().SetExecutable(t, file)
|
||||
|
||||
case linux.PR_SET_MM_AUXV,
|
||||
linux.PR_SET_MM_START_CODE,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user