2023-05-17 11:36:01 -04:00
|
|
|
//go:build integration && linux && cgo
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
package integration
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2023-10-05 05:20:22 -04:00
|
|
|
"sync"
|
2022-03-22 11:03:15 -04:00
|
|
|
"testing"
|
|
|
|
|
2022-09-21 07:47:57 -04:00
|
|
|
"github.com/edgelesssys/constellation/v2/csi/cryptmapper"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2022-06-30 09:24:36 -04:00
|
|
|
"go.uber.org/goleak"
|
2022-03-22 11:03:15 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-07-17 07:55:31 -04:00
|
|
|
devicePath string = "testDevice"
|
2023-10-05 05:20:22 -04:00
|
|
|
deviceName string = "testDeviceName"
|
2022-03-22 11:03:15 -04:00
|
|
|
)
|
|
|
|
|
2023-10-05 05:20:22 -04:00
|
|
|
func setup(devicePath string) {
|
2023-07-17 07:55:31 -04:00
|
|
|
if err := exec.Command("/bin/dd", "if=/dev/zero", fmt.Sprintf("of=%s", devicePath), "bs=64M", "count=1").Run(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
2022-05-19 02:47:17 -04:00
|
|
|
func teardown(devicePath string) {
|
2023-07-17 07:55:31 -04:00
|
|
|
if err := exec.Command("/bin/rm", "-f", devicePath).Run(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2022-05-19 02:47:17 -04:00
|
|
|
}
|
|
|
|
|
2023-03-20 06:08:46 -04:00
|
|
|
func cp(source, target string) error {
|
2022-05-19 02:47:17 -04:00
|
|
|
return exec.Command("cp", source, target).Run()
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
2023-10-05 05:20:22 -04:00
|
|
|
func resize(devicePath string) {
|
2023-07-17 07:55:31 -04:00
|
|
|
if err := exec.Command("/bin/dd", "if=/dev/zero", fmt.Sprintf("of=%s", devicePath), "bs=32M", "count=1", "oflag=append", "conv=notrunc").Run(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2022-05-10 04:43:48 -04:00
|
|
|
}
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
if os.Getuid() != 0 {
|
2022-05-10 04:43:48 -04:00
|
|
|
fmt.Printf("This test suite requires root privileges, as libcryptsetup uses the kernel's device mapper.\n")
|
2022-03-22 11:03:15 -04:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2022-06-30 09:24:36 -04:00
|
|
|
goleak.VerifyTestMain(m)
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
result := m.Run()
|
|
|
|
os.Exit(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOpenAndClose(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
2023-10-05 05:20:22 -04:00
|
|
|
setup(devicePath)
|
2023-07-17 07:55:31 -04:00
|
|
|
defer teardown(devicePath)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2023-09-06 09:05:59 -04:00
|
|
|
mapper := cryptmapper.New(&fakeKMS{})
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
newPath, err := mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, false)
|
2022-03-22 11:03:15 -04:00
|
|
|
require.NoError(err)
|
2023-07-17 07:55:31 -04:00
|
|
|
defer func() {
|
|
|
|
_ = mapper.CloseCryptDevice(deviceName)
|
|
|
|
}()
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
// assert crypt device got created
|
|
|
|
_, err = os.Stat(newPath)
|
2023-07-17 07:55:31 -04:00
|
|
|
require.NoError(err)
|
2022-03-22 11:03:15 -04:00
|
|
|
// assert no integrity device got created
|
|
|
|
_, err = os.Stat(newPath + "_dif")
|
|
|
|
assert.True(os.IsNotExist(err))
|
|
|
|
|
2023-10-05 05:20:22 -04:00
|
|
|
// Opening the same device should return the same path and not error
|
|
|
|
newPath2, err := mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, false)
|
|
|
|
require.NoError(err)
|
|
|
|
assert.Equal(newPath, newPath2)
|
|
|
|
|
2022-05-10 04:43:48 -04:00
|
|
|
// Resize the device
|
2023-10-05 05:20:22 -04:00
|
|
|
resize(devicePath)
|
2022-05-10 04:43:48 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
resizedPath, err := mapper.ResizeCryptDevice(context.Background(), deviceName)
|
2022-05-10 04:43:48 -04:00
|
|
|
require.NoError(err)
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.Equal("/dev/mapper/"+deviceName, resizedPath)
|
2022-05-10 04:43:48 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName))
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
// assert crypt device got removed
|
|
|
|
_, err = os.Stat(newPath)
|
|
|
|
assert.True(os.IsNotExist(err))
|
2022-05-19 02:47:17 -04:00
|
|
|
|
|
|
|
// check if we can reopen the device
|
2023-07-17 07:55:31 -04:00
|
|
|
_, err = mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, true)
|
2022-05-19 02:47:17 -04:00
|
|
|
assert.NoError(err)
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName))
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestOpenAndCloseIntegrity(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
2023-10-05 05:20:22 -04:00
|
|
|
setup(devicePath)
|
2023-07-17 07:55:31 -04:00
|
|
|
defer teardown(devicePath)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2023-09-06 09:05:59 -04:00
|
|
|
mapper := cryptmapper.New(&fakeKMS{})
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
newPath, err := mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, true)
|
2022-03-22 11:03:15 -04:00
|
|
|
require.NoError(err)
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.Equal("/dev/mapper/"+deviceName, newPath)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
// assert crypt device got created
|
|
|
|
_, err = os.Stat(newPath)
|
|
|
|
assert.NoError(err)
|
|
|
|
// assert integrity device got created
|
|
|
|
_, err = os.Stat(newPath + "_dif")
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2023-10-05 05:20:22 -04:00
|
|
|
// Opening the same device should return the same path and not error
|
|
|
|
newPath2, err := mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, true)
|
|
|
|
require.NoError(err)
|
|
|
|
assert.Equal(newPath, newPath2)
|
|
|
|
|
2022-05-10 04:43:48 -04:00
|
|
|
// integrity devices do not support resizing
|
2023-10-05 05:20:22 -04:00
|
|
|
resize(devicePath)
|
2023-07-17 07:55:31 -04:00
|
|
|
_, err = mapper.ResizeCryptDevice(context.Background(), deviceName)
|
2022-05-10 04:43:48 -04:00
|
|
|
assert.Error(err)
|
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName))
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
// assert crypt device got removed
|
|
|
|
_, err = os.Stat(newPath)
|
|
|
|
assert.True(os.IsNotExist(err))
|
|
|
|
// assert integrity device got removed
|
|
|
|
_, err = os.Stat(newPath + "_dif")
|
|
|
|
assert.True(os.IsNotExist(err))
|
2022-05-19 02:47:17 -04:00
|
|
|
|
|
|
|
// check if we can reopen the device
|
2023-07-17 07:55:31 -04:00
|
|
|
_, err = mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, true)
|
2022-05-19 02:47:17 -04:00
|
|
|
assert.NoError(err)
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName))
|
2022-05-19 02:47:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeviceCloning(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
require := require.New(t)
|
2023-10-05 05:20:22 -04:00
|
|
|
setup(devicePath)
|
2023-07-17 07:55:31 -04:00
|
|
|
defer teardown(devicePath)
|
2022-05-19 02:47:17 -04:00
|
|
|
|
2023-09-06 09:05:59 -04:00
|
|
|
mapper := cryptmapper.New(&dynamicKMS{})
|
2022-05-19 02:47:17 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
_, err := mapper.OpenCryptDevice(context.Background(), devicePath, deviceName, false)
|
2022-05-19 02:47:17 -04:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
require.NoError(cp(devicePath, devicePath+"-copy"))
|
|
|
|
defer teardown(devicePath + "-copy")
|
2022-05-19 02:47:17 -04:00
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
_, err = mapper.OpenCryptDevice(context.Background(), devicePath+"-copy", deviceName+"-copy", false)
|
2022-05-19 02:47:17 -04:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2023-07-17 07:55:31 -04:00
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName))
|
|
|
|
assert.NoError(mapper.CloseCryptDevice(deviceName + "-copy"))
|
2022-05-19 02:47:17 -04:00
|
|
|
}
|
|
|
|
|
2023-10-05 05:20:22 -04:00
|
|
|
func TestConcurrency(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
setup(devicePath)
|
|
|
|
defer teardown(devicePath)
|
|
|
|
|
|
|
|
device2 := devicePath + "-2"
|
|
|
|
setup(device2)
|
|
|
|
defer teardown(device2)
|
|
|
|
|
|
|
|
mapper := cryptmapper.New(&fakeKMS{})
|
|
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
runTest := func(path, name string) {
|
|
|
|
newPath, err := mapper.OpenCryptDevice(context.Background(), path, name, false)
|
|
|
|
assert.NoError(err)
|
|
|
|
defer func() {
|
|
|
|
_ = mapper.CloseCryptDevice(name)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// assert crypt device got created
|
|
|
|
_, err = os.Stat(newPath)
|
|
|
|
assert.NoError(err)
|
|
|
|
// assert no integrity device got created
|
|
|
|
_, err = os.Stat(newPath + "_dif")
|
|
|
|
assert.True(os.IsNotExist(err))
|
|
|
|
assert.NoError(mapper.CloseCryptDevice(name))
|
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Add(2)
|
|
|
|
go runTest(devicePath, deviceName)
|
|
|
|
go runTest(device2, deviceName+"-2")
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2022-09-05 02:42:55 -04:00
|
|
|
type fakeKMS struct{}
|
|
|
|
|
2023-03-20 06:03:36 -04:00
|
|
|
func (k *fakeKMS) GetDEK(_ context.Context, _ string, dekSize int) ([]byte, error) {
|
2022-09-05 02:42:55 -04:00
|
|
|
key := make([]byte, dekSize)
|
|
|
|
for i := range key {
|
|
|
|
key[i] = 0x41
|
|
|
|
}
|
|
|
|
return key, nil
|
|
|
|
}
|
|
|
|
|
2022-05-19 02:47:17 -04:00
|
|
|
type dynamicKMS struct{}
|
|
|
|
|
2023-03-20 06:03:36 -04:00
|
|
|
func (k *dynamicKMS) GetDEK(_ context.Context, dekID string, dekSize int) ([]byte, error) {
|
2022-05-19 02:47:17 -04:00
|
|
|
key := make([]byte, dekSize)
|
|
|
|
for i := range key {
|
|
|
|
key[i] = 0x41 ^ dekID[i%len(dekID)]
|
|
|
|
}
|
|
|
|
return key, nil
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|