gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/inet/abstract_socket_namespace.go (about) 1 // Copyright 2018 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 inet 16 17 import ( 18 "fmt" 19 "math/rand" 20 21 "gvisor.dev/gvisor/pkg/context" 22 "gvisor.dev/gvisor/pkg/refs" 23 "gvisor.dev/gvisor/pkg/sentry/socket/unix/transport" 24 "gvisor.dev/gvisor/pkg/syserr" 25 ) 26 27 // +stateify savable 28 type abstractEndpoint struct { 29 ep transport.BoundEndpoint 30 socket refs.TryRefCounter 31 name string 32 ns *AbstractSocketNamespace 33 } 34 35 // AbstractSocketNamespace is used to implement the Linux abstract socket functionality. 36 // 37 // +stateify savable 38 type AbstractSocketNamespace struct { 39 mu abstractSocketNamespaceMutex `state:"nosave"` 40 41 // Keeps a mapping from name to endpoint. AbstractSocketNamespace does not hold 42 // any references on any sockets that it contains; when retrieving a socket, 43 // TryIncRef() must be called in case the socket is concurrently being 44 // destroyed. It is the responsibility of the socket to remove itself from the 45 // abstract socket namespace when it is destroyed. 46 endpoints map[string]abstractEndpoint 47 } 48 49 // A boundEndpoint wraps a transport.BoundEndpoint to maintain a reference on 50 // its backing socket. 51 type boundEndpoint struct { 52 transport.BoundEndpoint 53 socket refs.TryRefCounter 54 } 55 56 // Release implements transport.BoundEndpoint.Release. 57 func (e *boundEndpoint) Release(ctx context.Context) { 58 e.socket.DecRef(ctx) 59 e.BoundEndpoint.Release(ctx) 60 } 61 62 func (a *AbstractSocketNamespace) init() { 63 a.endpoints = make(map[string]abstractEndpoint) 64 } 65 66 // BoundEndpoint retrieves the endpoint bound to the given name. The return 67 // value is nil if no endpoint was bound. 68 func (a *AbstractSocketNamespace) BoundEndpoint(name string) transport.BoundEndpoint { 69 a.mu.Lock() 70 defer a.mu.Unlock() 71 72 ep, ok := a.endpoints[name] 73 if !ok { 74 return nil 75 } 76 77 if !ep.socket.TryIncRef() { 78 // The socket has reached zero references and is being destroyed. 79 return nil 80 } 81 82 return &boundEndpoint{ep.ep, ep.socket} 83 } 84 85 // Bind binds the given socket. 86 // 87 // When the last reference managed by socket is dropped, ep may be removed from the 88 // namespace. 89 func (a *AbstractSocketNamespace) Bind(ctx context.Context, path string, ep transport.BoundEndpoint, socket refs.TryRefCounter) (string, *syserr.Error) { 90 a.mu.Lock() 91 defer a.mu.Unlock() 92 93 name := "" 94 if path == "" { 95 // Autobind feature. 96 mask := uint32(0xFFFFF) 97 r := rand.Uint32() 98 for i := uint32(0); i <= mask; i++ { 99 p := fmt.Sprintf("X%05x", (r+i)&mask) 100 if _, ok := a.endpoints[p[1:]]; ok { 101 continue 102 } 103 b := ([]byte)(p) 104 b[0] = 0 105 path = string(b) 106 break 107 } 108 if path == "" { 109 return "", syserr.ErrNoSpace 110 } 111 name = path[1:] 112 } else { 113 name = path[1:] 114 // Check if there is already a socket (which has not yet been destroyed) bound at name. 115 if _, ok := a.endpoints[name]; ok { 116 return "", syserr.ErrPortInUse 117 } 118 } 119 120 ae := abstractEndpoint{ep: ep, name: name, ns: a} 121 ae.socket = socket 122 a.endpoints[name] = ae 123 return path, nil 124 } 125 126 // Remove removes the specified socket at name from the abstract socket 127 // namespace, if it has not yet been replaced. 128 func (a *AbstractSocketNamespace) Remove(name string, socket refs.TryRefCounter) { 129 a.mu.Lock() 130 defer a.mu.Unlock() 131 132 ep, ok := a.endpoints[name] 133 if !ok { 134 // We never delete a map entry apart from a socket's destructor (although the 135 // map entry may be overwritten). Therefore, a socket should exist, even if it 136 // may not be the one we expect. 137 panic(fmt.Sprintf("expected socket to exist at '%s' in abstract socket namespace", name)) 138 } 139 140 // A Bind() operation may race with callers of Remove(), e.g. in the 141 // following case: 142 // socket1 reaches zero references and begins destruction 143 // a.Bind("foo", ep, socket2) replaces socket1 with socket2 144 // socket1's destructor calls a.Remove("foo", socket1) 145 // 146 // Therefore, we need to check that the socket at name is what we expect 147 // before modifying the map. 148 if ep.socket == socket { 149 delete(a.endpoints, name) 150 } 151 }