Fix panic when calling dup2().

PiperOrigin-RevId: 329572337
This commit is contained in:
Nayana Bidari
2020-09-01 13:41:01 -07:00
committed by gVisor bot
parent 723fb5c116
commit 04c284f8c2
10 changed files with 49 additions and 45 deletions
+21 -22
View File
@@ -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
+4 -4
View File
@@ -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")
}
})
+8 -7
View File
@@ -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)
}
}
}
+8 -4
View File
@@ -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 {
+1 -1
View File
@@ -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)
}
}
+1 -1
View File
@@ -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)
}
}
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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)
}
}
+1 -1
View File
@@ -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)
}
}