diff options
author | Googler <noreply@google.com> | 2018-04-27 10:37:02 -0700 |
---|---|---|
committer | Adin Scannell <ascannell@google.com> | 2018-04-28 01:44:26 -0400 |
commit | d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch) | |
tree | 54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/sentry/syscalls/linux/error.go | |
parent | f70210e742919f40aa2f0934a22f1c9ba6dada62 (diff) |
Check in gVisor.
PiperOrigin-RevId: 194583126
Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/sentry/syscalls/linux/error.go')
-rw-r--r-- | pkg/sentry/syscalls/linux/error.go | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/pkg/sentry/syscalls/linux/error.go b/pkg/sentry/syscalls/linux/error.go new file mode 100644 index 000000000..013b385bc --- /dev/null +++ b/pkg/sentry/syscalls/linux/error.go @@ -0,0 +1,117 @@ +// Copyright 2018 Google Inc. +// +// 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 linux + +import ( + "io" + "sync" + "syscall" + + "gvisor.googlesource.com/gvisor/pkg/log" + "gvisor.googlesource.com/gvisor/pkg/metric" + "gvisor.googlesource.com/gvisor/pkg/sentry/arch" + "gvisor.googlesource.com/gvisor/pkg/sentry/fs" + "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/syserror" +) + +var ( + partialResultMetric = metric.MustCreateNewUint64Metric("/syscalls/partial_result", true /* sync */, "Whether or not a partial result has occurred for this sandbox.") + partialResultOnce sync.Once +) + +// handleIOError handles special error cases for partial results. For some +// errors, we may consume the error and return only the partial read/write. +// +// op and f are used only for panics. +func handleIOError(t *kernel.Task, partialResult bool, err, intr error, op string, f *fs.File) error { + switch err { + case nil: + // Typical successful syscall. + return nil + case io.EOF: + // EOF is always consumed. If this is a partial read/write + // (result != 0), the application will see that, otherwise + // they will see 0. + return nil + case syserror.ErrExceedsFileSizeLimit: + // Ignore partialResult because this error only applies to + // normal files, and for those files we cannot accumulate + // write results. + // + // Do not consume the error and return it as EFBIG. + // Simultaneously send a SIGXFSZ per setrlimit(2). + t.SendSignal(&arch.SignalInfo{ + Signo: int32(syscall.SIGXFSZ), + Code: arch.SignalInfoKernel, + }) + return syscall.EFBIG + case syserror.ErrInterrupted: + // The syscall was interrupted. Return nil if it completed + // partially, otherwise return the error code that the syscall + // needs (to indicate to the kernel what it should do). + if partialResult { + return nil + } + return intr + } + + if !partialResult { + // Typical syscall error. + return err + } + + switch err { + case syserror.EINTR: + // Syscall interrupted, but completed a partial + // read/write. Like ErrWouldBlock, since we have a + // partial read/write, we consume the error and return + // the partial result. + return nil + case syserror.EFAULT: + // EFAULT is only shown the user if nothing was + // read/written. If we read something (this case), they see + // a partial read/write. They will then presumably try again + // with an incremented buffer, which will EFAULT with + // result == 0. + return nil + case syserror.EPIPE: + // Writes to a pipe or socket will return EPIPE if the other + // side is gone. The partial write is returned. EPIPE will be + // returned on the next call. + // + // TODO: In some cases SIGPIPE should also be sent + // to the application. + return nil + case syserror.ErrWouldBlock: + // Syscall would block, but completed a partial read/write. + // This case should only be returned by IssueIO for nonblocking + // files. Since we have a partial read/write, we consume + // ErrWouldBlock, returning the partial result. + return nil + } + + switch err.(type) { + case kernel.SyscallRestartErrno: + // Identical to the EINTR case. + return nil + } + + // An unknown error is encountered with a partial read/write. + name, _ := f.Dirent.FullName(nil /* ignore chroot */) + log.Traceback("Invalid request partialResult %v and err (type %T) %v for %s operation on %q, %T", partialResult, err, err, op, name, f.FileOperations) + partialResultOnce.Do(partialResultMetric.Increment) + return nil +} |