mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-02 02:02:24 +00:00
virtcontainers: Implement function to get a free context ID
FindContextID generates a random number between 3 and max uint32 and uses it as context ID. Using ioctl findContextID checks if the context ID is free, if the context ID is being used by other process, this function iterates from over all valid context IDs until one is available. `/dev/vhost-vsock` is used to check what context IDs are free, we need it to ensure we are using a unique context ID to create the vsocks. Signed-off-by: Julio Montes <julio.montes@intel.com>
This commit is contained in:
parent
2339ac3f93
commit
9b283254c3
89
virtcontainers/utils/utils_linux.go
Normal file
89
virtcontainers/utils/utils_linux.go
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// from <linux/vhost.h>
|
||||
// VHOST_VSOCK_SET_GUEST_CID = _IOW(VHOST_VIRTIO, 0x60, __u64)
|
||||
const ioctlVhostVsockSetGuestCid = 0x4008AF60
|
||||
|
||||
var ioctlFunc = ioctl
|
||||
|
||||
var maxUInt uint32 = 1<<32 - 1
|
||||
|
||||
func ioctl(fd uintptr, request int, arg1 uint32) error {
|
||||
if _, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(request),
|
||||
uintptr(unsafe.Pointer(&arg1)),
|
||||
); errno != 0 {
|
||||
return os.NewSyscallError("ioctl", fmt.Errorf("%d", int(errno)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindContextID finds a unique context ID by generating a random number between 3 and max unsigned int (maxUint).
|
||||
// Using the ioctl VHOST_VSOCK_SET_GUEST_CID, findContextID asks to the kernel if the given
|
||||
// context ID (N) is available, when the context ID is not available, incrementing by 1 findContextID
|
||||
// iterates from N to maxUint until an available context ID is found, otherwise decrementing by 1
|
||||
// findContextID iterates from N to 3 until an available context ID is found, this is the last chance
|
||||
// to find a context ID available.
|
||||
// On success vhost file and a context ID greater or equal than 3 are returned, otherwise 0 and an error are returned.
|
||||
// vhost file can be used to send vhost file decriptor to QEMU. It's the caller's responsibility to
|
||||
// close vhost file descriptor.
|
||||
//
|
||||
// Benefits of using random context IDs:
|
||||
// - Reduce the probability of a *DoS attack*, since other processes don't know whatis the initial context ID
|
||||
// used by findContextID to find a context ID available
|
||||
//
|
||||
func FindContextID() (*os.File, uint32, error) {
|
||||
// context IDs 0x0, 0x1 and 0x2 are reserved, 0x3 is the first context ID usable.
|
||||
var firstContextID uint32 = 0x3
|
||||
var contextID = firstContextID
|
||||
|
||||
// Generate a random number
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(int64(maxUInt)))
|
||||
if err == nil && n.Int64() >= int64(firstContextID) {
|
||||
contextID = uint32(n.Int64())
|
||||
}
|
||||
|
||||
// Open vhost-vsock device to check what context ID is available.
|
||||
// This file descriptor holds/locks the context ID and it should be
|
||||
// inherited by QEMU process.
|
||||
vsockFd, err := os.OpenFile(VHostVSockDevicePath, syscall.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Looking for the first available context ID.
|
||||
for cid := contextID; cid <= maxUInt; cid++ {
|
||||
if err := ioctlFunc(vsockFd.Fd(), ioctlVhostVsockSetGuestCid, cid); err == nil {
|
||||
return vsockFd, cid, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Last chance to get a free context ID.
|
||||
for cid := contextID - 1; cid >= firstContextID; cid-- {
|
||||
if err := ioctlFunc(vsockFd.Fd(), ioctlVhostVsockSetGuestCid, cid); err == nil {
|
||||
return vsockFd, cid, nil
|
||||
}
|
||||
}
|
||||
|
||||
vsockFd.Close()
|
||||
return nil, 0, fmt.Errorf("Could not get a unique context ID for the vsock")
|
||||
}
|
35
virtcontainers/utils/utils_linux_test.go
Normal file
35
virtcontainers/utils/utils_linux_test.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFindContextID(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
ioctlFunc = func(fd uintptr, request int, arg1 uint32) error {
|
||||
return errors.New("ioctl")
|
||||
}
|
||||
|
||||
orgVHostVSockDevicePath := VHostVSockDevicePath
|
||||
orgMaxUInt := maxUInt
|
||||
defer func() {
|
||||
VHostVSockDevicePath = orgVHostVSockDevicePath
|
||||
maxUInt = orgMaxUInt
|
||||
}()
|
||||
VHostVSockDevicePath = "/dev/null"
|
||||
maxUInt = uint32(1000000)
|
||||
|
||||
f, cid, err := FindContextID()
|
||||
assert.Nil(f)
|
||||
assert.Zero(cid)
|
||||
assert.Error(err)
|
||||
}
|
Loading…
Reference in New Issue
Block a user