From 0c82bbeaee765cabf45a0f293ee87f45a7004a16 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 12 Aug 2019 14:35:20 -0400 Subject: [PATCH] move keyctl to internal & func remove auth from keyring Move pkg/keyctl to internal/pkg/keyctl. Add method removeAllAuthFromKeyring. Get key describes from keyring using KEYCTL_READ and KEYCTL_DESCRIBE, and remove them from keyring if the decription has prefix 'container-registry-login:'. Signed-off-by: Qi Wang --- {pkg => internal/pkg}/keyctl/key.go | 9 +++ {pkg => internal/pkg}/keyctl/keyring.go | 41 ++++++++++++++ {pkg => internal/pkg}/keyctl/keyring_test.go | 58 ++++++++++++++++++++ {pkg => internal/pkg}/keyctl/perm.go | 0 {pkg => internal/pkg}/keyctl/sys_linux.go | 0 pkg/docker/config/config.go | 10 +++- pkg/docker/config/config_linux.go | 40 +++++++++++++- pkg/docker/config/config_unsupported.go | 4 ++ 8 files changed, 159 insertions(+), 3 deletions(-) rename {pkg => internal/pkg}/keyctl/key.go (83%) rename {pkg => internal/pkg}/keyctl/keyring.go (69%) rename {pkg => internal/pkg}/keyctl/keyring_test.go (68%) rename {pkg => internal/pkg}/keyctl/perm.go (100%) rename {pkg => internal/pkg}/keyctl/sys_linux.go (100%) diff --git a/pkg/keyctl/key.go b/internal/pkg/keyctl/key.go similarity index 83% rename from pkg/keyctl/key.go rename to internal/pkg/keyctl/key.go index e4396a9df7..88e123cdd1 100644 --- a/pkg/keyctl/key.go +++ b/internal/pkg/keyctl/key.go @@ -62,3 +62,12 @@ func (k *Key) Unlink() error { _, err := unix.KeyctlInt(unix.KEYCTL_UNLINK, int(k.id), int(k.ring), 0, 0) return err } + +// Describe returns a string describing the attributes of a specified key +func (k *Key) Describe() (string, error) { + keyAttr, err := unix.KeyctlString(unix.KEYCTL_DESCRIBE, int(k.id)) + if err != nil { + return "", err + } + return keyAttr, nil +} diff --git a/pkg/keyctl/keyring.go b/internal/pkg/keyctl/keyring.go similarity index 69% rename from pkg/keyctl/keyring.go rename to internal/pkg/keyctl/keyring.go index 6e029c9235..4bf1701562 100644 --- a/pkg/keyctl/keyring.go +++ b/internal/pkg/keyctl/keyring.go @@ -11,6 +11,8 @@ package keyctl import ( + "unsafe" + "golang.org/x/sys/unix" ) @@ -77,3 +79,42 @@ func Link(parent Keyring, child ID) error { _, err := unix.KeyctlInt(unix.KEYCTL_LINK, int(child.ID()), int(parent.ID()), 0, 0) return err } + +// ReadUserKeyring reads user keyring and returns slice of key with id(key_serial_t) representing the IDs of all the keys that are linked to it +func ReadUserKeyring() ([]*Key, error) { + var ( + b []byte + err error + sizeRead int + ) + krSize := 4 + size := krSize + b = make([]byte, size) + sizeRead = size + 1 + for sizeRead > size { + r1, err := unix.KeyctlBuffer(unix.KEYCTL_READ, unix.KEY_SPEC_USER_KEYRING, b, size) + if err != nil { + return nil, err + } + + if sizeRead = int(r1); sizeRead > size { + b = make([]byte, sizeRead) + size = sizeRead + sizeRead = size + 1 + } else { + krSize = sizeRead + } + } + keyIDs := getKeyIDsFromByte(b[:krSize]) + return keyIDs, err +} + +func getKeyIDsFromByte(byteKeyIDs []byte) []*Key { + idSize := 4 + var keys []*Key + for idx := 0; idx+idSize <= len(byteKeyIDs); idx = idx + idSize { + tempID := *(*int32)(unsafe.Pointer(&byteKeyIDs[idx])) + keys = append(keys, &Key{id: keyID(tempID)}) + } + return keys +} diff --git a/pkg/keyctl/keyring_test.go b/internal/pkg/keyctl/keyring_test.go similarity index 68% rename from pkg/keyctl/keyring_test.go rename to internal/pkg/keyctl/keyring_test.go index b6d293ac24..b89db7b321 100644 --- a/pkg/keyctl/keyring_test.go +++ b/internal/pkg/keyctl/keyring_test.go @@ -4,6 +4,7 @@ package keyctl import ( "crypto/rand" + "strings" "testing" ) @@ -143,3 +144,60 @@ func TestUnlink(t *testing.T) { t.Fatal(err) } } + +func TestReadKeyring(t *testing.T) { + token := make([]byte, 20) + rand.Read(token) + + testname := "testuser" + + userKeyring, err := UserKeyring() + if err != nil { + t.Fatal(err) + } + + userKey, err := userKeyring.Add(testname, token) + if err != nil { + t.Fatal(err, userKey) + } + keys, err := ReadUserKeyring() + if err != nil { + t.Fatal(err) + } + expectedKeyLen := 1 + if len(keys) != 1 { + t.Errorf("expected to read %d userkeyring, but get %d", expectedKeyLen, len(keys)) + } + err = Unlink(userKeyring, userKey) + if err != nil { + t.Fatal(err) + } +} + +func TestDescribe(t *testing.T) { + token := make([]byte, 20) + rand.Read(token) + + testname := "testuser" + + userKeyring, err := UserKeyring() + if err != nil { + t.Fatal(err) + } + + userKey, err := userKeyring.Add(testname, token) + if err != nil { + t.Fatal(err, userKey) + } + keyAttr, err := userKey.Describe() + if err != nil { + t.Fatal(err) + } + if !strings.Contains(keyAttr, testname) { + t.Errorf("expect description contains %s, but get %s", testname, keyAttr) + } + err = Unlink(userKeyring, userKey) + if err != nil { + t.Fatal(err) + } +} diff --git a/pkg/keyctl/perm.go b/internal/pkg/keyctl/perm.go similarity index 100% rename from pkg/keyctl/perm.go rename to internal/pkg/keyctl/perm.go diff --git a/pkg/keyctl/sys_linux.go b/internal/pkg/keyctl/sys_linux.go similarity index 100% rename from pkg/keyctl/sys_linux.go rename to internal/pkg/keyctl/sys_linux.go diff --git a/pkg/docker/config/config.go b/pkg/docker/config/config.go index eef629d5c6..5ab6ba649e 100644 --- a/pkg/docker/config/config.go +++ b/pkg/docker/config/config.go @@ -142,9 +142,17 @@ func RemoveAuthentication(sys *types.SystemContext, registry string) error { }) } -// RemoveAllAuthentication deletes all the credentials stored in auth.json +// RemoveAllAuthentication deletes all the credentials stored in auth.json and kernel keyring func RemoveAllAuthentication(sys *types.SystemContext) error { return modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) { + if enableKeyring { + err := removeAllAuthFromKernelKeyring() + if err == nil { + logrus.Debugf("removing all credentials from kernel keyring") + return false, nil + } + logrus.Debugf("error removing credentials from kernel keyring") + } auths.CredHelpers = make(map[string]string) auths.AuthConfigs = make(map[string]dockerAuthConfig) return true, nil diff --git a/pkg/docker/config/config_linux.go b/pkg/docker/config/config_linux.go index 4d66a50df5..7a49b6cb69 100644 --- a/pkg/docker/config/config_linux.go +++ b/pkg/docker/config/config_linux.go @@ -4,10 +4,13 @@ import ( "fmt" "strings" - "github.com/containers/image/pkg/keyctl" + "github.com/containers/image/internal/pkg/keyctl" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) +const keyDescribePrefix = "container-registry-login:" + func getAuthFromKernelKeyring(registry string) (string, string, error) { userkeyring, err := keyctl.UserKeyring() if err != nil { @@ -41,6 +44,39 @@ func deleteAuthFromKernelKeyring(registry string) error { return key.Unlink() } +func removeAllAuthFromKernelKeyring() error { + keys, err := keyctl.ReadUserKeyring() + if err != nil { + return err + } + + userkeyring, err := keyctl.UserKeyring() + if err != nil { + return err + } + + for _, k := range keys { + keyAttr, err := k.Describe() + if err != nil { + return err + } + // split string "type;uid;gid;perm;description" + keyAttrs := strings.SplitN(keyAttr, ";", 5) + if len(keyAttrs) < 5 { + return errors.Errorf("Key attributes of %d are not avaliable", k.ID()) + } + keyDescribe := keyAttrs[4] + if strings.HasPrefix(keyDescribe, keyDescribePrefix) { + err := keyctl.Unlink(userkeyring, k) + if err != nil { + return errors.Wrapf(err, "error unlinking key %d", k.ID()) + } + logrus.Debugf("unlinked key %d:%s", k.ID(), keyAttr) + } + } + return nil +} + func setAuthToKernelKeyring(registry, username, password string) error { keyring, err := keyctl.SessionKeyring() if err != nil { @@ -75,5 +111,5 @@ func setAuthToKernelKeyring(registry, username, password string) error { } func genDescription(registry string) string { - return fmt.Sprintf("container-registry-login:%s", registry) + return fmt.Sprintf("%s%s", keyDescribePrefix, registry) } diff --git a/pkg/docker/config/config_unsupported.go b/pkg/docker/config/config_unsupported.go index 1c1a02511c..9b0e8bee25 100644 --- a/pkg/docker/config/config_unsupported.go +++ b/pkg/docker/config/config_unsupported.go @@ -14,3 +14,7 @@ func deleteAuthFromKernelKeyring(registry string) error { func setAuthToKernelKeyring(registry, username, password string) error { return ErrNotSupported } + +func removeAllAuthFromKernelKeyring() error { + return ErrNotSupported +}