Files
Ayush Ranjan ed9678b679 Delete pgalloc.MemoryFileProvider.
The work done in c087777e37 ("Plumb restore context to afterLoad()") makes
pgalloc.MemoryFileProvider redundant as structs can now easily restore
pgalloc.MemoryFile in stateify's afterLoad() method. This allows structs to
have a pgalloc.MemoryFile field and use that directly, instead of going through
the provided interface.

This cleans up a lot of code and also should be more performant (avoids an
interface method call on many hot paths).

PiperOrigin-RevId: 615258927
2024-03-12 20:06:58 -07:00

178 lines
5.2 KiB
Go

// Copyright 2018 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 kernel
import (
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux/errno"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/kernel/futex"
"gvisor.dev/gvisor/pkg/sentry/loader"
"gvisor.dev/gvisor/pkg/sentry/mm"
"gvisor.dev/gvisor/pkg/syserr"
)
var errNoSyscalls = syserr.New("no syscall table found", errno.ENOEXEC)
// Auxmap contains miscellaneous data for the task.
type Auxmap map[string]any
// TaskImage is the subset of a task's data that is provided by the loader.
//
// +stateify savable
type TaskImage struct {
// Name is the thread name set by the prctl(PR_SET_NAME) system call.
Name string
// Arch is the architecture-specific context (registers, etc.)
Arch *arch.Context64
// MemoryManager is the task's address space.
MemoryManager *mm.MemoryManager
// fu implements futexes in the address space.
fu *futex.Manager
// st is the task's syscall table.
st *SyscallTable `state:".(syscallTableInfo)"`
// fileCaps is the image's extended attribute named security.capability.
fileCaps string
}
// FileCaps return the task image's security.capability extended attribute.
func (image *TaskImage) FileCaps() string {
return image.fileCaps
}
// release releases all resources held by the TaskImage. release is called by
// the task when it execs into a new TaskImage.
func (image *TaskImage) release(ctx context.Context) {
// Nil out pointers so that if the task is saved after release, it doesn't
// follow the pointers to possibly now-invalid objects.
if image.MemoryManager != nil {
image.MemoryManager.DecUsers(ctx)
image.MemoryManager = nil
}
image.fu = nil
}
// Fork returns a duplicate of image. The copied TaskImage always has an
// independent arch.Context64. If shareAddressSpace is true, the copied
// TaskImage shares an address space with the original; otherwise, the copied
// TaskImage has an independent address space that is initially a duplicate
// of the original's.
func (image *TaskImage) Fork(ctx context.Context, k *Kernel, shareAddressSpace bool) (*TaskImage, error) {
newImage := &TaskImage{
Name: image.Name,
Arch: image.Arch.Fork(),
st: image.st,
}
if shareAddressSpace {
newImage.MemoryManager = image.MemoryManager
if newImage.MemoryManager != nil {
if !newImage.MemoryManager.IncUsers() {
// Shouldn't be possible since image.MemoryManager should be a
// counted user.
panic(fmt.Sprintf("TaskImage.Fork called with userless TaskImage.MemoryManager"))
}
}
newImage.fu = image.fu
} else {
newMM, err := image.MemoryManager.Fork(ctx)
if err != nil {
return nil, err
}
newImage.MemoryManager = newMM
newImage.fu = k.futexes.Fork()
}
return newImage, nil
}
// Arch returns t's arch.Context64.
//
// Preconditions: The caller must be running on the task goroutine, or t.mu
// must be locked.
func (t *Task) Arch() *arch.Context64 {
return t.image.Arch
}
// MemoryManager returns t's MemoryManager. MemoryManager does not take an
// additional reference on the returned MM.
//
// Preconditions: The caller must be running on the task goroutine, or t.mu
// must be locked.
func (t *Task) MemoryManager() *mm.MemoryManager {
return t.image.MemoryManager
}
// SyscallTable returns t's syscall table.
//
// Preconditions: The caller must be running on the task goroutine, or t.mu
// must be locked.
func (t *Task) SyscallTable() *SyscallTable {
return t.image.st
}
// Stack returns the userspace stack.
//
// Preconditions: The caller must be running on the task goroutine, or t.mu
// must be locked.
func (t *Task) Stack() *arch.Stack {
return &arch.Stack{
Arch: t.Arch(),
IO: t.MemoryManager(),
Bottom: hostarch.Addr(t.Arch().Stack()),
}
}
// LoadTaskImage loads a specified file into a new TaskImage.
//
// args.MemoryManager does not need to be set by the caller.
func (k *Kernel) LoadTaskImage(ctx context.Context, args loader.LoadArgs) (*TaskImage, *syserr.Error) {
// Prepare a new user address space to load into.
m := mm.NewMemoryManager(k, k.mf, k.SleepForAddressSpaceActivation)
defer m.DecUsers(ctx)
args.MemoryManager = m
info, err := loader.Load(ctx, args, k.extraAuxv, k.vdso)
if err != nil {
return nil, err
}
// Lookup our new syscall table.
st, ok := LookupSyscallTable(info.OS, info.Arch.Arch())
if !ok {
// No syscall table found. This means that the ELF binary does not match
// the architecture.
return nil, errNoSyscalls
}
if !m.IncUsers() {
panic("Failed to increment users count on new MM")
}
return &TaskImage{
Name: info.Name,
Arch: info.Arch,
MemoryManager: m,
fu: k.futexes.Fork(),
st: st,
fileCaps: info.FileCaps,
}, nil
}