* `fscrypt setup MOUNTPOINT` - Gets a filesystem ready for use with fscrypt
* `fscrypt encrypt DIRECTORY` - Encrypts an empty directory
* `fscrypt unlock DIRECTORY` - Unlocks an encrypted directory
-* `fscrypt purge MOUNTPOINT` - Removes keys for a filesystem before unmounting
+* `fscrypt lock DIRECTORY` - Locks an encrypted directory
+* `fscrypt purge MOUNTPOINT` - Locks all encrypted directories on a filesystem
* `fscrypt status [PATH]` - Gets detailed info about filesystems or paths
* `fscrypt metadata` - Manages policies or protectors directly
PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"
-# Purging a filesystem locks all the files.
->>>>> sudo fscrypt purge /mnt/disk --user=$USER
-WARNING: Encrypted data on this filesystem will be inaccessible until unlocked again!!
-Purge all policy keys from "/mnt/disk" and drop global inode cache? [y/N] y
-Policies purged for "/mnt/disk".
-
+# Lock the directory.
+>>>>> sudo fscrypt lock /mnt/disk/dir1 --user=$USER
+Encrypted data removed from filesystem cache.
+"/mnt/disk/dir1" is now locked.
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
#### Quiet Version
```bash
->>>>> sudo fscrypt purge /mnt/disk --user=$USER --quiet --force
+>>>>> sudo fscrypt lock /mnt/disk/dir1 --quiet --user=$USER
>>>>> echo "hunter2" | fscrypt unlock /mnt/disk/dir1 --quiet
```
appropriate key into the keyring. This requires unlocking one of
the protectors protecting this directory (either by selecting a
protector or specifying one with %s). This directory will be
- locked again upon reboot, or after running "fscrypt purge" and
- unmounting the corresponding filesystem.`, directoryArg,
+ locked again upon reboot, or after running "fscrypt lock" or
+ "fscrypt purge".`, directoryArg,
shortDisplay(unlockWithFlag)),
Flags: []cli.Flag{unlockWithFlag, keyFileFlag, userFlag},
Action: unlockAction,
return nil
}
+func dropCachesIfRequested(c *cli.Context, ctx *actions.Context) error {
+ if dropCachesFlag.Value {
+ if err := security.DropFilesystemCache(); err != nil {
+ return err
+ }
+ fmt.Fprintf(c.App.Writer, "Encrypted data removed from filesystem cache.\n")
+ } else {
+ fmt.Fprintf(c.App.Writer, "Filesystem %q should now be unmounted.\n", ctx.Mount.Path)
+ }
+ return nil
+}
+
+// Lock takes an encrypted directory and locks it, undoing Unlock.
+var Lock = cli.Command{
+ Name: "lock",
+ ArgsUsage: directoryArg,
+ Usage: "lock an encrypted directory",
+ Description: fmt.Sprintf(`This command takes %s, an encrypted directory
+ which has been unlocked by fscrypt, and locks the directory by
+ removing the encryption key from the kernel. I.e., it undoes the
+ effect of 'fscrypt unlock'.
+
+ For this to be effective, all files in the directory must first
+ be closed.
+
+ The %s=true option may be needed to properly lock the directory.
+ Root is required for this.
+
+ WARNING: even after the key has been removed, decrypted data may
+ still be present in freed memory, where it may still be
+ recoverable by an attacker who compromises system memory. To be
+ fully safe, you must reboot with a power cycle.`,
+ directoryArg, shortDisplay(dropCachesFlag)),
+ Flags: []cli.Flag{dropCachesFlag, userFlag},
+ Action: lockAction,
+}
+
+func lockAction(c *cli.Context) error {
+ if c.NArg() != 1 {
+ return expectedArgsErr(c, 1, false)
+ }
+
+ targetUser, err := parseUserFlag(true)
+ if err != nil {
+ return newExitError(c, err)
+ }
+ path := c.Args().Get(0)
+ ctx, err := actions.NewContextFromPath(path, targetUser)
+ if err != nil {
+ return newExitError(c, err)
+ }
+
+ log.Printf("performing sanity checks")
+ // Ensure path is encrypted and filesystem is using fscrypt.
+ policy, err := actions.GetPolicyFromPath(ctx, path)
+ if err != nil {
+ return newExitError(c, err)
+ }
+ // Check if directory is already locked
+ if policy.IsFullyDeprovisioned() {
+ log.Printf("policy %s is already fully deprovisioned", policy.Descriptor())
+ return newExitError(c, errors.Wrapf(ErrPolicyLocked, path))
+ }
+ // Check for permission to drop caches, if it will be needed.
+ if policy.NeedsUserKeyring() && dropCachesFlag.Value && !util.IsUserRoot() {
+ return newExitError(c, ErrDropCachesPerm)
+ }
+
+ if err = policy.Deprovision(); err != nil {
+ return newExitError(c, err)
+ }
+
+ if policy.NeedsUserKeyring() {
+ if err = dropCachesIfRequested(c, ctx); err != nil {
+ return newExitError(c, err)
+ }
+ }
+
+ fmt.Fprintf(c.App.Writer, "%q is now locked.\n", path)
+ return nil
+}
+
// Purge removes all the policy keys from the keyring (also need unmount).
var Purge = cli.Command{
Name: "purge",
}
fmt.Fprintf(c.App.Writer, "Policies purged for %q.\n", ctx.Mount.Path)
- if dropCachesFlag.Value {
- if err = security.DropFilesystemCache(); err != nil {
- return newExitError(c, err)
- }
- fmt.Fprintf(c.App.Writer, "Encrypted data removed from filesystem cache.\n")
- } else {
- fmt.Fprintf(c.App.Writer, "Filesystem %q should now be unmounted.\n", ctx.Mount.Path)
+ if err = dropCachesIfRequested(c, ctx); err != nil {
+ return newExitError(c, err)
}
return nil
}
ErrAllLoadsFailed = errors.New("could not load any protectors")
ErrMustBeRoot = errors.New("this command must be run as root")
ErrPolicyUnlocked = errors.New("this file or directory is already unlocked")
+ ErrPolicyLocked = errors.New("this file or directory is already locked")
ErrBadOwners = errors.New("you do not own this directory")
ErrNotEmptyDir = errors.New("not an empty directory")
ErrNotPassphrase = errors.New("protector does not use a passphrase")
needs to be enabled for this filesystem. See the
documentation on how to enable encryption on ext4
systems (and the risks of doing so).`
+ case keyring.ErrKeyFilesOpen:
+ return `Directory was incompletely locked because some files are
+ still open. These files remain accessible. Try killing
+ any processes using files in the directory, then
+ re-running 'fscrypt lock'.`
case keyring.ErrSessionUserKeying:
return `This is usually the result of a bad PAM configuration.
Either correct the problem in your PAM stack, enable