Skip to content

Commit

Permalink
keyring: for test
Browse files Browse the repository at this point in the history
Signed-off-by: Bin Tang <[email protected]>
  • Loading branch information
sctb512 committed Aug 4, 2023
1 parent ce775ee commit ee9c16d
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 18 deletions.
6 changes: 3 additions & 3 deletions pkg/auth/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
75 changes: 63 additions & 12 deletions pkg/auth/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package auth

import (
"os"
"strconv"
"strings"
"sync"
Expand All @@ -28,7 +29,7 @@ var (
type KeyRing struct {
sessKeyID int
keyLock sync.RWMutex
avaliable bool
available bool
}

func GetSessionID() (int, error) {
Expand All @@ -51,33 +52,75 @@ 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)
}

_, err = unix.KeyctlInt(unix.KEYCTL_LINK, keyID, sessKeyID, 0, 0)
if err != nil {
return 0, err
}

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)

return keyID, nil
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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")
}
Expand All @@ -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
}

Expand All @@ -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
}

Expand Down
33 changes: 30 additions & 3 deletions pkg/auth/keyring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,50 @@ 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)
}

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)
Expand All @@ -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
Expand Down Expand Up @@ -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)))
})
Expand Down

0 comments on commit ee9c16d

Please sign in to comment.