mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix panic when calling dup2().
PiperOrigin-RevId: 329572337
This commit is contained in:
committed by
gVisor bot
parent
723fb5c116
commit
04c284f8c2
@@ -112,7 +112,7 @@ func (f *FDTable) loadDescriptorTable(m map[int32]descriptor) {
|
||||
ctx := context.Background()
|
||||
f.init() // Initialize table.
|
||||
for fd, d := range m {
|
||||
f.setAll(fd, d.file, d.fileVFS2, d.flags)
|
||||
f.setAll(ctx, fd, d.file, d.fileVFS2, d.flags)
|
||||
|
||||
// Note that we do _not_ need to acquire a extra table reference here. The
|
||||
// table reference will already be accounted for in the file, so we drop the
|
||||
@@ -127,7 +127,7 @@ func (f *FDTable) loadDescriptorTable(m map[int32]descriptor) {
|
||||
}
|
||||
|
||||
// drop drops the table reference.
|
||||
func (f *FDTable) drop(file *fs.File) {
|
||||
func (f *FDTable) drop(ctx context.Context, file *fs.File) {
|
||||
// Release locks.
|
||||
file.Dirent.Inode.LockCtx.Posix.UnlockRegion(f, lock.LockRange{0, lock.LockEOF})
|
||||
|
||||
@@ -145,14 +145,13 @@ func (f *FDTable) drop(file *fs.File) {
|
||||
d.InotifyEvent(ev, 0)
|
||||
|
||||
// Drop the table reference.
|
||||
file.DecRef(context.Background())
|
||||
file.DecRef(ctx)
|
||||
}
|
||||
|
||||
// dropVFS2 drops the table reference.
|
||||
func (f *FDTable) dropVFS2(file *vfs.FileDescription) {
|
||||
func (f *FDTable) dropVFS2(ctx context.Context, file *vfs.FileDescription) {
|
||||
// Release any POSIX lock possibly held by the FDTable. Range {0, 0} means the
|
||||
// entire file.
|
||||
ctx := context.Background()
|
||||
err := file.UnlockPOSIX(ctx, f, 0, 0, linux.SEEK_SET)
|
||||
if err != nil && err != syserror.ENOLCK {
|
||||
panic(fmt.Sprintf("UnlockPOSIX failed: %v", err))
|
||||
@@ -289,15 +288,15 @@ func (f *FDTable) NewFDs(ctx context.Context, fd int32, files []*fs.File, flags
|
||||
// Install all entries.
|
||||
for i := fd; i < end && len(fds) < len(files); i++ {
|
||||
if d, _, _ := f.get(i); d == nil {
|
||||
f.set(i, files[len(fds)], flags) // Set the descriptor.
|
||||
fds = append(fds, i) // Record the file descriptor.
|
||||
f.set(ctx, i, files[len(fds)], flags) // Set the descriptor.
|
||||
fds = append(fds, i) // Record the file descriptor.
|
||||
}
|
||||
}
|
||||
|
||||
// Failure? Unwind existing FDs.
|
||||
if len(fds) < len(files) {
|
||||
for _, i := range fds {
|
||||
f.set(i, nil, FDFlags{}) // Zap entry.
|
||||
f.set(ctx, i, nil, FDFlags{}) // Zap entry.
|
||||
}
|
||||
return nil, syscall.EMFILE
|
||||
}
|
||||
@@ -344,15 +343,15 @@ func (f *FDTable) NewFDsVFS2(ctx context.Context, fd int32, files []*vfs.FileDes
|
||||
// Install all entries.
|
||||
for i := fd; i < end && len(fds) < len(files); i++ {
|
||||
if d, _, _ := f.getVFS2(i); d == nil {
|
||||
f.setVFS2(i, files[len(fds)], flags) // Set the descriptor.
|
||||
fds = append(fds, i) // Record the file descriptor.
|
||||
f.setVFS2(ctx, i, files[len(fds)], flags) // Set the descriptor.
|
||||
fds = append(fds, i) // Record the file descriptor.
|
||||
}
|
||||
}
|
||||
|
||||
// Failure? Unwind existing FDs.
|
||||
if len(fds) < len(files) {
|
||||
for _, i := range fds {
|
||||
f.setVFS2(i, nil, FDFlags{}) // Zap entry.
|
||||
f.setVFS2(ctx, i, nil, FDFlags{}) // Zap entry.
|
||||
}
|
||||
return nil, syscall.EMFILE
|
||||
}
|
||||
@@ -397,7 +396,7 @@ func (f *FDTable) NewFDVFS2(ctx context.Context, minfd int32, file *vfs.FileDesc
|
||||
}
|
||||
for fd < end {
|
||||
if d, _, _ := f.getVFS2(fd); d == nil {
|
||||
f.setVFS2(fd, file, flags)
|
||||
f.setVFS2(ctx, fd, file, flags)
|
||||
if fd == f.next {
|
||||
// Update next search start position.
|
||||
f.next = fd + 1
|
||||
@@ -439,14 +438,14 @@ func (f *FDTable) newFDAt(ctx context.Context, fd int32, file *fs.File, fileVFS2
|
||||
// Install the entry.
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.setAll(fd, file, fileVFS2, flags)
|
||||
f.setAll(ctx, fd, file, fileVFS2, flags)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFlags sets the flags for the given file descriptor.
|
||||
//
|
||||
// True is returned iff flags were changed.
|
||||
func (f *FDTable) SetFlags(fd int32, flags FDFlags) error {
|
||||
func (f *FDTable) SetFlags(ctx context.Context, fd int32, flags FDFlags) error {
|
||||
if fd < 0 {
|
||||
// Don't accept negative FDs.
|
||||
return syscall.EBADF
|
||||
@@ -462,14 +461,14 @@ func (f *FDTable) SetFlags(fd int32, flags FDFlags) error {
|
||||
}
|
||||
|
||||
// Update the flags.
|
||||
f.set(fd, file, flags)
|
||||
f.set(ctx, fd, file, flags)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFlagsVFS2 sets the flags for the given file descriptor.
|
||||
//
|
||||
// True is returned iff flags were changed.
|
||||
func (f *FDTable) SetFlagsVFS2(fd int32, flags FDFlags) error {
|
||||
func (f *FDTable) SetFlagsVFS2(ctx context.Context, fd int32, flags FDFlags) error {
|
||||
if fd < 0 {
|
||||
// Don't accept negative FDs.
|
||||
return syscall.EBADF
|
||||
@@ -485,7 +484,7 @@ func (f *FDTable) SetFlagsVFS2(fd int32, flags FDFlags) error {
|
||||
}
|
||||
|
||||
// Update the flags.
|
||||
f.setVFS2(fd, file, flags)
|
||||
f.setVFS2(ctx, fd, file, flags)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -584,9 +583,9 @@ func (f *FDTable) Fork(ctx context.Context) *FDTable {
|
||||
// reference for the clone. We don't need anything else.
|
||||
switch {
|
||||
case file != nil:
|
||||
clone.set(fd, file, flags)
|
||||
clone.set(ctx, fd, file, flags)
|
||||
case fileVFS2 != nil:
|
||||
clone.setVFS2(fd, fileVFS2, flags)
|
||||
clone.setVFS2(ctx, fd, fileVFS2, flags)
|
||||
}
|
||||
})
|
||||
return clone
|
||||
@@ -595,7 +594,7 @@ func (f *FDTable) Fork(ctx context.Context) *FDTable {
|
||||
// Remove removes an FD from and returns a non-file iff successful.
|
||||
//
|
||||
// N.B. Callers are required to use DecRef when they are done.
|
||||
func (f *FDTable) Remove(fd int32) (*fs.File, *vfs.FileDescription) {
|
||||
func (f *FDTable) Remove(ctx context.Context, fd int32) (*fs.File, *vfs.FileDescription) {
|
||||
if fd < 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -618,7 +617,7 @@ func (f *FDTable) Remove(fd int32) (*fs.File, *vfs.FileDescription) {
|
||||
orig2.IncRef()
|
||||
}
|
||||
if orig != nil || orig2 != nil {
|
||||
f.setAll(fd, nil, nil, FDFlags{}) // Zap entry.
|
||||
f.setAll(ctx, fd, nil, nil, FDFlags{}) // Zap entry.
|
||||
}
|
||||
return orig, orig2
|
||||
}
|
||||
@@ -630,7 +629,7 @@ func (f *FDTable) RemoveIf(ctx context.Context, cond func(*fs.File, *vfs.FileDes
|
||||
|
||||
f.forEach(ctx, func(fd int32, file *fs.File, fileVFS2 *vfs.FileDescription, flags FDFlags) {
|
||||
if cond(file, fileVFS2, flags) {
|
||||
f.set(fd, nil, FDFlags{}) // Clear from table.
|
||||
f.set(ctx, fd, nil, FDFlags{}) // Clear from table.
|
||||
// Update current available position.
|
||||
if fd < f.next {
|
||||
f.next = fd
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestFDTableMany(t *testing.T) {
|
||||
}
|
||||
|
||||
i := int32(2)
|
||||
fdTable.Remove(i)
|
||||
fdTable.Remove(ctx, i)
|
||||
if fds, err := fdTable.NewFDs(ctx, 0, []*fs.File{file}, FDFlags{}); err != nil || fds[0] != i {
|
||||
t.Fatalf("Allocated %v FDs but wanted to allocate %v: %v", i, maxFD, err)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ func TestFDTableOverLimit(t *testing.T) {
|
||||
t.Fatalf("fdTable.NewFDs(maxFD-3, {f,f,f}): got %v, wanted nil", err)
|
||||
} else {
|
||||
for _, fd := range fds {
|
||||
fdTable.Remove(fd)
|
||||
fdTable.Remove(ctx, fd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,13 +150,13 @@ func TestFDTable(t *testing.T) {
|
||||
t.Fatalf("fdTable.Get(2): got a %v, wanted nil", ref)
|
||||
}
|
||||
|
||||
ref, _ := fdTable.Remove(1)
|
||||
ref, _ := fdTable.Remove(ctx, 1)
|
||||
if ref == nil {
|
||||
t.Fatalf("fdTable.Remove(1) for an existing FD: failed, want success")
|
||||
}
|
||||
ref.DecRef(ctx)
|
||||
|
||||
if ref, _ := fdTable.Remove(1); ref != nil {
|
||||
if ref, _ := fdTable.Remove(ctx, 1); ref != nil {
|
||||
t.Fatalf("r.Remove(1) for a removed FD: got success, want failure")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
@@ -84,8 +85,8 @@ func (f *FDTable) getAll(fd int32) (*fs.File, *vfs.FileDescription, FDFlags, boo
|
||||
// reference needed by the table iff the file is different.
|
||||
//
|
||||
// Precondition: mu must be held.
|
||||
func (f *FDTable) set(fd int32, file *fs.File, flags FDFlags) {
|
||||
f.setAll(fd, file, nil, flags)
|
||||
func (f *FDTable) set(ctx context.Context, fd int32, file *fs.File, flags FDFlags) {
|
||||
f.setAll(ctx, fd, file, nil, flags)
|
||||
}
|
||||
|
||||
// setVFS2 sets an entry.
|
||||
@@ -94,8 +95,8 @@ func (f *FDTable) set(fd int32, file *fs.File, flags FDFlags) {
|
||||
// reference needed by the table iff the file is different.
|
||||
//
|
||||
// Precondition: mu must be held.
|
||||
func (f *FDTable) setVFS2(fd int32, file *vfs.FileDescription, flags FDFlags) {
|
||||
f.setAll(fd, nil, file, flags)
|
||||
func (f *FDTable) setVFS2(ctx context.Context, fd int32, file *vfs.FileDescription, flags FDFlags) {
|
||||
f.setAll(ctx, fd, nil, file, flags)
|
||||
}
|
||||
|
||||
// setAll sets an entry.
|
||||
@@ -104,7 +105,7 @@ func (f *FDTable) setVFS2(fd int32, file *vfs.FileDescription, flags FDFlags) {
|
||||
// reference needed by the table iff the file is different.
|
||||
//
|
||||
// Precondition: mu must be held.
|
||||
func (f *FDTable) setAll(fd int32, file *fs.File, fileVFS2 *vfs.FileDescription, flags FDFlags) {
|
||||
func (f *FDTable) setAll(ctx context.Context, fd int32, file *fs.File, fileVFS2 *vfs.FileDescription, flags FDFlags) {
|
||||
if file != nil && fileVFS2 != nil {
|
||||
panic("VFS1 and VFS2 files set")
|
||||
}
|
||||
@@ -152,11 +153,11 @@ func (f *FDTable) setAll(fd int32, file *fs.File, fileVFS2 *vfs.FileDescription,
|
||||
switch {
|
||||
case orig.file != nil:
|
||||
if desc == nil || desc.file != orig.file {
|
||||
f.drop(orig.file)
|
||||
f.drop(ctx, orig.file)
|
||||
}
|
||||
case orig.fileVFS2 != nil:
|
||||
if desc == nil || desc.fileVFS2 != orig.fileVFS2 {
|
||||
f.dropVFS2(orig.fileVFS2)
|
||||
f.dropVFS2(ctx, orig.fileVFS2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,12 +601,12 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
// Shared flags between file and socket.
|
||||
switch request {
|
||||
case linux.FIONCLEX:
|
||||
t.FDTable().SetFlags(fd, kernel.FDFlags{
|
||||
t.FDTable().SetFlags(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: false,
|
||||
})
|
||||
return 0, nil, nil
|
||||
case linux.FIOCLEX:
|
||||
t.FDTable().SetFlags(fd, kernel.FDFlags{
|
||||
t.FDTable().SetFlags(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: true,
|
||||
})
|
||||
return 0, nil, nil
|
||||
@@ -787,7 +787,7 @@ func Close(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
// Note that Remove provides a reference on the file that we may use to
|
||||
// flush. It is still active until we drop the final reference below
|
||||
// (and other reference-holding operations complete).
|
||||
file, _ := t.FDTable().Remove(fd)
|
||||
file, _ := t.FDTable().Remove(t, fd)
|
||||
if file == nil {
|
||||
return 0, nil, syserror.EBADF
|
||||
}
|
||||
@@ -941,7 +941,7 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
return uintptr(flags.ToLinuxFDFlags()), nil, nil
|
||||
case linux.F_SETFD:
|
||||
flags := args[2].Uint()
|
||||
err := t.FDTable().SetFlags(fd, kernel.FDFlags{
|
||||
err := t.FDTable().SetFlags(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: flags&linux.FD_CLOEXEC != 0,
|
||||
})
|
||||
return 0, nil, err
|
||||
@@ -1154,6 +1154,10 @@ func Fadvise64(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
// LINT.ThenChange(vfs2/fd.go)
|
||||
|
||||
// LINT.IfChange
|
||||
|
||||
func mkdirAt(t *kernel.Task, dirFD int32, addr usermem.Addr, mode linux.FileMode) error {
|
||||
path, _, err := copyInPath(t, addr, false /* allowEmpty */)
|
||||
if err != nil {
|
||||
|
||||
@@ -48,7 +48,7 @@ func pipe2(t *kernel.Task, addr usermem.Addr, flags uint) (uintptr, error) {
|
||||
|
||||
if _, err := t.CopyOut(addr, fds); err != nil {
|
||||
for _, fd := range fds {
|
||||
if file, _ := t.FDTable().Remove(fd); file != nil {
|
||||
if file, _ := t.FDTable().Remove(t, fd); file != nil {
|
||||
file.DecRef(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ func SocketPair(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy
|
||||
// Copy the file descriptors out.
|
||||
if _, err := t.CopyOut(socks, fds); err != nil {
|
||||
for _, fd := range fds {
|
||||
if file, _ := t.FDTable().Remove(fd); file != nil {
|
||||
if file, _ := t.FDTable().Remove(t, fd); file != nil {
|
||||
file.DecRef(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func Close(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
// Note that Remove provides a reference on the file that we may use to
|
||||
// flush. It is still active until we drop the final reference below
|
||||
// (and other reference-holding operations complete).
|
||||
_, file := t.FDTable().Remove(fd)
|
||||
_, file := t.FDTable().Remove(t, fd)
|
||||
if file == nil {
|
||||
return 0, nil, syserror.EBADF
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
return uintptr(flags.ToLinuxFDFlags()), nil, nil
|
||||
case linux.F_SETFD:
|
||||
flags := args[2].Uint()
|
||||
err := t.FDTable().SetFlagsVFS2(fd, kernel.FDFlags{
|
||||
err := t.FDTable().SetFlagsVFS2(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: flags&linux.FD_CLOEXEC != 0,
|
||||
})
|
||||
return 0, nil, err
|
||||
|
||||
@@ -34,13 +34,13 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
// Handle ioctls that apply to all FDs.
|
||||
switch args[1].Int() {
|
||||
case linux.FIONCLEX:
|
||||
t.FDTable().SetFlagsVFS2(fd, kernel.FDFlags{
|
||||
t.FDTable().SetFlagsVFS2(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: false,
|
||||
})
|
||||
return 0, nil, nil
|
||||
|
||||
case linux.FIOCLEX:
|
||||
t.FDTable().SetFlagsVFS2(fd, kernel.FDFlags{
|
||||
t.FDTable().SetFlagsVFS2(t, fd, kernel.FDFlags{
|
||||
CloseOnExec: true,
|
||||
})
|
||||
return 0, nil, nil
|
||||
|
||||
@@ -53,7 +53,7 @@ func pipe2(t *kernel.Task, addr usermem.Addr, flags int32) error {
|
||||
}
|
||||
if _, err := t.CopyOut(addr, fds); err != nil {
|
||||
for _, fd := range fds {
|
||||
if _, file := t.FDTable().Remove(fd); file != nil {
|
||||
if _, file := t.FDTable().Remove(t, fd); file != nil {
|
||||
file.DecRef(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ func SocketPair(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy
|
||||
|
||||
if _, err := t.CopyOut(addr, fds); err != nil {
|
||||
for _, fd := range fds {
|
||||
if _, file := t.FDTable().Remove(fd); file != nil {
|
||||
if _, file := t.FDTable().Remove(t, fd); file != nil {
|
||||
file.DecRef(t)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user