github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/syserr/syserr.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package syserr contains sandbox-internal errors. These errors are distinct
    16  // from both the errors returned by host system calls and the errors returned
    17  // to sandboxed applications.
    18  package syserr
    19  
    20  import (
    21  	"fmt"
    22  
    23  	"golang.org/x/sys/unix"
    24  	"github.com/sagernet/gvisor/pkg/abi/linux/errno"
    25  	"github.com/sagernet/gvisor/pkg/errors"
    26  	"github.com/sagernet/gvisor/pkg/errors/linuxerr"
    27  	"github.com/sagernet/gvisor/pkg/safecopy"
    28  )
    29  
    30  // Error represents an internal error.
    31  type Error struct {
    32  	// message is the human readable form of this Error.
    33  	message string
    34  
    35  	// noTranslation indicates that this Error cannot be translated to a
    36  	// errno.Errno.
    37  	noTranslation bool
    38  
    39  	// errno is the errno.Errno this Error should be translated to.
    40  	errno errno.Errno
    41  }
    42  
    43  // New creates a new Error and adds a translation for it.
    44  //
    45  // New must only be called at init.
    46  func New(message string, linuxTranslation errno.Errno) *Error {
    47  	err := &Error{message: message, errno: linuxTranslation}
    48  
    49  	// TODO(b/34162363): Remove this.
    50  	if int(err.errno) >= len(linuxBackwardsTranslations) {
    51  		panic(fmt.Sprint("invalid errno: ", err.errno))
    52  	}
    53  
    54  	e := error(unix.Errno(err.errno))
    55  	// linuxerr.ErrWouldBlock gets translated to linuxerr.EWOULDBLOCK and
    56  	// enables proper blocking semantics. This should temporary address the
    57  	// class of blocking bugs that keep popping up with the current state of
    58  	// the error space.
    59  	if err.errno == linuxerr.EWOULDBLOCK.Errno() {
    60  		e = linuxerr.ErrWouldBlock
    61  	}
    62  	linuxBackwardsTranslations[err.errno] = linuxBackwardsTranslation{err: e, ok: true}
    63  
    64  	return err
    65  }
    66  
    67  // NewDynamic creates a new error with a dynamic error message and an errno
    68  // translation.
    69  //
    70  // NewDynamic should only be used sparingly and not be used for static error
    71  // messages. Errors with static error messages should be declared with New as
    72  // global variables.
    73  func NewDynamic(message string, linuxTranslation errno.Errno) *Error {
    74  	return &Error{message: message, errno: linuxTranslation}
    75  }
    76  
    77  func newWithHost(message string, linuxTranslation errno.Errno, hostErrno unix.Errno) *Error {
    78  	e := New(message, linuxTranslation)
    79  	addHostTranslation(hostErrno, e)
    80  	return e
    81  }
    82  
    83  // String implements fmt.Stringer.String.
    84  func (e *Error) String() string {
    85  	if e == nil {
    86  		return "<nil>"
    87  	}
    88  	return e.message
    89  }
    90  
    91  type linuxBackwardsTranslation struct {
    92  	err error
    93  	ok  bool
    94  }
    95  
    96  // TODO(b/34162363): Remove this.
    97  var linuxBackwardsTranslations [maxErrno]linuxBackwardsTranslation
    98  
    99  // ToError translates an Error to a corresponding error value.
   100  //
   101  // TODO(b/34162363): Remove this.
   102  func (e *Error) ToError() error {
   103  	if e == nil {
   104  		return nil
   105  	}
   106  	if e.noTranslation {
   107  		panic(fmt.Sprintf("error %q does not support translation", e.message))
   108  	}
   109  	err := int(e.errno)
   110  	if err == errno.NOERRNO {
   111  		return nil
   112  	}
   113  	if err >= len(linuxBackwardsTranslations) || !linuxBackwardsTranslations[err].ok {
   114  		panic(fmt.Sprintf("unknown error %q (%d)", e.message, err))
   115  	}
   116  	return linuxBackwardsTranslations[err].err
   117  }
   118  
   119  // ToLinux converts the Error to a Linux ABI error that can be returned to the
   120  // application.
   121  func (e *Error) ToLinux() errno.Errno {
   122  	if e.noTranslation {
   123  		panic(fmt.Sprintf("No Linux ABI translation available for %q", e.message))
   124  	}
   125  	return e.errno
   126  }
   127  
   128  // TODO(b/34162363): Remove or replace most of these errors.
   129  //
   130  // Some of the errors should be replaced with package specific errors and
   131  // others should be removed entirely.
   132  //
   133  // Note that some errors are declared in platform-specific files.
   134  var (
   135  	ErrNotPermitted               = newWithHost("operation not permitted", errno.EPERM, unix.EPERM)
   136  	ErrNoFileOrDir                = newWithHost("no such file or directory", errno.ENOENT, unix.ENOENT)
   137  	ErrNoProcess                  = newWithHost("no such process", errno.ESRCH, unix.ESRCH)
   138  	ErrInterrupted                = newWithHost("interrupted system call", errno.EINTR, unix.EINTR)
   139  	ErrIO                         = newWithHost("I/O error", errno.EIO, unix.EIO)
   140  	ErrDeviceOrAddress            = newWithHost("no such device or address", errno.ENXIO, unix.ENXIO)
   141  	ErrTooManyArgs                = newWithHost("argument list too long", errno.E2BIG, unix.E2BIG)
   142  	ErrEcec                       = newWithHost("exec format error", errno.ENOEXEC, unix.ENOEXEC)
   143  	ErrBadFD                      = newWithHost("bad file number", errno.EBADF, unix.EBADF)
   144  	ErrNoChild                    = newWithHost("no child processes", errno.ECHILD, unix.ECHILD)
   145  	ErrTryAgain                   = newWithHost("try again", errno.EAGAIN, unix.EAGAIN)
   146  	ErrNoMemory                   = newWithHost("out of memory", errno.ENOMEM, unix.ENOMEM)
   147  	ErrPermissionDenied           = newWithHost("permission denied", errno.EACCES, unix.EACCES)
   148  	ErrBadAddress                 = newWithHost("bad address", errno.EFAULT, unix.EFAULT)
   149  	ErrNotBlockDevice             = newWithHost("block device required", errno.ENOTBLK, unix.ENOTBLK)
   150  	ErrBusy                       = newWithHost("device or resource busy", errno.EBUSY, unix.EBUSY)
   151  	ErrExists                     = newWithHost("file exists", errno.EEXIST, unix.EEXIST)
   152  	ErrCrossDeviceLink            = newWithHost("cross-device link", errno.EXDEV, unix.EXDEV)
   153  	ErrNoDevice                   = newWithHost("no such device", errno.ENODEV, unix.ENODEV)
   154  	ErrNotDir                     = newWithHost("not a directory", errno.ENOTDIR, unix.ENOTDIR)
   155  	ErrIsDir                      = newWithHost("is a directory", errno.EISDIR, unix.EISDIR)
   156  	ErrInvalidArgument            = newWithHost("invalid argument", errno.EINVAL, unix.EINVAL)
   157  	ErrFileTableOverflow          = newWithHost("file table overflow", errno.ENFILE, unix.ENFILE)
   158  	ErrTooManyOpenFiles           = newWithHost("too many open files", errno.EMFILE, unix.EMFILE)
   159  	ErrNotTTY                     = newWithHost("not a typewriter", errno.ENOTTY, unix.ENOTTY)
   160  	ErrTestFileBusy               = newWithHost("text file busy", errno.ETXTBSY, unix.ETXTBSY)
   161  	ErrFileTooBig                 = newWithHost("file too large", errno.EFBIG, unix.EFBIG)
   162  	ErrNoSpace                    = newWithHost("no space left on device", errno.ENOSPC, unix.ENOSPC)
   163  	ErrIllegalSeek                = newWithHost("illegal seek", errno.ESPIPE, unix.ESPIPE)
   164  	ErrReadOnlyFS                 = newWithHost("read-only file system", errno.EROFS, unix.EROFS)
   165  	ErrTooManyLinks               = newWithHost("too many links", errno.EMLINK, unix.EMLINK)
   166  	ErrBrokenPipe                 = newWithHost("broken pipe", errno.EPIPE, unix.EPIPE)
   167  	ErrDomain                     = newWithHost("math argument out of domain of func", errno.EDOM, unix.EDOM)
   168  	ErrRange                      = newWithHost("math result not representable", errno.ERANGE, unix.ERANGE)
   169  	ErrNameTooLong                = newWithHost("file name too long", errno.ENAMETOOLONG, unix.ENAMETOOLONG)
   170  	ErrNoLocksAvailable           = newWithHost("no record locks available", errno.ENOLCK, unix.ENOLCK)
   171  	ErrInvalidSyscall             = newWithHost("invalid system call number", errno.ENOSYS, unix.ENOSYS)
   172  	ErrDirNotEmpty                = newWithHost("directory not empty", errno.ENOTEMPTY, unix.ENOTEMPTY)
   173  	ErrLinkLoop                   = newWithHost("too many symbolic links encountered", errno.ELOOP, unix.ELOOP)
   174  	ErrNoMessage                  = newWithHost("no message of desired type", errno.ENOMSG, unix.ENOMSG)
   175  	ErrIdentifierRemoved          = newWithHost("identifier removed", errno.EIDRM, unix.EIDRM)
   176  	ErrNotStream                  = newWithHost("device not a stream", errno.ENOSTR, unix.ENOSTR)
   177  	ErrNoDataAvailable            = newWithHost("no data available", errno.ENODATA, unix.ENODATA)
   178  	ErrTimerExpired               = newWithHost("timer expired", errno.ETIME, unix.ETIME)
   179  	ErrStreamsResourceDepleted    = newWithHost("out of streams resources", errno.ENOSR, unix.ENOSR)
   180  	ErrIsRemote                   = newWithHost("object is remote", errno.EREMOTE, unix.EREMOTE)
   181  	ErrNoLink                     = newWithHost("link has been severed", errno.ENOLINK, unix.ENOLINK)
   182  	ErrProtocol                   = newWithHost("protocol error", errno.EPROTO, unix.EPROTO)
   183  	ErrMultihopAttempted          = newWithHost("multihop attempted", errno.EMULTIHOP, unix.EMULTIHOP)
   184  	ErrInvalidDataMessage         = newWithHost("not a data message", errno.EBADMSG, unix.EBADMSG)
   185  	ErrOverflow                   = newWithHost("value too large for defined data type", errno.EOVERFLOW, unix.EOVERFLOW)
   186  	ErrIllegalByteSequence        = newWithHost("illegal byte sequence", errno.EILSEQ, unix.EILSEQ)
   187  	ErrTooManyUsers               = newWithHost("too many users", errno.EUSERS, unix.EUSERS)
   188  	ErrNotASocket                 = newWithHost("socket operation on non-socket", errno.ENOTSOCK, unix.ENOTSOCK)
   189  	ErrDestinationAddressRequired = newWithHost("destination address required", errno.EDESTADDRREQ, unix.EDESTADDRREQ)
   190  	ErrMessageTooLong             = newWithHost("message too long", errno.EMSGSIZE, unix.EMSGSIZE)
   191  	ErrWrongProtocolForSocket     = newWithHost("protocol wrong type for socket", errno.EPROTOTYPE, unix.EPROTOTYPE)
   192  	ErrProtocolNotAvailable       = newWithHost("protocol not available", errno.ENOPROTOOPT, unix.ENOPROTOOPT)
   193  	ErrProtocolNotSupported       = newWithHost("protocol not supported", errno.EPROTONOSUPPORT, unix.EPROTONOSUPPORT)
   194  	ErrSocketNotSupported         = newWithHost("socket type not supported", errno.ESOCKTNOSUPPORT, unix.ESOCKTNOSUPPORT)
   195  	ErrEndpointOperation          = newWithHost("operation not supported on transport endpoint", errno.EOPNOTSUPP, unix.EOPNOTSUPP)
   196  	ErrProtocolFamilyNotSupported = newWithHost("protocol family not supported", errno.EPFNOSUPPORT, unix.EPFNOSUPPORT)
   197  	ErrAddressFamilyNotSupported  = newWithHost("address family not supported by protocol", errno.EAFNOSUPPORT, unix.EAFNOSUPPORT)
   198  	ErrAddressInUse               = newWithHost("address already in use", errno.EADDRINUSE, unix.EADDRINUSE)
   199  	ErrAddressNotAvailable        = newWithHost("cannot assign requested address", errno.EADDRNOTAVAIL, unix.EADDRNOTAVAIL)
   200  	ErrNetworkDown                = newWithHost("network is down", errno.ENETDOWN, unix.ENETDOWN)
   201  	ErrNetworkUnreachable         = newWithHost("network is unreachable", errno.ENETUNREACH, unix.ENETUNREACH)
   202  	ErrNetworkReset               = newWithHost("network dropped connection because of reset", errno.ENETRESET, unix.ENETRESET)
   203  	ErrConnectionAborted          = newWithHost("software caused connection abort", errno.ECONNABORTED, unix.ECONNABORTED)
   204  	ErrConnectionReset            = newWithHost("connection reset by peer", errno.ECONNRESET, unix.ECONNRESET)
   205  	ErrNoBufferSpace              = newWithHost("no buffer space available", errno.ENOBUFS, unix.ENOBUFS)
   206  	ErrAlreadyConnected           = newWithHost("transport endpoint is already connected", errno.EISCONN, unix.EISCONN)
   207  	ErrNotConnected               = newWithHost("transport endpoint is not connected", errno.ENOTCONN, unix.ENOTCONN)
   208  	ErrShutdown                   = newWithHost("cannot send after transport endpoint shutdown", errno.ESHUTDOWN, unix.ESHUTDOWN)
   209  	ErrTooManyRefs                = newWithHost("too many references: cannot splice", errno.ETOOMANYREFS, unix.ETOOMANYREFS)
   210  	ErrTimedOut                   = newWithHost("connection timed out", errno.ETIMEDOUT, unix.ETIMEDOUT)
   211  	ErrConnectionRefused          = newWithHost("connection refused", errno.ECONNREFUSED, unix.ECONNREFUSED)
   212  	ErrHostDown                   = newWithHost("host is down", errno.EHOSTDOWN, unix.EHOSTDOWN)
   213  	ErrHostUnreachable            = newWithHost("no route to host", errno.EHOSTUNREACH, unix.EHOSTUNREACH)
   214  	ErrAlreadyInProgress          = newWithHost("operation already in progress", errno.EALREADY, unix.EALREADY)
   215  	ErrInProgress                 = newWithHost("operation now in progress", errno.EINPROGRESS, unix.EINPROGRESS)
   216  	ErrStaleFileHandle            = newWithHost("stale file handle", errno.ESTALE, unix.ESTALE)
   217  	ErrQuotaExceeded              = newWithHost("quota exceeded", errno.EDQUOT, unix.EDQUOT)
   218  	ErrCanceled                   = newWithHost("operation canceled", errno.ECANCELED, unix.ECANCELED)
   219  	ErrOwnerDied                  = newWithHost("owner died", errno.EOWNERDEAD, unix.EOWNERDEAD)
   220  	ErrNotRecoverable             = newWithHost("state not recoverable", errno.ENOTRECOVERABLE, unix.ENOTRECOVERABLE)
   221  
   222  	// ErrWouldBlock translates to EWOULDBLOCK which is the same as EAGAIN
   223  	// on Linux.
   224  	ErrWouldBlock = New("operation would block", errno.EWOULDBLOCK)
   225  )
   226  
   227  // FromError converts a generic error to an *Error.
   228  //
   229  // TODO(b/34162363): Remove this function.
   230  func FromError(err error) *Error {
   231  	if err == nil {
   232  		return nil
   233  	}
   234  
   235  	switch e := err.(type) {
   236  	case unix.Errno:
   237  		return FromHost(e)
   238  	case *errors.Error:
   239  		return FromHost(unix.Errno(e.Errno()))
   240  	case safecopy.SegvError, safecopy.BusError, safecopy.AlignmentError:
   241  		return FromHost(unix.EFAULT)
   242  	}
   243  
   244  	msg := fmt.Sprintf("err: %s type: %T", err.Error(), err)
   245  	panic(msg)
   246  }