Files
moby/plugin/manager_test.go
T
Paweł Gronowski d5986c0430 plugin: Fix off-by-one in privilege validation
Fix an off-by-one error in isEqual() where the comparison loop started
at index 1 instead of 0, causing the first privilege (after sorting
alphabetically by name) to never be validated.

This allowed a malicious plugin to request different values for
whichever privilege sorts first — most notably "allow-all-devices",
which grants unrestricted rwm access to all host devices.

The bug also meant that plugins requesting exactly one privilege had
zero iterations of the comparison loop, bypassing validation entirely.

Also fix an existing test case ("diff-order-but-same-value") that only
passed due to the off-by-one bug, and add test cases for single-element
and first-sorted-element mismatches.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 99a095ecf0)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-03-25 13:11:13 +01:00

92 lines
3.3 KiB
Go

package plugin // import "github.com/docker/docker/plugin"
import (
"testing"
"github.com/docker/docker/api/types"
)
func TestValidatePrivileges(t *testing.T) {
testData := map[string]struct {
requiredPrivileges types.PluginPrivileges
privileges types.PluginPrivileges
result bool
}{
"diff-len": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "Privilege1", Description: "Description", Value: []string{"abc", "def", "ghi"}},
},
privileges: []types.PluginPrivilege{
{Name: "Privilege1", Description: "Description", Value: []string{"abc", "def", "ghi"}},
{Name: "Privilege2", Description: "Description", Value: []string{"123", "456", "789"}},
},
result: false,
},
"diff-value": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "Privilege1", Description: "Description", Value: []string{"abc", "def", "GHI"}},
{Name: "Privilege2", Description: "Description", Value: []string{"123", "456", "***"}},
},
privileges: []types.PluginPrivilege{
{Name: "Privilege1", Description: "Description", Value: []string{"abc", "def", "ghi"}},
{Name: "Privilege2", Description: "Description", Value: []string{"123", "456", "789"}},
},
result: false,
},
"diff-order-but-same-value": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "Privilege1", Description: "Description", Value: []string{"abc", "def", "GHI"}},
{Name: "Privilege2", Description: "Description", Value: []string{"123", "456", "789"}},
},
privileges: []types.PluginPrivilege{
{Name: "Privilege2", Description: "Description", Value: []string{"123", "456", "789"}},
{Name: "Privilege1", Description: "Description", Value: []string{"GHI", "abc", "def"}},
},
result: true,
},
"single-element-same": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"true"}},
},
privileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"true"}},
},
result: true,
},
"single-element-diff-value": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"false"}},
},
privileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"true"}},
},
result: false,
},
"first-sorted-element-diff-value": {
requiredPrivileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"false"}},
{Name: "network", Description: "Description", Value: []string{"host"}},
},
privileges: []types.PluginPrivilege{
{Name: "allow-all-devices", Description: "Description", Value: []string{"true"}},
{Name: "network", Description: "Description", Value: []string{"host"}},
},
result: false,
},
"empty-privileges": {
requiredPrivileges: []types.PluginPrivilege{},
privileges: []types.PluginPrivilege{},
result: true,
},
}
for key, data := range testData {
t.Run(key, func(t *testing.T) {
err := validatePrivileges(data.requiredPrivileges, data.privileges)
if (err == nil) != data.result {
t.Fatalf("expected result to be %t, got %t", data.result, (err == nil))
}
})
}
}