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 }