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