github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/devices/tundev/tundev.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 tundev implements the /dev/net/tun device.
    16  package tundev
    17  
    18  import (
    19  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    20  	"github.com/SagerNet/gvisor/pkg/context"
    21  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    22  	"github.com/SagerNet/gvisor/pkg/hostarch"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/fsimpl/devtmpfs"
    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/sentry/vfs"
    29  	"github.com/SagerNet/gvisor/pkg/syserror"
    30  	"github.com/SagerNet/gvisor/pkg/tcpip/link/tun"
    31  	"github.com/SagerNet/gvisor/pkg/usermem"
    32  	"github.com/SagerNet/gvisor/pkg/waiter"
    33  )
    34  
    35  const (
    36  	netTunDevMajor = 10
    37  	netTunDevMinor = 200
    38  )
    39  
    40  // tunDevice implements vfs.Device for /dev/net/tun.
    41  //
    42  // +stateify savable
    43  type tunDevice struct{}
    44  
    45  // Open implements vfs.Device.Open.
    46  func (tunDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
    47  	fd := &tunFD{}
    48  	if err := fd.vfsfd.Init(fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{
    49  		UseDentryMetadata: true,
    50  	}); err != nil {
    51  		return nil, err
    52  	}
    53  	return &fd.vfsfd, nil
    54  }
    55  
    56  // tunFD implements vfs.FileDescriptionImpl for /dev/net/tun.
    57  //
    58  // +stateify savable
    59  type tunFD struct {
    60  	vfsfd vfs.FileDescription
    61  	vfs.FileDescriptionDefaultImpl
    62  	vfs.DentryMetadataFileDescriptionImpl
    63  	vfs.NoLockFD
    64  
    65  	device tun.Device
    66  }
    67  
    68  // Ioctl implements vfs.FileDescriptionImpl.Ioctl.
    69  func (fd *tunFD) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error) {
    70  	request := args[1].Uint()
    71  	data := args[2].Pointer()
    72  
    73  	t := kernel.TaskFromContext(ctx)
    74  	if t == nil {
    75  		panic("Ioctl should be called from a task context")
    76  	}
    77  
    78  	switch request {
    79  	case linux.TUNSETIFF:
    80  		if !t.HasCapability(linux.CAP_NET_ADMIN) {
    81  			return 0, linuxerr.EPERM
    82  		}
    83  		stack, ok := t.NetworkContext().(*netstack.Stack)
    84  		if !ok {
    85  			return 0, linuxerr.EINVAL
    86  		}
    87  
    88  		var req linux.IFReq
    89  		if _, err := req.CopyIn(t, data); err != nil {
    90  			return 0, err
    91  		}
    92  
    93  		// Validate flags.
    94  		flags, err := netstack.LinuxToTUNFlags(hostarch.ByteOrder.Uint16(req.Data[:]))
    95  		if err != nil {
    96  			return 0, err
    97  		}
    98  		return 0, fd.device.SetIff(stack.Stack, req.Name(), flags)
    99  
   100  	case linux.TUNGETIFF:
   101  		var req linux.IFReq
   102  		copy(req.IFName[:], fd.device.Name())
   103  		hostarch.ByteOrder.PutUint16(req.Data[:], netstack.TUNFlagsToLinux(fd.device.Flags()))
   104  		_, err := req.CopyOut(t, data)
   105  		return 0, err
   106  
   107  	default:
   108  		return 0, syserror.ENOTTY
   109  	}
   110  }
   111  
   112  // Release implements vfs.FileDescriptionImpl.Release.
   113  func (fd *tunFD) Release(ctx context.Context) {
   114  	fd.device.Release(ctx)
   115  }
   116  
   117  // PRead implements vfs.FileDescriptionImpl.PRead.
   118  func (fd *tunFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
   119  	return fd.Read(ctx, dst, opts)
   120  }
   121  
   122  // Read implements vfs.FileDescriptionImpl.Read.
   123  func (fd *tunFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) {
   124  	data, err := fd.device.Read()
   125  	if err != nil {
   126  		return 0, err
   127  	}
   128  	n, err := dst.CopyOut(ctx, data)
   129  	if n > 0 && n < len(data) {
   130  		// Not an error for partial copying. Packet truncated.
   131  		err = nil
   132  	}
   133  	return int64(n), err
   134  }
   135  
   136  // PWrite implements vfs.FileDescriptionImpl.PWrite.
   137  func (fd *tunFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) {
   138  	return fd.Write(ctx, src, opts)
   139  }
   140  
   141  // Write implements vfs.FileDescriptionImpl.Write.
   142  func (fd *tunFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) {
   143  	data := make([]byte, src.NumBytes())
   144  	if _, err := src.CopyIn(ctx, data); err != nil {
   145  		return 0, err
   146  	}
   147  	return fd.device.Write(data)
   148  }
   149  
   150  // Readiness implements watier.Waitable.Readiness.
   151  func (fd *tunFD) Readiness(mask waiter.EventMask) waiter.EventMask {
   152  	return fd.device.Readiness(mask)
   153  }
   154  
   155  // EventRegister implements watier.Waitable.EventRegister.
   156  func (fd *tunFD) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
   157  	fd.device.EventRegister(e, mask)
   158  }
   159  
   160  // EventUnregister implements watier.Waitable.EventUnregister.
   161  func (fd *tunFD) EventUnregister(e *waiter.Entry) {
   162  	fd.device.EventUnregister(e)
   163  }
   164  
   165  // IsNetTunSupported returns whether /dev/net/tun device is supported for s.
   166  func IsNetTunSupported(s inet.Stack) bool {
   167  	_, ok := s.(*netstack.Stack)
   168  	return ok
   169  }
   170  
   171  // Register registers all devices implemented by this package in vfsObj.
   172  func Register(vfsObj *vfs.VirtualFilesystem) error {
   173  	return vfsObj.RegisterDevice(vfs.CharDevice, netTunDevMajor, netTunDevMinor, tunDevice{}, &vfs.RegisterDeviceOptions{})
   174  }
   175  
   176  // CreateDevtmpfsFiles creates device special files in dev representing all
   177  // devices implemented by this package.
   178  func CreateDevtmpfsFiles(ctx context.Context, dev *devtmpfs.Accessor) error {
   179  	return dev.CreateDeviceFile(ctx, "net/tun", vfs.CharDevice, netTunDevMajor, netTunDevMinor, 0666 /* mode */)
   180  }