gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/gvisor/pkg/abi/linux" 23 "gvisor.dev/gvisor/pkg/buffer" 24 "gvisor.dev/gvisor/pkg/context" 25 "gvisor.dev/gvisor/pkg/errors/linuxerr" 26 "gvisor.dev/gvisor/pkg/hostarch" 27 "gvisor.dev/gvisor/pkg/sentry/arch" 28 "gvisor.dev/gvisor/pkg/sentry/inet" 29 "gvisor.dev/gvisor/pkg/sentry/kernel" 30 "gvisor.dev/gvisor/pkg/sentry/socket/netstack" 31 "gvisor.dev/gvisor/pkg/sentry/vfs" 32 "gvisor.dev/gvisor/pkg/tcpip/link/tun" 33 "gvisor.dev/gvisor/pkg/usermem" 34 "gvisor.dev/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 }