jsipprell / keyctl

A Go-lang interface to the linux kernel keyring api

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Permission denied when extracting key data in UserSessionKeyring

DocLambda opened this issue · comments

When adding a key to the UserSessionKeyring and directly afterwards reading that key again, I get a permission denied trying to extract the data from the key. The following code triggers the issue

package main

import (
	"fmt"

	"github.com/jsipprell/keyctl"
)

func main() {
	name := "some-key"
	value := "lala"

	fmt.Println("accessing keyring")
	keyring, err := keyctl.UserSessionKeyring()
	if err != nil {
		panic(err)
	}

	fmt.Println("adding key")
	if _, err := keyring.Add(name, []byte(value)); err != nil {
		panic(err)
	}

	fmt.Println("searching key")
	key, err := keyring.Search(name)
	if err != nil {
		panic(err)
	}
	fmt.Printf("key: %v\n", key)

	fmt.Println("extracting key info")
	info, err := key.Info()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key info: %v\n", info)

	fmt.Println("extracting key data")
	data, err := key.Get()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key data: %v\n", data)
}

generating the following output

accessing keyring
adding key
searching key
key: &{some-key 814656017 -5 0 0}
extracting key info
key info: {key some-key <uid> <gid> alswrv-----v------------ true}
extracting key data
panic: permission denied

Interestingly when changing keyring, err := keyctl.UserSessionKeyring() to keyring, err := keyctl.SessionKeyring() the error goes away. If I generate the same key via commandline keyctl add user some-data foo @u, and omit the keyring.Add() call I can extract the data successfully even though the permissions look identical.

Any idea what's going on?

Tracked down the reason too restrictive standard permissions. When creating a key (or a keyring) in the user-session keyring it has the default permissions of alswrv-----v------------. Unfortunately, we loose possession of that key (or keyring) immediately after creation preventing us from changing those permission (as user has only read permission).

Using PR #7 providing the Link() function we can work-around the problem by creating the key in the session keyring. There we will keep the possession of the key and are able to change the permission. Afterwards, we link the generated key to the final keyring (user-session) and unlink from session keyring. This procedure solves the issue and also works for named keyrings etc.

Here the working code (requires #7):

package main

import (
        "fmt"

        "github.com/jsipprell/keyctl"
)

func main() {
        name := "some-key"
        value := "lala"

        fmt.Println("accessing keyring")
        keyring, err := keyctl.UserSessionKeyring()
        if err != nil {
                panic(err)
        }

        fmt.Println("opening session keyring")
        session, err := keyctl.SessionKeyring()
        if err != nil {
                panic(err)
        }

        fmt.Println("adding key to session")
        key, err := session.Add(name, []byte(value))
        if err != nil {
                panic(err)
        }

        perm := keyctl.PermUserAll | keyctl.PermProcessAll
        fmt.Printf("setting key perm to %q\n", perm)
        if err:= keyctl.SetPerm(key, perm); err != nil {
                panic(err)
        }

        fmt.Println("linking key to keyring")
	       if err := keyctl.Link(keyring, key); err != nil {
                panic(err)
	             }

        fmt.Println("unlinking key from session")
	      if err := keyctl.Unlink(session, key); err != nil {
                panic(err)
        }

        fmt.Println("searching key")
        key, err = keyring.Search(name)
        if err != nil {
                panic(err)
        }
        fmt.Printf("key: %v\n", key)

        fmt.Println("extracting key info")
        info, err := key.Info()
        if err != nil {
                panic(err)
        }
        fmt.Printf("key info: %v\n", info)

        fmt.Println("extracting key data")
        data, err := key.Get()
        if err != nil {
                panic(err)
        }
        fmt.Printf("key data: %v\n", data)
}