github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/kernel/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 kernel 16 17 import ( 18 "fmt" 19 20 "github.com/MerlinKodo/gvisor/pkg/context" 21 "github.com/MerlinKodo/gvisor/pkg/refs" 22 "github.com/MerlinKodo/gvisor/pkg/sentry/socket/unix/transport" 23 "github.com/MerlinKodo/gvisor/pkg/sync" 24 "golang.org/x/sys/unix" 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 sync.Mutex `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 // NewAbstractSocketNamespace returns a new AbstractSocketNamespace. 50 func NewAbstractSocketNamespace() *AbstractSocketNamespace { 51 return &AbstractSocketNamespace{ 52 endpoints: make(map[string]abstractEndpoint), 53 } 54 } 55 56 // A boundEndpoint wraps a transport.BoundEndpoint to maintain a reference on 57 // its backing socket. 58 type boundEndpoint struct { 59 transport.BoundEndpoint 60 socket refs.TryRefCounter 61 } 62 63 // Release implements transport.BoundEndpoint.Release. 64 func (e *boundEndpoint) Release(ctx context.Context) { 65 e.socket.DecRef(ctx) 66 e.BoundEndpoint.Release(ctx) 67 } 68 69 // BoundEndpoint retrieves the endpoint bound to the given name. The return 70 // value is nil if no endpoint was bound. 71 func (a *AbstractSocketNamespace) BoundEndpoint(name string) transport.BoundEndpoint { 72 a.mu.Lock() 73 defer a.mu.Unlock() 74 75 ep, ok := a.endpoints[name] 76 if !ok { 77 return nil 78 } 79 80 if !ep.socket.TryIncRef() { 81 // The socket has reached zero references and is being destroyed. 82 return nil 83 } 84 85 return &boundEndpoint{ep.ep, ep.socket} 86 } 87 88 // Bind binds the given socket. 89 // 90 // When the last reference managed by socket is dropped, ep may be removed from the 91 // namespace. 92 func (a *AbstractSocketNamespace) Bind(ctx context.Context, name string, ep transport.BoundEndpoint, socket refs.TryRefCounter) error { 93 a.mu.Lock() 94 defer a.mu.Unlock() 95 96 // Check if there is already a socket (which has not yet been destroyed) bound at name. 97 if ep, ok := a.endpoints[name]; ok { 98 if ep.socket.TryIncRef() { 99 ep.socket.DecRef(ctx) 100 return unix.EADDRINUSE 101 } 102 } 103 104 ae := abstractEndpoint{ep: ep, name: name, ns: a} 105 ae.socket = socket 106 a.endpoints[name] = ae 107 return nil 108 } 109 110 // Remove removes the specified socket at name from the abstract socket 111 // namespace, if it has not yet been replaced. 112 func (a *AbstractSocketNamespace) Remove(name string, socket refs.TryRefCounter) { 113 a.mu.Lock() 114 defer a.mu.Unlock() 115 116 ep, ok := a.endpoints[name] 117 if !ok { 118 // We never delete a map entry apart from a socket's destructor (although the 119 // map entry may be overwritten). Therefore, a socket should exist, even if it 120 // may not be the one we expect. 121 panic(fmt.Sprintf("expected socket to exist at '%s' in abstract socket namespace", name)) 122 } 123 124 // A Bind() operation may race with callers of Remove(), e.g. in the 125 // following case: 126 // socket1 reaches zero references and begins destruction 127 // a.Bind("foo", ep, socket2) replaces socket1 with socket2 128 // socket1's destructor calls a.Remove("foo", socket1) 129 // 130 // Therefore, we need to check that the socket at name is what we expect 131 // before modifying the map. 132 if ep.socket == socket { 133 delete(a.endpoints, name) 134 } 135 }