diff options
author | Christopher Koch <chrisko@google.com> | 2019-02-08 10:50:14 -0800 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-02-08 10:51:24 -0800 |
commit | 5079b38a9af1d66ad720005d7487dd711a0cb713 (patch) | |
tree | 8aa1bcf46e69ac8ab5875acdad16f30422e341a2 /pkg | |
parent | 80f901b16b8bb8fe397cc44578035173f5155b24 (diff) |
Keep FilePayloads open on server side until after RPC completed.
Prevents URPC FDs from being closed mid-call, especially if they
are used as raw FDs.
PiperOrigin-RevId: 233087955
Change-Id: I815a2ff32cc5f03774605aef0b35a32862f8e633
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/fd/fd.go | 3 | ||||
-rw-r--r-- | pkg/urpc/BUILD | 1 | ||||
-rw-r--r-- | pkg/urpc/urpc.go | 12 |
3 files changed, 16 insertions, 0 deletions
diff --git a/pkg/fd/fd.go b/pkg/fd/fd.go index f6656ffa1..a2edf2aa6 100644 --- a/pkg/fd/fd.go +++ b/pkg/fd/fd.go @@ -158,6 +158,9 @@ func New(fd int) *FD { // The returned FD is always blocking (Go 1.9+). func NewFromFile(file *os.File) (*FD, error) { fd, err := syscall.Dup(int(file.Fd())) + // Technically, the runtime may call the finalizer on file as soon as + // Fd() returns. + runtime.KeepAlive(file) if err != nil { return &FD{ReadWriter{-1}}, err } diff --git a/pkg/urpc/BUILD b/pkg/urpc/BUILD index 36cae67e1..0192fb35b 100644 --- a/pkg/urpc/BUILD +++ b/pkg/urpc/BUILD @@ -8,6 +8,7 @@ go_library( importpath = "gvisor.googlesource.com/gvisor/pkg/urpc", visibility = ["//:sandbox"], deps = [ + "//pkg/fd", "//pkg/log", "//pkg/unet", ], diff --git a/pkg/urpc/urpc.go b/pkg/urpc/urpc.go index 753366be2..6d528b180 100644 --- a/pkg/urpc/urpc.go +++ b/pkg/urpc/urpc.go @@ -29,6 +29,7 @@ import ( "runtime" "sync" + "gvisor.googlesource.com/gvisor/pkg/fd" "gvisor.googlesource.com/gvisor/pkg/log" "gvisor.googlesource.com/gvisor/pkg/unet" ) @@ -71,6 +72,11 @@ type FilePayload struct { Files []*os.File `json:"-"` } +// ReleaseFD releases the indexth FD. +func (f *FilePayload) ReleaseFD(index int) (*fd.FD, error) { + return fd.NewFromFile(f.Files[index]) +} + // filePayload returns the file. It may be nil. func (f *FilePayload) filePayload() []*os.File { return f.Files @@ -268,6 +274,12 @@ func (s *Server) handleOne(client *unet.Socket) error { return err } + // Explicitly close all these files after the call. + // + // This is also explicitly a reference to the files after the call, + // which means they are kept open for the duration of the call. + defer closeAll(newFs) + // Start the request. if !s.clientBeginRequest(client) { // Client is dead; don't process this call. |