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