github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/dev/net_tun.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 dev 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/context" 20 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 21 "github.com/SagerNet/gvisor/pkg/hostarch" 22 "github.com/SagerNet/gvisor/pkg/sentry/arch" 23 "github.com/SagerNet/gvisor/pkg/sentry/fs" 24 "github.com/SagerNet/gvisor/pkg/sentry/fs/fsutil" 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/syserror" 29 "github.com/SagerNet/gvisor/pkg/tcpip/link/tun" 30 "github.com/SagerNet/gvisor/pkg/usermem" 31 "github.com/SagerNet/gvisor/pkg/waiter" 32 ) 33 34 const ( 35 netTunDevMajor = 10 36 netTunDevMinor = 200 37 ) 38 39 // +stateify savable 40 type netTunInodeOperations struct { 41 fsutil.InodeGenericChecker `state:"nosave"` 42 fsutil.InodeNoExtendedAttributes `state:"nosave"` 43 fsutil.InodeNoopAllocate `state:"nosave"` 44 fsutil.InodeNoopRelease `state:"nosave"` 45 fsutil.InodeNoopTruncate `state:"nosave"` 46 fsutil.InodeNoopWriteOut `state:"nosave"` 47 fsutil.InodeNotDirectory `state:"nosave"` 48 fsutil.InodeNotMappable `state:"nosave"` 49 fsutil.InodeNotSocket `state:"nosave"` 50 fsutil.InodeNotSymlink `state:"nosave"` 51 fsutil.InodeVirtual `state:"nosave"` 52 53 fsutil.InodeSimpleAttributes 54 } 55 56 var _ fs.InodeOperations = (*netTunInodeOperations)(nil) 57 58 func newNetTunDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *netTunInodeOperations { 59 return &netTunInodeOperations{ 60 InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC), 61 } 62 } 63 64 // GetFile implements fs.InodeOperations.GetFile. 65 func (*netTunInodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) { 66 return fs.NewFile(ctx, d, flags, &netTunFileOperations{}), nil 67 } 68 69 // +stateify savable 70 type netTunFileOperations struct { 71 fsutil.FileNoSeek `state:"nosave"` 72 fsutil.FileNoMMap `state:"nosave"` 73 fsutil.FileNoSplice `state:"nosave"` 74 fsutil.FileNoopFlush `state:"nosave"` 75 fsutil.FileNoopFsync `state:"nosave"` 76 fsutil.FileNotDirReaddir `state:"nosave"` 77 fsutil.FileUseInodeUnstableAttr `state:"nosave"` 78 79 device tun.Device 80 } 81 82 var _ fs.FileOperations = (*netTunFileOperations)(nil) 83 84 // Release implements fs.FileOperations.Release. 85 func (n *netTunFileOperations) Release(ctx context.Context) { 86 n.device.Release(ctx) 87 } 88 89 // Ioctl implements fs.FileOperations.Ioctl. 90 func (n *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) { 91 request := args[1].Uint() 92 data := args[2].Pointer() 93 94 t := kernel.TaskFromContext(ctx) 95 if t == nil { 96 panic("Ioctl should be called from a task context") 97 } 98 99 switch request { 100 case linux.TUNSETIFF: 101 if !t.HasCapability(linux.CAP_NET_ADMIN) { 102 return 0, linuxerr.EPERM 103 } 104 stack, ok := t.NetworkContext().(*netstack.Stack) 105 if !ok { 106 return 0, linuxerr.EINVAL 107 } 108 109 var req linux.IFReq 110 if _, err := req.CopyIn(t, data); err != nil { 111 return 0, err 112 } 113 114 // Validate flags. 115 flags, err := netstack.LinuxToTUNFlags(hostarch.ByteOrder.Uint16(req.Data[:])) 116 if err != nil { 117 return 0, err 118 } 119 return 0, n.device.SetIff(stack.Stack, req.Name(), flags) 120 121 case linux.TUNGETIFF: 122 var req linux.IFReq 123 copy(req.IFName[:], n.device.Name()) 124 hostarch.ByteOrder.PutUint16(req.Data[:], netstack.TUNFlagsToLinux(n.device.Flags())) 125 _, err := req.CopyOut(t, data) 126 return 0, err 127 128 default: 129 return 0, syserror.ENOTTY 130 } 131 } 132 133 // Write implements fs.FileOperations.Write. 134 func (n *netTunFileOperations) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) { 135 data := make([]byte, src.NumBytes()) 136 if _, err := src.CopyIn(ctx, data); err != nil { 137 return 0, err 138 } 139 return n.device.Write(data) 140 } 141 142 // Read implements fs.FileOperations.Read. 143 func (n *netTunFileOperations) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) { 144 data, err := n.device.Read() 145 if err != nil { 146 return 0, err 147 } 148 bytesCopied, err := dst.CopyOut(ctx, data) 149 if bytesCopied > 0 && bytesCopied < len(data) { 150 // Not an error for partial copying. Packet truncated. 151 err = nil 152 } 153 return int64(bytesCopied), err 154 } 155 156 // Readiness implements watier.Waitable.Readiness. 157 func (n *netTunFileOperations) Readiness(mask waiter.EventMask) waiter.EventMask { 158 return n.device.Readiness(mask) 159 } 160 161 // EventRegister implements watier.Waitable.EventRegister. 162 func (n *netTunFileOperations) EventRegister(e *waiter.Entry, mask waiter.EventMask) { 163 n.device.EventRegister(e, mask) 164 } 165 166 // EventUnregister implements watier.Waitable.EventUnregister. 167 func (n *netTunFileOperations) EventUnregister(e *waiter.Entry) { 168 n.device.EventUnregister(e) 169 } 170 171 // isNetTunSupported returns whether /dev/net/tun device is supported for s. 172 func isNetTunSupported(s inet.Stack) bool { 173 _, ok := s.(*netstack.Stack) 174 return ok 175 }