mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
libct: move cmsg helpers to new internal/cmsg package
These helpers all make more sense as a self-contained package and moving them has the added benefit of removing an unneeded libpathrs dependency (from libcontainer/utils's import of pathrs-lite) from several test binaries. Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
"github.com/opencontainers/runc/internal/pathrs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
@@ -1193,7 +1194,7 @@ func (c *Container) criuNotifications(resp *criurpc.CriuResp, process *Process,
|
||||
defer master.Close()
|
||||
|
||||
// While we can access console.master, using the API is a good idea.
|
||||
if err := utils.SendFile(process.ConsoleSocket, master); err != nil {
|
||||
if err := cmsg.SendFile(process.ConsoleSocket, master); err != nil {
|
||||
return err
|
||||
}
|
||||
case "status-ready":
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
"github.com/opencontainers/runc/internal/linux"
|
||||
"github.com/opencontainers/runc/internal/pathrs"
|
||||
"github.com/opencontainers/runc/libcontainer/capabilities"
|
||||
@@ -406,7 +407,7 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error {
|
||||
}
|
||||
}
|
||||
// While we can access console.master, using the API is a good idea.
|
||||
if err := utils.SendRawFd(socket, pty.Name(), pty.Fd()); err != nil {
|
||||
if err := cmsg.SendRawFd(socket, pty.Name(), pty.Fd()); err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.KeepAlive(pty)
|
||||
@@ -728,7 +729,7 @@ func setupPidfd(socket *os.File, initType string) error {
|
||||
return fmt.Errorf("failed to pidfd_open: %w", err)
|
||||
}
|
||||
|
||||
if err := utils.SendRawFd(socket, initType, uintptr(pidFd)); err != nil {
|
||||
if err := cmsg.SendRawFd(socket, initType, uintptr(pidFd)); err != nil {
|
||||
unix.Close(pidFd)
|
||||
return fmt.Errorf("failed to send pidfd on socket: %w", err)
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestExecIn(t *testing.T) {
|
||||
@@ -272,7 +273,7 @@ func TestExecInTTY(t *testing.T) {
|
||||
|
||||
done := make(chan (error))
|
||||
go func() {
|
||||
f, err := utils.RecvFile(parent)
|
||||
f, err := cmsg.RecvFile(parent)
|
||||
if err != nil {
|
||||
done <- fmt.Errorf("RecvFile: %w", err)
|
||||
return
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
"github.com/opencontainers/runc/internal/linux"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
@@ -1132,7 +1133,7 @@ func sendContainerProcessState(listenerPath string, state *specs.ContainerProces
|
||||
return fmt.Errorf("cannot marshall seccomp state: %w", err)
|
||||
}
|
||||
|
||||
if err := utils.SendRawFd(socket, string(b), file.Fd()); err != nil {
|
||||
if err := cmsg.SendRawFd(socket, string(b), file.Fd()); err != nil {
|
||||
return fmt.Errorf("cannot send seccomp fd to %s: %w", listenerPath, err)
|
||||
}
|
||||
runtime.KeepAlive(file)
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
)
|
||||
|
||||
type syncType string
|
||||
@@ -102,7 +102,7 @@ func doWriteSync(pipe *syncSocket, sync syncT) error {
|
||||
}
|
||||
if sync.Flags&syncFlagHasFd != 0 {
|
||||
logrus.Debugf("writing sync file %s", sync)
|
||||
if err := utils.SendFile(pipe.File(), sync.File); err != nil {
|
||||
if err := cmsg.SendFile(pipe.File(), sync.File); err != nil {
|
||||
return fmt.Errorf("sending file after sync %q: %w", sync.Type, err)
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func doReadSync(pipe *syncSocket) (syncT, error) {
|
||||
}
|
||||
if sync.Flags&syncFlagHasFd != 0 {
|
||||
logrus.Debugf("reading sync file %s", sync)
|
||||
file, err := utils.RecvFile(pipe.File())
|
||||
file, err := cmsg.RecvFile(pipe.File())
|
||||
if err != nil {
|
||||
return sync, fmt.Errorf("receiving fd from sync %v failed: %w", sync.Type, err)
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package utils
|
||||
|
||||
/*
|
||||
* Copyright 2016, 2017 SUSE LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/opencontainers/runc/internal/linux"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// MaxNameLen is the maximum length of the name of a file descriptor being sent
|
||||
// using SendFile. The name of the file handle returned by RecvFile will never be
|
||||
// larger than this value.
|
||||
const MaxNameLen = 4096
|
||||
|
||||
// oobSpace is the size of the oob slice required to store a single FD. Note
|
||||
// that unix.UnixRights appears to make the assumption that fd is always int32,
|
||||
// so sizeof(fd) = 4.
|
||||
var oobSpace = unix.CmsgSpace(4)
|
||||
|
||||
// RecvFile waits for a file descriptor to be sent over the given AF_UNIX
|
||||
// socket. The file name of the remote file descriptor will be recreated
|
||||
// locally (it is sent as non-auxiliary data in the same payload).
|
||||
func RecvFile(socket *os.File) (_ *os.File, Err error) {
|
||||
name := make([]byte, MaxNameLen)
|
||||
oob := make([]byte, oobSpace)
|
||||
|
||||
sockfd := socket.Fd()
|
||||
var (
|
||||
n, oobn int
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
n, oobn, _, _, err = unix.Recvmsg(int(sockfd), name, oob, unix.MSG_CMSG_CLOEXEC)
|
||||
if err != unix.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, os.NewSyscallError("recvmsg", err)
|
||||
}
|
||||
if n >= MaxNameLen || oobn != oobSpace {
|
||||
return nil, fmt.Errorf("recvfile: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
|
||||
}
|
||||
// Truncate.
|
||||
name = name[:n]
|
||||
oob = oob[:oobn]
|
||||
|
||||
scms, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We cannot control how many SCM_RIGHTS we receive, and upon receiving
|
||||
// them all of the descriptors are installed in our fd table, so we need to
|
||||
// parse all of the SCM_RIGHTS we received in order to close all of the
|
||||
// descriptors on error.
|
||||
var fds []int
|
||||
defer func() {
|
||||
for i, fd := range fds {
|
||||
if i == 0 && Err == nil {
|
||||
// Only close the first one on error.
|
||||
continue
|
||||
}
|
||||
// Always close extra ones.
|
||||
_ = unix.Close(fd)
|
||||
}
|
||||
}()
|
||||
var lastErr error
|
||||
for _, scm := range scms {
|
||||
if scm.Header.Type == unix.SCM_RIGHTS {
|
||||
scmFds, err := unix.ParseUnixRights(&scm)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
} else {
|
||||
fds = append(fds, scmFds...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
// We do this after collecting the fds to make sure we close them all when
|
||||
// returning an error here.
|
||||
if len(scms) != 1 {
|
||||
return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
|
||||
}
|
||||
if len(fds) != 1 {
|
||||
return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
|
||||
}
|
||||
return os.NewFile(uintptr(fds[0]), string(name)), nil
|
||||
}
|
||||
|
||||
// SendFile sends a file over the given AF_UNIX socket. file.Name() is also
|
||||
// included so that if the other end uses RecvFile, the file will have the same
|
||||
// name information.
|
||||
func SendFile(socket, file *os.File) error {
|
||||
name := file.Name()
|
||||
if len(name) >= MaxNameLen {
|
||||
return fmt.Errorf("sendfd: filename too long: %s", name)
|
||||
}
|
||||
err := SendRawFd(socket, name, file.Fd())
|
||||
runtime.KeepAlive(file)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendRawFd sends a specific file descriptor over the given AF_UNIX socket.
|
||||
func SendRawFd(socket *os.File, msg string, fd uintptr) error {
|
||||
oob := unix.UnixRights(int(fd))
|
||||
return linux.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/runc/internal/cmsg"
|
||||
)
|
||||
|
||||
// RecvFile waits for a file descriptor to be sent over the given AF_UNIX
|
||||
// socket. The file name of the remote file descriptor will be recreated
|
||||
// locally (it is sent as non-auxiliary data in the same payload).
|
||||
//
|
||||
// Deprecated: This method is deprecated and has been moved to an internal
|
||||
// package (see [cmsg.RecvFile]). It will be removed in runc 1.6.
|
||||
func RecvFile(socket *os.File) (*os.File, error) {
|
||||
return cmsg.RecvFile(socket)
|
||||
}
|
||||
|
||||
// SendFile sends a file over the given AF_UNIX socket. file.Name() is also
|
||||
// included so that if the other end uses RecvFile, the file will have the same
|
||||
// name information.
|
||||
//
|
||||
// Deprecated: This method is deprecated and has been moved to an internal
|
||||
// package (see [cmsg.SendFile]). It will be removed in runc 1.6.
|
||||
func SendFile(socket, file *os.File) error {
|
||||
return cmsg.SendFile(socket, file)
|
||||
}
|
||||
|
||||
// SendRawFd sends a specific file descriptor over the given AF_UNIX socket.
|
||||
//
|
||||
// Deprecated: This method is deprecated and has been moved to an internal
|
||||
// package (see [cmsg.SendRawFd]). It will be removed in runc 1.6.
|
||||
func SendRawFd(socket *os.File, msg string, fd uintptr) error {
|
||||
return cmsg.SendRawFd(socket, msg, fd)
|
||||
}
|
||||
Reference in New Issue
Block a user