github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/dev/net_tun.go (about)

     1  // Copyright 2020 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 dev
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/context"
    20  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    21  	"github.com/SagerNet/gvisor/pkg/hostarch"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/fs/fsutil"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/inet"
    26  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    27  	"github.com/SagerNet/gvisor/pkg/sentry/socket/netstack"
    28  	"github.com/SagerNet/gvisor/pkg/syserror"
    29  	"github.com/SagerNet/gvisor/pkg/tcpip/link/tun"
    30  	"github.com/SagerNet/gvisor/pkg/usermem"
    31  	"github.com/SagerNet/gvisor/pkg/waiter"
    32  )
    33  
    34  const (
    35  	netTunDevMajor = 10
    36  	netTunDevMinor = 200
    37  )
    38  
    39  // +stateify savable
    40  type netTunInodeOperations struct {
    41  	fsutil.InodeGenericChecker       `state:"nosave"`
    42  	fsutil.InodeNoExtendedAttributes `state:"nosave"`
    43  	fsutil.InodeNoopAllocate         `state:"nosave"`
    44  	fsutil.InodeNoopRelease          `state:"nosave"`
    45  	fsutil.InodeNoopTruncate         `state:"nosave"`
    46  	fsutil.InodeNoopWriteOut         `state:"nosave"`
    47  	fsutil.InodeNotDirectory         `state:"nosave"`
    48  	fsutil.InodeNotMappable          `state:"nosave"`
    49  	fsutil.InodeNotSocket            `state:"nosave"`
    50  	fsutil.InodeNotSymlink           `state:"nosave"`
    51  	fsutil.InodeVirtual              `state:"nosave"`
    52  
    53  	fsutil.InodeSimpleAttributes
    54  }
    55  
    56  var _ fs.InodeOperations = (*netTunInodeOperations)(nil)
    57  
    58  func newNetTunDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *netTunInodeOperations {
    59  	return &netTunInodeOperations{
    60  		InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC),
    61  	}
    62  }
    63  
    64  // GetFile implements fs.InodeOperations.GetFile.
    65  func (*netTunInodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
    66  	return fs.NewFile(ctx, d, flags, &netTunFileOperations{}), nil
    67  }
    68  
    69  // +stateify savable
    70  type netTunFileOperations struct {
    71  	fsutil.FileNoSeek               `state:"nosave"`
    72  	fsutil.FileNoMMap               `state:"nosave"`
    73  	fsutil.FileNoSplice             `state:"nosave"`
    74  	fsutil.FileNoopFlush            `state:"nosave"`
    75  	fsutil.FileNoopFsync            `state:"nosave"`
    76  	fsutil.FileNotDirReaddir        `state:"nosave"`
    77  	fsutil.FileUseInodeUnstableAttr `state:"nosave"`
    78  
    79  	device tun.Device
    80  }
    81  
    82  var _ fs.FileOperations = (*netTunFileOperations)(nil)
    83  
    84  // Release implements fs.FileOperations.Release.
    85  func (n *netTunFileOperations) Release(ctx context.Context) {
    86  	n.device.Release(ctx)
    87  }
    88  
    89  // Ioctl implements fs.FileOperations.Ioctl.
    90  func (n *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
    91  	request := args[1].Uint()
    92  	data := args[2].Pointer()
    93  
    94  	t := kernel.TaskFromContext(ctx)
    95  	if t == nil {
    96  		panic("Ioctl should be called from a task context")
    97  	}
    98  
    99  	switch request {
   100  	case linux.TUNSETIFF:
   101  		if !t.HasCapability(linux.CAP_NET_ADMIN) {
   102  			return 0, linuxerr.EPERM
   103  		}
   104  		stack, ok := t.NetworkContext().(*netstack.Stack)
   105  		if !ok {
   106  			return 0, linuxerr.EINVAL
   107  		}
   108  
   109  		var req linux.IFReq
   110  		if _, err := req.CopyIn(t, data); err != nil {
   111  			return 0, err
   112  		}
   113  
   114  		// Validate flags.
   115  		flags, err := netstack.LinuxToTUNFlags(hostarch.ByteOrder.Uint16(req.Data[:]))
   116  		if err != nil {
   117  			return 0, err
   118  		}
   119  		return 0, n.device.SetIff(stack.Stack, req.Name(), flags)
   120  
   121  	case linux.TUNGETIFF:
   122  		var req linux.IFReq
   123  		copy(req.IFName[:], n.device.Name())
   124  		hostarch.ByteOrder.PutUint16(req.Data[:], netstack.TUNFlagsToLinux(n.device.Flags()))
   125  		_, err := req.CopyOut(t, data)
   126  		return 0, err
   127  
   128  	default:
   129  		return 0, syserror.ENOTTY
   130  	}
   131  }
   132  
   133  // Write implements fs.FileOperations.Write.
   134  func (n *netTunFileOperations) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
   135  	data := make([]byte, src.NumBytes())
   136  	if _, err := src.CopyIn(ctx, data); err != nil {
   137  		return 0, err
   138  	}
   139  	return n.device.Write(data)
   140  }
   141  
   142  // Read implements fs.FileOperations.Read.
   143  func (n *netTunFileOperations) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
   144  	data, err := n.device.Read()
   145  	if err != nil {
   146  		return 0, err
   147  	}
   148  	bytesCopied, err := dst.CopyOut(ctx, data)
   149  	if bytesCopied > 0 && bytesCopied < len(data) {
   150  		// Not an error for partial copying. Packet truncated.
   151  		err = nil
   152  	}
   153  	return int64(bytesCopied), err
   154  }
   155  
   156  // Readiness implements watier.Waitable.Readiness.
   157  func (n *netTunFileOperations) Readiness(mask waiter.EventMask) waiter.EventMask {
   158  	return n.device.Readiness(mask)
   159  }
   160  
   161  // EventRegister implements watier.Waitable.EventRegister.
   162  func (n *netTunFileOperations) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
   163  	n.device.EventRegister(e, mask)
   164  }
   165  
   166  // EventUnregister implements watier.Waitable.EventUnregister.
   167  func (n *netTunFileOperations) EventUnregister(e *waiter.Entry) {
   168  	n.device.EventUnregister(e)
   169  }
   170  
   171  // isNetTunSupported returns whether /dev/net/tun device is supported for s.
   172  func isNetTunSupported(s inet.Stack) bool {
   173  	_, ok := s.(*netstack.Stack)
   174  	return ok
   175  }