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 }