aboutsummaryrefslogtreecommitdiff
path: root/actions
diff options
context:
space:
mode:
Diffstat (limited to 'actions')
-rw-r--r--actions/config.go4
-rw-r--r--actions/context.go19
-rw-r--r--actions/policy.go89
-rw-r--r--actions/protector.go6
4 files changed, 91 insertions, 27 deletions
diff --git a/actions/config.go b/actions/config.go
index 7fdaf5b..6b019df 100644
--- a/actions/config.go
+++ b/actions/config.go
@@ -133,6 +133,10 @@ func getConfig() (*metadata.Config, error) {
config.Options.Filenames = metadata.DefaultOptions.Filenames
log.Printf("Falling back to filenames mode of %q", config.Options.Filenames)
}
+ if config.Options.PolicyVersion == 0 {
+ config.Options.PolicyVersion = metadata.DefaultOptions.PolicyVersion
+ log.Printf("Falling back to policy version of %d", config.Options.PolicyVersion)
+ }
if err := config.CheckValidity(); err != nil {
return nil, errors.Wrap(ErrBadConfigFile, err.Error())
diff --git a/actions/context.go b/actions/context.go
index 5a56789..f07f225 100644
--- a/actions/context.go
+++ b/actions/context.go
@@ -37,6 +37,7 @@ import (
"github.com/pkg/errors"
"github.com/google/fscrypt/filesystem"
+ "github.com/google/fscrypt/keyring"
"github.com/google/fscrypt/metadata"
"github.com/google/fscrypt/util"
)
@@ -57,10 +58,13 @@ type Context struct {
// modified after being loaded to customise parameters.
Config *metadata.Config
// Mount is the filesystem relative to which all Protectors and Policies
- // are added, edited, removed, and applied.
+ // are added, edited, removed, and applied, and to which policies using
+ // the filesystem keyring are provisioned.
Mount *filesystem.Mount
- // TargetUser is the user for which protectors are created and to whose
- // keyring policies are provisioned.
+ // TargetUser is the user for whom protectors are created, and to whose
+ // keyring policies using the user keyring are provisioned. It's also
+ // the user for whom the keys are claimed in the filesystem keyring when
+ // v2 policies are provisioned.
TargetUser *user.User
}
@@ -145,6 +149,15 @@ func (ctx *Context) getService() string {
return unix.FSCRYPT_KEY_DESC_PREFIX
}
+func (ctx *Context) getKeyringOptions() *keyring.Options {
+ return &keyring.Options{
+ Mount: ctx.Mount,
+ User: ctx.TargetUser,
+ Service: ctx.getService(),
+ UseFsKeyringForV1Policies: ctx.Config.GetUseFsKeyringForV1Policies(),
+ }
+}
+
// getProtectorOption returns the ProtectorOption for the protector on the
// context's mountpoint with the specified descriptor.
func (ctx *Context) getProtectorOption(protectorDescriptor string) *ProtectorOption {
diff --git a/actions/policy.go b/actions/policy.go
index 875a01f..41e108e 100644
--- a/actions/policy.go
+++ b/actions/policy.go
@@ -28,8 +28,8 @@ import (
"github.com/google/fscrypt/crypto"
"github.com/google/fscrypt/filesystem"
+ "github.com/google/fscrypt/keyring"
"github.com/google/fscrypt/metadata"
- "github.com/google/fscrypt/security"
"github.com/google/fscrypt/util"
)
@@ -44,8 +44,8 @@ var (
)
// PurgeAllPolicies removes all policy keys on the filesystem from the kernel
-// keyring. In order for this removal to have an effect, the filesystem should
-// also be unmounted.
+// keyring. In order for this to fully take effect, the filesystem may also need
+// to be unmounted or caches dropped.
func PurgeAllPolicies(ctx *Context) error {
if err := ctx.checkContext(); err != nil {
return err
@@ -56,12 +56,16 @@ func PurgeAllPolicies(ctx *Context) error {
}
for _, policyDescriptor := range policies {
- service := ctx.getService()
- err = security.RemoveKey(service+policyDescriptor, ctx.TargetUser)
-
+ err = keyring.RemoveEncryptionKey(policyDescriptor, ctx.getKeyringOptions(), false)
switch errors.Cause(err) {
- case nil, security.ErrKeySearch:
+ case nil, keyring.ErrKeyNotPresent:
// We don't care if the key has already been removed
+ case keyring.ErrKeyFilesOpen:
+ log.Printf("Key for policy %s couldn't be fully removed because some files are still in-use",
+ policyDescriptor)
+ case keyring.ErrKeyAddedByOtherUsers:
+ log.Printf("Key for policy %s couldn't be fully removed because other user(s) have added it too",
+ policyDescriptor)
default:
return err
}
@@ -94,11 +98,17 @@ func CreatePolicy(ctx *Context, protector *Protector) (*Policy, error) {
return nil, err
}
+ keyDescriptor, err := crypto.ComputeKeyDescriptor(key, ctx.Config.Options.PolicyVersion)
+ if err != nil {
+ key.Wipe()
+ return nil, err
+ }
+
policy := &Policy{
Context: ctx,
data: &metadata.PolicyData{
Options: ctx.Config.Options,
- KeyDescriptor: crypto.ComputeDescriptor(key),
+ KeyDescriptor: keyDescriptor,
},
key: key,
created: true,
@@ -188,17 +198,16 @@ func (policy *Policy) Descriptor() string {
return policy.data.KeyDescriptor
}
-// Description returns the description that will be used when the key for this
-// Policy is inserted into the keyring
-func (policy *Policy) Description() string {
- return policy.Context.getService() + policy.Descriptor()
-}
-
// Options returns the encryption options of this policy.
func (policy *Policy) Options() *metadata.EncryptionOptions {
return policy.data.Options
}
+// Version returns the version of this policy.
+func (policy *Policy) Version() int64 {
+ return policy.data.Options.PolicyVersion
+}
+
// Destroy removes a policy from the filesystem. The internal key should still
// be wiped with Lock().
func (policy *Policy) Destroy() error {
@@ -374,11 +383,24 @@ func (policy *Policy) Apply(path string) error {
return metadata.SetPolicy(path, policy.data)
}
-// IsProvisioned returns a boolean indicating if the policy has its key in the
-// keyring, meaning files and directories using this policy are accessible.
-func (policy *Policy) IsProvisioned() bool {
- _, err := security.FindKey(policy.Description(), policy.Context.TargetUser)
- return err == nil
+// GetProvisioningStatus returns the status of this policy's key in the keyring.
+func (policy *Policy) GetProvisioningStatus() keyring.KeyStatus {
+ status, _ := keyring.GetEncryptionKeyStatus(policy.Descriptor(),
+ policy.Context.getKeyringOptions())
+ return status
+}
+
+// IsProvisionedByTargetUser returns true if the policy's key is present in the
+// target kernel keyring, but not if that keyring is a filesystem keyring and
+// the key only been added by users other than Context.TargetUser.
+func (policy *Policy) IsProvisionedByTargetUser() bool {
+ return policy.GetProvisioningStatus() == keyring.KeyPresent
+}
+
+// IsFullyDeprovisioned returns true if the policy has been fully deprovisioned,
+// including by all users and with all files protected by it having been closed.
+func (policy *Policy) IsFullyDeprovisioned() bool {
+ return policy.GetProvisioningStatus() == keyring.KeyAbsent
}
// Provision inserts the Policy key into the kernel keyring. This allows reading
@@ -387,13 +409,34 @@ func (policy *Policy) Provision() error {
if policy.key == nil {
return ErrLocked
}
- return crypto.InsertPolicyKey(policy.key, policy.Description(), policy.Context.TargetUser)
+ return keyring.AddEncryptionKey(policy.key, policy.Descriptor(),
+ policy.Context.getKeyringOptions())
}
// Deprovision removes the Policy key from the kernel keyring. This prevents
-// reading and writing to the directory once the caches are cleared.
-func (policy *Policy) Deprovision() error {
- return security.RemoveKey(policy.Description(), policy.Context.TargetUser)
+// reading and writing to the directory --- unless the target keyring is a user
+// keyring, in which case caches must be dropped too.
+func (policy *Policy) Deprovision(allUsers bool) error {
+ return keyring.RemoveEncryptionKey(policy.Descriptor(),
+ policy.Context.getKeyringOptions(), allUsers)
+}
+
+// NeedsUserKeyring returns true if Provision and Deprovision for this policy
+// will use a user keyring, not a filesystem keyring.
+func (policy *Policy) NeedsUserKeyring() bool {
+ return policy.Version() == 1 && !policy.Context.Config.GetUseFsKeyringForV1Policies()
+}
+
+// NeedsRootToProvision returns true if Provision and Deprovision will require
+// root for this policy in the current configuration.
+func (policy *Policy) NeedsRootToProvision() bool {
+ return policy.Version() == 1 && policy.Context.Config.GetUseFsKeyringForV1Policies()
+}
+
+// CanBeAppliedWithoutProvisioning returns true if this process can apply this
+// policy to a directory without first calling Provision.
+func (policy *Policy) CanBeAppliedWithoutProvisioning() bool {
+ return policy.Version() == 1 || util.IsUserRoot()
}
// commitData writes the Policy's current data to the filesystem.
diff --git a/actions/protector.go b/actions/protector.go
index fe5d694..4bd7c15 100644
--- a/actions/protector.go
+++ b/actions/protector.go
@@ -140,7 +140,11 @@ func CreateProtector(ctx *Context, name string, keyFn KeyFunc) (*Protector, erro
if protector.key, err = crypto.NewRandomKey(metadata.InternalKeyLen); err != nil {
return nil, err
}
- protector.data.ProtectorDescriptor = crypto.ComputeDescriptor(protector.key)
+ protector.data.ProtectorDescriptor, err = crypto.ComputeKeyDescriptor(protector.key, 1)
+ if err != nil {
+ protector.Lock()
+ return nil, err
+ }
if err = protector.Rewrap(keyFn); err != nil {
protector.Lock()