Skip to content

Commit 85d3b5c

Browse files
samuelkarpdmcgowan
authored andcommitted
containerd-shim: use path-based unix socket
This allows filesystem-based ACLs for configuring access to the socket of a shim. Ported from Michael Crosby's similar patch for v2 shims. Signed-off-by: Samuel Karp <[email protected]>
1 parent 689d92c commit 85d3b5c

3 files changed

Lines changed: 105 additions & 18 deletions

File tree

cmd/containerd-shim/main_unix.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ var (
7171
func init() {
7272
flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs")
7373
flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim")
74-
flag.StringVar(&socketFlag, "socket", "", "abstract socket path to serve")
74+
flag.StringVar(&socketFlag, "socket", "", "socket path to serve")
7575
flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd")
7676
flag.StringVar(&workdirFlag, "workdir", "", "path used to storge large temporary data")
7777
flag.StringVar(&runtimeRootFlag, "runtime-root", process.RuncRoot, "root directory for the runtime")
@@ -202,10 +202,18 @@ func serve(ctx context.Context, server *ttrpc.Server, path string) error {
202202
f.Close()
203203
path = "[inherited from parent]"
204204
} else {
205-
if len(path) > 106 {
206-
return errors.Errorf("%q: unix socket path too long (> 106)", path)
205+
const (
206+
abstractSocketPrefix = "\x00"
207+
socketPathLimit = 106
208+
)
209+
p := strings.TrimPrefix(path, "unix://")
210+
if len(p) == len(path) {
211+
p = abstractSocketPrefix + p
207212
}
208-
l, err = net.Listen("unix", "\x00"+path)
213+
if len(p) > socketPathLimit {
214+
return errors.Errorf("%q: unix socket path too long (> %d)", p, socketPathLimit)
215+
}
216+
l, err = net.Listen("unix", p)
209217
}
210218
if err != nil {
211219
return err

runtime/v1/linux/bundle.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) Shi
9191
return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
9292
config := b.shimConfig(ns, c, ropts)
9393
return config,
94-
client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler)
94+
client.WithStart(c.Shim, b.shimAddress(ns, daemonAddress), daemonAddress, cgroup, c.ShimDebug, exitHandler)
9595
}
9696
}
9797

@@ -117,6 +117,11 @@ func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientO
117117

118118
// Delete deletes the bundle from disk
119119
func (b *bundle) Delete() error {
120+
address, _ := b.loadAddress()
121+
if address != "" {
122+
// we don't care about errors here
123+
client.RemoveSocket(address)
124+
}
120125
err := atomicDelete(b.path)
121126
if err == nil {
122127
return atomicDelete(b.workDir)
@@ -133,9 +138,11 @@ func (b *bundle) legacyShimAddress(namespace string) string {
133138
return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
134139
}
135140

136-
func (b *bundle) shimAddress(namespace string) string {
137-
d := sha256.Sum256([]byte(filepath.Join(namespace, b.id)))
138-
return filepath.Join(string(filepath.Separator), "containerd-shim", fmt.Sprintf("%x.sock", d))
141+
const socketRoot = "/run/containerd"
142+
143+
func (b *bundle) shimAddress(namespace, socketPath string) string {
144+
d := sha256.Sum256([]byte(filepath.Join(socketPath, namespace, b.id)))
145+
return fmt.Sprintf("unix://%s/%x", filepath.Join(socketRoot, "s"), d)
139146
}
140147

141148
func (b *bundle) loadAddress() (string, error) {

runtime/v1/shim/client/client.go

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,17 @@ func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHa
5757
return func(ctx context.Context, config shim.Config) (_ shimapi.ShimService, _ io.Closer, err error) {
5858
socket, err := newSocket(address)
5959
if err != nil {
60-
return nil, nil, err
60+
if !eaddrinuse(err) {
61+
return nil, nil, err
62+
}
63+
if err := RemoveSocket(address); err != nil {
64+
return nil, nil, errors.Wrap(err, "remove already used socket")
65+
}
66+
if socket, err = newSocket(address); err != nil {
67+
return nil, nil, err
68+
}
6169
}
62-
defer socket.Close()
70+
6371
f, err := socket.File()
6472
if err != nil {
6573
return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", address)
@@ -104,6 +112,8 @@ func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHa
104112
if stderrLog != nil {
105113
stderrLog.Close()
106114
}
115+
socket.Close()
116+
RemoveSocket(address)
107117
}()
108118
log.G(ctx).WithFields(logrus.Fields{
109119
"pid": cmd.Process.Pid,
@@ -138,6 +148,26 @@ func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHa
138148
}
139149
}
140150

151+
func eaddrinuse(err error) bool {
152+
cause := errors.Cause(err)
153+
netErr, ok := cause.(*net.OpError)
154+
if !ok {
155+
return false
156+
}
157+
if netErr.Op != "listen" {
158+
return false
159+
}
160+
syscallErr, ok := netErr.Err.(*os.SyscallError)
161+
if !ok {
162+
return false
163+
}
164+
errno, ok := syscallErr.Err.(syscall.Errno)
165+
if !ok {
166+
return false
167+
}
168+
return errno == syscall.EADDRINUSE
169+
}
170+
141171
// setupOOMScore gets containerd's oom score and adds +1 to it
142172
// to ensure a shim has a lower* score than the daemons
143173
func setupOOMScore(shimPid int) error {
@@ -210,31 +240,73 @@ func writeFile(path, address string) error {
210240
return os.Rename(tempPath, path)
211241
}
212242

243+
const (
244+
abstractSocketPrefix = "\x00"
245+
socketPathLimit = 106
246+
)
247+
248+
type socket string
249+
250+
func (s socket) isAbstract() bool {
251+
return !strings.HasPrefix(string(s), "unix://")
252+
}
253+
254+
func (s socket) path() string {
255+
path := strings.TrimPrefix(string(s), "unix://")
256+
// if there was no trim performed, we assume an abstract socket
257+
if len(path) == len(s) {
258+
path = abstractSocketPrefix + path
259+
}
260+
return path
261+
}
262+
213263
func newSocket(address string) (*net.UnixListener, error) {
214-
if len(address) > 106 {
215-
return nil, errors.Errorf("%q: unix socket path too long (> 106)", address)
264+
if len(address) > socketPathLimit {
265+
return nil, errors.Errorf("%q: unix socket path too long (> %d)", address, socketPathLimit)
266+
}
267+
var (
268+
sock = socket(address)
269+
path = sock.path()
270+
)
271+
if !sock.isAbstract() {
272+
if err := os.MkdirAll(filepath.Dir(path), 0600); err != nil {
273+
return nil, errors.Wrapf(err, "%s", path)
274+
}
216275
}
217-
l, err := net.Listen("unix", "\x00"+address)
276+
l, err := net.Listen("unix", path)
218277
if err != nil {
219-
return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address)
278+
return nil, errors.Wrapf(err, "failed to listen to unix socket %q (abstract: %t)", address, sock.isAbstract())
279+
}
280+
if err := os.Chmod(path, 0600); err != nil {
281+
l.Close()
282+
return nil, err
220283
}
221284

222285
return l.(*net.UnixListener), nil
223286
}
224287

288+
// RemoveSocket removes the socket at the specified address if
289+
// it exists on the filesystem
290+
func RemoveSocket(address string) error {
291+
sock := socket(address)
292+
if !sock.isAbstract() {
293+
return os.Remove(sock.path())
294+
}
295+
return nil
296+
}
297+
225298
func connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) {
226299
return d(address, 100*time.Second)
227300
}
228301

229-
func annonDialer(address string, timeout time.Duration) (net.Conn, error) {
230-
address = strings.TrimPrefix(address, "unix://")
231-
return net.DialTimeout("unix", "\x00"+address, timeout)
302+
func anonDialer(address string, timeout time.Duration) (net.Conn, error) {
303+
return net.DialTimeout("unix", socket(address).path(), timeout)
232304
}
233305

234306
// WithConnect connects to an existing shim
235307
func WithConnect(address string, onClose func()) Opt {
236308
return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) {
237-
conn, err := connect(address, annonDialer)
309+
conn, err := connect(address, anonDialer)
238310
if err != nil {
239311
return nil, nil, err
240312
}

0 commit comments

Comments
 (0)