From a9c1dd0fad85b02e32528a19dc2cfef1f4ce683e Mon Sep 17 00:00:00 2001 From: Bin Tang Date: Thu, 3 Aug 2023 16:25:10 +0800 Subject: [PATCH] keyring: for test Signed-off-by: Bin Tang --- pkg/auth/cache.go | 6 ++-- pkg/auth/keyring.go | 75 +++++++++++++++++++++++++++++++++------- pkg/auth/keyring_test.go | 33 ++++++++++++++++-- 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/pkg/auth/cache.go b/pkg/auth/cache.go index 1a16ac1384..6a3011f584 100644 --- a/pkg/auth/cache.go +++ b/pkg/auth/cache.go @@ -63,10 +63,10 @@ func (c *Cache) GetAuth(imageHost string) (string, error) { return data, err } -func (c *Cache) GetKeyChain(ImageID string) (*PassKeyChain, error) { - image, err := registry.ParseImage(ImageID) +func (c *Cache) GetKeyChain(imageID string) (*PassKeyChain, error) { + image, err := registry.ParseImage(imageID) if err != nil { - return nil, errors.Wrapf(err, "parse image %s", ImageID) + return nil, errors.Wrapf(err, "parse image %s", imageID) } cachedAuth, err := c.GetAuth(image.Host) diff --git a/pkg/auth/keyring.go b/pkg/auth/keyring.go index 254f10ba57..7b76b9f9f6 100644 --- a/pkg/auth/keyring.go +++ b/pkg/auth/keyring.go @@ -7,6 +7,7 @@ package auth import ( + "os" "strconv" "strings" "sync" @@ -28,7 +29,7 @@ var ( type KeyRing struct { sessKeyID int keyLock sync.RWMutex - avaliable bool + available bool } func GetSessionID() (int, error) { @@ -51,29 +52,71 @@ func GetSessionID() (int, error) { log.L.Infof("added search permission for session keyring %s", defaultSessionName) globalKeyRing.sessKeyID = sessKeyID - globalKeyRing.avaliable = true + globalKeyRing.available = true }, ) - if joinSessionErr != nil { - return 0, errors.Wrapf(joinSessionErr, "join session keyring %s.", defaultSessionName) - } - if !globalKeyRing.avaliable { + if !globalKeyRing.available || joinSessionErr != nil { return 0, unix.EINVAL } return globalKeyRing.sessKeyID, nil } +func ClearKeyring() error { + sessKeyID, err := GetSessionID() + if err != nil { + return err + } + log.L.Infof("[abin] clear keyring session ID: %d", sessKeyID) + + _, err = unix.KeyctlInt(unix.KEYCTL_CLEAR, sessKeyID, 0, 0, 0) + + return err +} + func AddKeyring(id, value string) (int, error) { sessKeyID, err := GetSessionID() if err != nil { return 0, err } + log.L.Infof("[abin]session ID: %d", sessKeyID) globalKeyRing.keyLock.Lock() defer globalKeyRing.keyLock.Unlock() + permFull, _, err := checkPermission(sessKeyID, 0) + if err != nil { + return 0, errors.Wrap(err, "check permission before adding key") + } + log.L.Infof("[abin] keyring permission: %b, uid: %d, gid: %d", permFull, os.Getuid(), os.Getgid()) + keyID, err := unix.AddKey("user", id, []byte(value), sessKeyID) + if err != nil { + if errors.Is(err, unix.EACCES) { + log.L.Infof("[abin] error unix.EACCES: %d", err) + return 0, unix.EINVAL + } + return 0, errors.Wrapf(err, "add key %s", id) + } + + permFull, _, err = checkPermission(keyID, 0) + if err != nil { + return 0, errors.Wrap(err, "check permission before adding key") + } + log.L.Infof("[abin] key %d permission: %b", keyID, permFull) + + if err := addSearchPermission(keyID); err != nil { + log.L.Infof("[abin] add permission to key: %d, err: %v", keyID, err) + return keyID, unix.EINVAL + } + + permFull, _, err = checkPermission(keyID, 0) + if err != nil { + return 0, errors.Wrap(err, "check permission before adding key") + } + log.L.Infof("[abin] key %d after add permission: %b", keyID, permFull) + + _, err = unix.KeyctlInt(unix.KEYCTL_LINK, keyID, sessKeyID, 0, 0) if err != nil { return 0, err } @@ -105,7 +148,7 @@ func checkPermission(ringID int, targetMask uint32) (uint32, bool, error) { permFull := uint32(perm64) & mask - return permFull, (permFull & targetMask) != 0, nil + return permFull, (permFull&targetMask)^targetMask == 0, nil } func addSearchPermission(ringID int) error { @@ -130,10 +173,10 @@ func addSearchPermission(ringID int) error { * * Refer to https://man7.org/linux/man-pages/man7/keyrings.7.html */ - var searchPermissionBits uint32 = 0x80000 + var allUserPermissionBits uint32 = 0x3f0000 // Check if the search right for user already exists. - permFull, hasPermission, err := checkPermission(ringID, searchPermissionBits) + permFull, hasPermission, err := checkPermission(ringID, allUserPermissionBits) if err != nil { return errors.Wrap(err, "check permission") } @@ -142,17 +185,21 @@ func addSearchPermission(ringID int) error { } // Add search right for user. - if err := unix.KeyctlSetperm(ringID, permFull|searchPermissionBits); err != nil { + if err := unix.KeyctlSetperm(ringID, permFull|allUserPermissionBits); err != nil { + log.L.Infof("[abin] set perm error: %v, ringID: %d, bits: %b", err, ringID, permFull|allUserPermissionBits) return errors.Wrap(err, "set permission") } - permFull, hasPermission, err = checkPermission(ringID, searchPermissionBits) + permFull, hasPermission, err = checkPermission(ringID, allUserPermissionBits) if err != nil { return errors.Wrap(err, "check permission after add search permission") } if !hasPermission { - return errors.Errorf("add search permission failed, current permission: %b", permFull) + return unix.EINVAL } + + log.L.Infof("[abin] keyring permission: %b", permFull) + return nil } @@ -177,6 +224,10 @@ func getData(key int) (string, error) { for { sizeRead, err := unix.KeyctlBuffer(unix.KEYCTL_READ, key, buffer, size) if err != nil { + log.L.Infof("[abin] KEYCTL_READ error:%v : %d", err, err) + if errors.Is(err, unix.EACCES) { + return "", unix.EINVAL + } return "", err } diff --git a/pkg/auth/keyring_test.go b/pkg/auth/keyring_test.go index 323f5452b1..f94abe3164 100644 --- a/pkg/auth/keyring_test.go +++ b/pkg/auth/keyring_test.go @@ -9,22 +9,34 @@ package auth import ( "testing" + "github.com/containerd/containerd/log" "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" ) func TestKeyRing_Add(t *testing.T) { A := assert.New(t) + err := ClearKeyring() + A.NoError(err) + testKey := "test" testValue := "value" keyID, err := AddKeyring(testKey, testValue) + if err != nil && err == unix.EINVAL { + return + } A.NoError(err) + log.L.Infof("[abin] keyID: %d", keyID) value, err := getData(keyID) + if err != nil && err == unix.EINVAL { + return + } A.NoError(err) A.Equal(testValue, value) - value, err = getData(-1) + value, err = getData(0) A.ErrorContains(err, "required key not available") A.Equal("", value) } @@ -32,9 +44,15 @@ func TestKeyRing_Add(t *testing.T) { func TestKeyRing_Search(t *testing.T) { A := assert.New(t) + err := ClearKeyring() + A.NoError(err) + testKey := "test" testValue := "value" - _, err := AddKeyring(testKey, testValue) + _, err = AddKeyring(testKey, testValue) + if err != nil && err == unix.EINVAL { + return + } A.NoError(err) value, err := SearchKeyring(testKey) @@ -49,6 +67,9 @@ func TestKeyRing_Search(t *testing.T) { func TestKeyRing_getData(t *testing.T) { A := assert.New(t) + err := ClearKeyring() + A.NoError(err) + testKey := "test" tests := []struct { name string @@ -78,10 +99,16 @@ func TestKeyRing_getData(t *testing.T) { testValue = append(testValue, 'A') } - keyID, err := AddKeyring(testKey, string(testValue[:])) + keyID, err := AddKeyring(testKey, string(testValue)) + if err != nil && err == unix.EINVAL { + return + } A.NoError(err) value, err := getData(keyID) + if err != nil && err == unix.EINVAL { + return + } A.NoError(err) A.Equal(tt.length, len([]byte(value))) })