Skip to content

Commit cbc4f98

Browse files
committed
libcontainer: rewrite cmsg to use sys/unix
The original implementation is in C, which increases cognitive load and possibly might cause us problems in the future. Since sys/unix is better maintained than the syscall standard library switching makes more sense. Signed-off-by: Aleksa Sarai <[email protected]>
1 parent 85de7ec commit cbc4f98

File tree

3 files changed

+56
-202
lines changed

3 files changed

+56
-202
lines changed

libcontainer/utils/cmsg.c

Lines changed: 0 additions & 148 deletions
This file was deleted.

libcontainer/utils/cmsg.go

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package utils
44

55
/*
6-
* Copyright 2016 SUSE LLC
6+
* Copyright 2016, 2017 SUSE LLC
77
*
88
* Licensed under the Apache License, Version 2.0 (the "License");
99
* you may not use this file except in compliance with the License.
@@ -18,40 +18,78 @@ package utils
1818
* limitations under the License.
1919
*/
2020

21-
/*
22-
#include <errno.h>
23-
#include <stdlib.h>
24-
#include "cmsg.h"
25-
*/
26-
import "C"
27-
2821
import (
22+
"fmt"
2923
"os"
30-
"unsafe"
24+
25+
"golang.org/x/sys/unix"
3126
)
3227

28+
// MaxSendfdLen is the maximum length of the name of a file descriptor being
29+
// sent using SendFd. The name of the file handle returned by RecvFd will never
30+
// be larger than this value.
31+
const MaxNameLen = 4096
32+
33+
// oobSpace is the size of the oob slice required to store a single FD. Note
34+
// that unix.UnixRights appears to make the assumption that fd is always int32,
35+
// so sizeof(fd) = 4.
36+
var oobSpace = unix.CmsgSpace(4)
37+
3338
// RecvFd waits for a file descriptor to be sent over the given AF_UNIX
3439
// socket. The file name of the remote file descriptor will be recreated
3540
// locally (it is sent as non-auxiliary data in the same payload).
3641
func RecvFd(socket *os.File) (*os.File, error) {
37-
file, err := C.recvfd(C.int(socket.Fd()))
42+
// For some reason, unix.Recvmsg uses the length rather than the capacity
43+
// when passing the msg_controllen and other attributes to recvmsg. So we
44+
// have to actually set the length.
45+
name := make([]byte, MaxNameLen)
46+
oob := make([]byte, oobSpace)
47+
48+
sockfd := socket.Fd()
49+
n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0)
3850
if err != nil {
3951
return nil, err
4052
}
41-
defer C.free(unsafe.Pointer(file.name))
42-
return os.NewFile(uintptr(file.fd), C.GoString(file.name)), nil
53+
54+
if n >= MaxNameLen || oobn != oobSpace {
55+
return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
56+
}
57+
58+
// Truncate.
59+
name = name[:n]
60+
oob = oob[:oobn]
61+
62+
scms, err := unix.ParseSocketControlMessage(oob)
63+
if err != nil {
64+
return nil, err
65+
}
66+
if len(scms) != 1 {
67+
return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
68+
}
69+
scm := scms[0]
70+
71+
fds, err := unix.ParseUnixRights(&scm)
72+
if err != nil {
73+
return nil, err
74+
}
75+
if len(fds) != 1 {
76+
return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
77+
}
78+
fd := uintptr(fds[0])
79+
80+
return os.NewFile(fd, string(name)), nil
4381
}
4482

4583
// SendFd sends a file descriptor over the given AF_UNIX socket. In
4684
// addition, the file.Name() of the given file will also be sent as
4785
// non-auxiliary data in the same payload (allowing to send contextual
4886
// information for a file descriptor).
4987
func SendFd(socket, file *os.File) error {
50-
var cfile C.struct_file_t
51-
cfile.fd = C.int(file.Fd())
52-
cfile.name = C.CString(file.Name())
53-
defer C.free(unsafe.Pointer(cfile.name))
88+
name := []byte(file.Name())
89+
if len(name) >= MaxNameLen {
90+
return fmt.Errorf("sendfd: filename too long: %s", file.Name())
91+
}
92+
oob := unix.UnixRights(int(file.Fd()))
5493

55-
_, err := C.sendfd(C.int(socket.Fd()), cfile)
56-
return err
94+
return unix.Sendmsg(int(socket.Fd()), name, oob, nil, 0)
5795
}

libcontainer/utils/cmsg.h

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)