- [Building and installing](#building-and-installing)
- [Runtime dependencies](#runtime-dependencies)
- [Configuration file](#configuration-file)
+- [Setting up `fscrypt` on a filesystem](#setting-up-fscrypt-on-a-filesystem)
- [Setting up for login protectors](#setting-up-for-login-protectors)
- [Securing your login passphrase](#securing-your-login-passphrase)
- [Enabling the PAM module](#enabling-the-pam-module)
kernels, it's better to not use this setting and instead (re-)create your
encrypted directories with `"policy_version": "2"`.
+## Setting up `fscrypt` on a filesystem
+
+`fscrypt` needs some directories to exist on the filesystem on which encryption
+will be used:
+
+* `MOUNTPOINT/.fscrypt/policies`
+* `MOUNTPOINT/.fscrypt/protectors`
+
+(If login protectors are used, these must also exist on the root filesystem.)
+
+To create these directories, run `fscrypt setup MOUNTPOINT`. If MOUNTPOINT is
+owned by root, as is usually the case, then this command will require root.
+
+There will be one decision you'll need to make: whether non-root users will be
+allowed to create `fscrypt` metadata (policies and protectors).
+
+If you say `y`, then these directories will be made world-writable, with the
+sticky bit set so that users can't delete each other's files -- just like
+`/tmp`. If you say `N`, then these directories will be writable only by root.
+
+Saying `y` maximizes the usability of `fscrypt`, and on most systems it's fine
+to say `y`. However, on some systems this may be inappropriate, as it will
+allow malicious users to fill the entire filesystem unless filesystem quotas
+have been configured -- similar to problems that have historically existed with
+other world-writable directories, e.g. `/tmp`. If you are concerned about this,
+say `N`. If you say `N`, then you'll only be able to run `fscrypt` as root to
+set up encryption on users' behalf, unless you manually set custom permissions
+on the metadata directories to grant write access to specific users or groups.
+
+If you chose the wrong mode at `fscrypt setup` time, you can change the
+directory permissions at any time. To enable single-user writable mode, run:
+
+ sudo chmod 0755 MOUNTPOINT/.fscrypt/*
+
+To enable world-writable mode, run:
+
+ sudo chmod 1777 MOUNTPOINT/.fscrypt/*
+
## Setting up for login protectors
If you want any encrypted directories to be protected by your login passphrase,
Defaulting to policy_version 2 because kernel supports it.
Customizing passphrase hashing difficulty for this system...
Created global config file at "/etc/fscrypt.conf".
-Metadata directories created at "/.fscrypt".
+Allow users other than root to create fscrypt metadata on the root filesystem?
+(See https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem) [y/N] y
+Metadata directories created at "/.fscrypt", writable by everyone.
# Start using fscrypt with our filesystem
->>>>> fscrypt setup /mnt/disk
-Metadata directories created at "/mnt/disk/.fscrypt".
+>>>>> sudo fscrypt setup /mnt/disk
+Allow users other than root to create fscrypt metadata on this filesystem? (See
+https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem) [y/N] y
+Metadata directories created at "/mnt/disk/.fscrypt", writable by everyone.
# Initialize encryption on a new empty directory
>>>>> mkdir /mnt/disk/dir1
#### Quiet version
```bash
->>>>> sudo fscrypt setup --quiet --force
->>>>> fscrypt setup /mnt/disk --quiet
+>>>>> sudo fscrypt setup --quiet --force --all-users
+>>>>> sudo fscrypt setup /mnt/disk --quiet --all-users
>>>>> echo "hunter2" | fscrypt encrypt /mnt/disk/dir1 --quiet --source=custom_passphrase --name="Super Secret"
```
"testing"
"time"
+ "github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/util"
"github.com/pkg/errors"
)
return nil, err
}
- return ctx, ctx.Mount.Setup()
+ return ctx, ctx.Mount.Setup(filesystem.WorldWritable)
}
// Cleans up the testing config file and testing filesystem data.
# Give the tests their own fscrypt.conf.
export FSCRYPT_CONF="$TMPDIR/fscrypt.conf"
- fscrypt setup --time=1ms > /dev/null
+ fscrypt setup --time=1ms --quiet --all-users > /dev/null
# The tests assume kernel support for v2 policies.
if ! grep -q '"policy_version": "2"' "$FSCRYPT_CONF"; then
fi
# Set up the test filesystems that aren't already set up.
- fscrypt setup "$MNT" > /dev/null
+ fscrypt setup --quiet --all-users "$MNT" > /dev/null
}
run_test()
# Try to encrypt a nonexistent directory
[ERROR] fscrypt encrypt: no such file or directory
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
Caution: due to the nature of modern storage devices and filesystems, the
original data may still be recoverable from disk. It's much better to encrypt
your files from the start.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
Caution: due to the nature of modern storage devices and filesystems, the
original data may still be recoverable from disk. It's much better to encrypt
your files from the start.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
# Encrypt a directory as non-root user
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "prot"
Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "prot"
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "prot"
Encryption can only be enabled on a directory you own,
even if you have write access to the directory.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
# Encrypt with custom passphrase protector
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "prot"
Enter custom passphrase for protector "prot": \r
Confirm passphrase: \r
"MNT/dir" is now encrypted, unlocked, and ready for use.\r
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc6 No custom protector "prot"
[ERROR] fscrypt encrypt: custom_passphrase protectors must be named
Use --name=PROTECTOR_NAME to specify a protector name.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
will lose access to this directory if you reinstall the operating
system or move this filesystem to another system.
-ext4 filesystem "MNT" has 2 protectors and 1 policy
+ext4 filesystem "MNT" has 2 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 Yes (MNT_ROOT) login protector for fscrypt-test-user
POLICY UNLOCKED PROTECTORS
desc3 Yes desc1, desc2
-ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies
+ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No login protector for fscrypt-test-user
system or move this filesystem to another system.\r
\r
"MNT/dir" is now encrypted, unlocked, and ready for use.\r
-ext4 filesystem "MNT" has 2 protectors and 1 policy
+ext4 filesystem "MNT" has 2 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc10 Yes (MNT_ROOT) login protector for fscrypt-test-user
POLICY UNLOCKED PROTECTORS
desc12 Yes desc10, desc11
-ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies
+ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc10 No login protector for fscrypt-test-user
will lose access to this directory if you reinstall the operating
system or move this filesystem to another system.
-ext4 filesystem "MNT" has 2 protectors and 1 policy
+ext4 filesystem "MNT" has 2 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc19 Yes (MNT_ROOT) login protector for fscrypt-test-user
POLICY UNLOCKED PROTECTORS
desc21 Yes desc19, desc20
-ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies
+ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc19 No login protector for fscrypt-test-user
Protector is owned by fscrypt-test-user:fscrypt-test-user
# Encrypt with login protector with --no-recovery
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc28 Yes (MNT_ROOT) login protector for fscrypt-test-user
POLICY UNLOCKED PROTECTORS
desc29 Yes desc28
-ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies
+ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc28 No login protector for fscrypt-test-user
Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
desc35 No login protector for fscrypt-test-user
-ext4 filesystem "MNT_ROOT" has 1 protector and 1 policy
+ext4 filesystem "MNT_ROOT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc35 No login protector for fscrypt-test-user
identified by user, not by name.
To fix this, don't specify the --name=PROTECTOR_NAME option.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
-ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies
+ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
# Try to use the wrong login passphrase
[ERROR] fscrypt encrypt: incorrect login passphrase
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
-ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies
+ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
will lose access to this directory if you reinstall the operating
system or move this filesystem to another system.
-ext4 filesystem "MNT" has 2 protectors and 1 policy
+ext4 filesystem "MNT" has 2 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc39 No custom protector "Recovery passphrase for dir"
# Encrypt with raw_key protector from file
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No raw key protector "prot"
desc1 No raw key protector "prot"
# Encrypt with raw_key protector from stdin
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc6 No raw key protector "prot"
# Try to encrypt with raw_key protector from file, using wrong key length
[ERROR] fscrypt encrypt: TMPDIR/raw_key: key file must be 32 bytes
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
# Try to encrypt with raw_key protector from stdin, using wrong key length
[ERROR] fscrypt encrypt: unexpected EOF
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
[ERROR] fscrypt status: file or directory "MNT/dir" is not
encrypted
# Encrypt with raw_key protector from file, unlock from stdin
"MNT/dir" is now locked.
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc11 No raw key protector "prot"
-ext4 filesystem "MNT" has 3 protectors and 1 policy
+ext4 filesystem "MNT" has 3 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "foo"
POLICY UNLOCKED PROTECTORS
desc4 No desc1, desc2, desc3
-ext4 filesystem "MNT" has 2 protectors and 1 policy
+ext4 filesystem "MNT" has 2 protectors and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc1 No custom protector "foo"
mount tmpfs -t tmpfs -o size=128m "$MNT"
_print_header "Try to create fscrypt metadata on tmpfs"
-_expect_failure "fscrypt setup '$MNT'"
+_expect_failure "fscrypt setup --quiet '$MNT'"
_print_header "Try to encrypt a directory on tmpfs"
mkdir "$MNT/dir"
Defaulting to policy_version 2 because kernel supports it.
Customizing passphrase hashing difficulty for this system...
Created global config file at "FSCRYPT_CONF".
-Metadata directories created at "MNT_ROOT/.fscrypt".
+Allow users other than root to create fscrypt metadata on this filesystem? (See
+https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem) [y/N] Metadata directories created at "MNT_ROOT/.fscrypt", writable by everyone.
# fscrypt setup when fscrypt.conf already exists (cancel)
Replace "FSCRYPT_CONF"? [y/N] [ERROR] fscrypt setup: operation canceled
# fscrypt setup --quiet --force when fscrypt.conf already exists
# fscrypt setup filesystem
-Metadata directories created at "MNT/.fscrypt".
+Allow users other than root to create fscrypt metadata on this filesystem? (See
+https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem) [y/N] Metadata directories created at "MNT/.fscrypt", writable by everyone.
# fscrypt setup filesystem (already set up)
[ERROR] fscrypt setup: filesystem MNT is already setup for
_print_header "fscrypt setup creates fscrypt.conf and /.fscrypt"
_rm_metadata "$MNT_ROOT"
rm -f "$FSCRYPT_CONF"
-fscrypt setup --time=1ms
+echo y | fscrypt setup --time=1ms
[ -e "$MNT_ROOT/.fscrypt" ]
_print_header "fscrypt setup when fscrypt.conf already exists (cancel)"
_print_header "fscrypt setup filesystem"
_rm_metadata "$MNT"
-fscrypt setup "$MNT"
+echo y | fscrypt setup "$MNT"
[ -e "$MNT/.fscrypt" ]
_print_header "fscrypt setup filesystem (already set up)"
--- /dev/null
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+Only root can create fscrypt metadata on this filesystem.
+
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+Only root can create fscrypt metadata on this filesystem.
+
+
+# Encrypt, lock, and unlock as root
+"MNT/dir" is now locked.
+
+# Encrypt as root with user's login protector
+
+IMPORTANT: See "MNT/dir/fscrypt_recovery_readme.txt" for
+ important recovery instructions. It is *strongly recommended* to
+ record the recovery passphrase in a secure location; otherwise you
+ will lose access to this directory if you reinstall the operating
+ system or move this filesystem to another system.
+
+Protector desc1 no longer protecting policy desc2.
+"MNT/dir" is now locked.
+Enter login passphrase for fscrypt-test-user: "MNT/dir" is now unlocked and ready for use.
+
+# Encrypt as user (should fail)
+[ERROR] fscrypt encrypt: user lacks permission to create fscrypt metadata on
+ MNT
+
+For how to allow users to create fscrypt metadata on a filesystem, refer to
+https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem
+
+# Encrypt as user if they set up filesystem (should succeed)
--- /dev/null
+#!/bin/bash
+
+# Test 'fscrypt setup' without --all-users.
+
+cd "$(dirname "$0")"
+. common.sh
+
+_rm_metadata "$MNT_ROOT"
+_rm_metadata "$MNT"
+rm "$FSCRYPT_CONF"
+fscrypt setup --time=1ms --quiet
+fscrypt setup --time=1ms --quiet "$MNT"
+fscrypt status "$MNT"
+_user_do "fscrypt status \"$MNT\""
+
+dir=$MNT/dir
+
+begin()
+{
+ _reset_filesystems
+ mkdir "$dir"
+ _print_header "$1"
+}
+
+begin "Encrypt, lock, and unlock as root"
+echo hunter2 | fscrypt encrypt --quiet --name=dir --skip-unlock "$dir"
+echo hunter2 | fscrypt unlock --quiet "$dir"
+fscrypt lock "$dir"
+
+begin "Encrypt as root with user's login protector"
+echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase --user="$TEST_USER" "$dir"
+# The user should be able to update the policy and protectors created by the
+# above command themselves. The easiest way to test this is by updating the
+# policy to remove the auto-generated recovery protector. This verifies that
+# (a) the policy was made owned by the user, and that (b) policy updates fall
+# back to overwrites when the process cannot write to the containing directory.
+# (It would be better to test updating the protectors too, but this is the
+# easiest test to do here.)
+policy=$(fscrypt status "$dir" | awk '/Policy/{print $2}')
+recovery_protector=$(_get_protector_descriptor "$MNT" custom 'Recovery passphrase for dir')
+_user_do "fscrypt metadata remove-protector-from-policy --force --protector=$MNT:$recovery_protector --policy=$MNT:$policy"
+chown "$TEST_USER" "$dir"
+_user_do "fscrypt lock $dir"
+_user_do "echo TEST_USER_PASS | fscrypt unlock $dir"
+
+begin "Encrypt as user (should fail)"
+chown "$TEST_USER" "$dir"
+_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=dir --skip-unlock \"$dir\""
+
+begin "Encrypt as user if they set up filesystem (should succeed)"
+_rm_metadata "$MNT"
+chown "$TEST_USER" "$MNT"
+chown "$TEST_USER" "$dir"
+_user_do "fscrypt setup --time=1ms --quiet $MNT"
+_user_do "echo hunter2 | fscrypt encrypt --quiet --name=dir3 --skip-unlock \"$dir\""
ext4 supported Yes
# Get status of setup mountpoint
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
-ext4 filesystem "MNT" has 0 protectors and 0 policies
+ext4 filesystem "MNT" has 0 protectors and 0 policies.
+All users can create fscrypt metadata on this filesystem.
# Get status of unencrypted directory on setup mountpoint
Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
desc2 No custom protector "prot"
-ext4 filesystem "MNT" has 1 protector and 1 policy
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
PROTECTOR LINKED DESCRIPTION
desc2 No custom protector "prot"
the README). This may require root privileges.`,
mountpointArg, actions.ConfigFileLocation,
shortDisplay(timeTargetFlag)),
- Flags: []cli.Flag{timeTargetFlag, forceFlag},
+ Flags: []cli.Flag{timeTargetFlag, forceFlag, allUsersSetupFlag},
Action: setupAction,
}
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, allUsersFlag},
+ Flags: []cli.Flag{dropCachesFlag, userFlag, allUsersLockFlag},
Action: lockAction,
}
return newExitError(c, ErrDropCachesPerm)
}
- if err = policy.Deprovision(allUsersFlag.Value); err != nil {
+ if err = policy.Deprovision(allUsersLockFlag.Value); err != nil {
switch err {
case keyring.ErrKeyNotPresent:
break
}
}
return ""
+ case *filesystem.ErrNoCreatePermission:
+ return `For how to allow users to create fscrypt metadata on a
+ filesystem, refer to
+ https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem`
case *filesystem.ErrNotSetup:
return fmt.Sprintf(`Run "sudo fscrypt setup %s" to use fscrypt
on this filesystem.`, e.Mount.Path)
allFlags = []prettyFlag{helpFlag, versionFlag, verboseFlag, quietFlag,
forceFlag, skipUnlockFlag, timeTargetFlag,
sourceFlag, nameFlag, keyFileFlag, protectorFlag,
- unlockWithFlag, policyFlag, allUsersFlag, noRecoveryFlag}
+ unlockWithFlag, policyFlag, allUsersLockFlag, allUsersSetupFlag,
+ noRecoveryFlag}
// universalFlags contains flags that should be on every command
universalFlags = []cli.Flag{verboseFlag, quietFlag, helpFlag}
)
privileges.`,
Default: true,
}
- allUsersFlag = &boolFlag{
+ allUsersLockFlag = &boolFlag{
Name: "all-users",
Usage: `Lock the directory no matter which user(s) have unlocked
it. Requires root privileges. This flag is only
different from the one you're locking it as. This flag
is only implemented for v2 encryption policies.`,
}
+ allUsersSetupFlag = &boolFlag{
+ Name: "all-users",
+ Usage: `When setting up a filesystem for fscrypt, allow users
+ other than the calling user (typically root) to create
+ fscrypt policies and protectors on the filesystem. Note
+ that this will create a world-writable directory, which
+ users could use to fill up the entire filesystem. Hence,
+ this option may not be appropriate for some systems.`,
+ }
noRecoveryFlag = &boolFlag{
Name: "no-recovery",
Usage: `Don't generate a recovery passphrase.`,
"os"
"github.com/google/fscrypt/actions"
+ "github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/util"
)
if err != nil {
return err
}
+ username := ctx.TargetUser.Username
- if err = ctx.Mount.Setup(); err != nil {
+ err = ctx.Mount.CheckSetup()
+ if err == nil {
+ return &filesystem.ErrAlreadySetup{Mount: ctx.Mount}
+ }
+ if _, ok := err.(*filesystem.ErrNotSetup); !ok {
return err
}
- fmt.Fprintf(w, "Metadata directories created at %q.\n", ctx.Mount.BaseDir())
+ allUsers := allUsersSetupFlag.Value
+ if !allUsers {
+ thisFilesystem := "this filesystem"
+ if ctx.Mount.Path == "/" {
+ thisFilesystem = "the root filesystem"
+ }
+ prompt := fmt.Sprintf(`Allow users other than %s to create
+fscrypt metadata on %s? (See
+https://github.com/google/fscrypt#setting-up-fscrypt-on-a-filesystem)`,
+ username, thisFilesystem)
+ allUsers, err = askQuestion(wrapText(prompt, 0), false)
+ if err != nil {
+ return err
+ }
+ }
+ var setupMode filesystem.SetupMode
+ if allUsers {
+ setupMode = filesystem.WorldWritable
+ } else {
+ setupMode = filesystem.SingleUserWritable
+ }
+ if err = ctx.Mount.Setup(setupMode); err != nil {
+ return err
+ }
+
+ if allUsers {
+ fmt.Fprintf(w, "Metadata directories created at %q, writable by everyone.\n",
+ ctx.Mount.BaseDir())
+ } else {
+ fmt.Fprintf(w, "Metadata directories created at %q, writable by %s only.\n",
+ ctx.Mount.BaseDir(), username)
+ }
return nil
}
return err
}
- fmt.Fprintf(w, "%s filesystem %q has %s and %s\n\n", ctx.Mount.FilesystemType,
+ fmt.Fprintf(w, "%s filesystem %q has %s and %s.\n", ctx.Mount.FilesystemType,
ctx.Mount.Path, pluralize(len(options), "protector"),
pluralize(len(policyDescriptors), "policy"))
+ if setupMode, user, err := ctx.Mount.GetSetupMode(); err == nil {
+ switch setupMode {
+ case filesystem.WorldWritable:
+ fmt.Fprintf(w, "All users can create fscrypt metadata on this filesystem.\n")
+ case filesystem.SingleUserWritable:
+ fmt.Fprintf(w, "Only %s can create fscrypt metadata on this filesystem.\n", user.Username)
+ }
+ }
+ fmt.Fprintf(w, "\n")
if len(options) > 0 {
writeOptions(w, options)
err.Target.Path, err.UnderlyingError)
}
+// ErrNoCreatePermission indicates that the current user lacks permission to
+// create fscrypt metadata on the given filesystem.
+type ErrNoCreatePermission struct {
+ Mount *Mount
+}
+
+func (err *ErrNoCreatePermission) Error() string {
+ return fmt.Sprintf("user lacks permission to create fscrypt metadata on %s", err.Mount.Path)
+}
+
// ErrNotAMountpoint indicates that a path is not a mountpoint.
type ErrNotAMountpoint struct {
Path string
// The base directory should be read-only (except for the creator)
basePermissions = 0755
- // The subdirectories should be writable to everyone, but they have the
- // sticky bit set so users cannot delete other users' metadata.
- dirPermissions = os.ModeSticky | 0777
// The metadata files are globally visible, but can only be deleted by
// the user that created them
filePermissions = 0644
maxMetadataFileSize = 16384
)
+// SetupMode is a mode for creating the fscrypt metadata directories.
+type SetupMode int
+
+const (
+ // SingleUserWritable specifies to make the fscrypt metadata directories
+ // writable by a single user (usually root) only.
+ SingleUserWritable SetupMode = iota
+ // WorldWritable specifies to make the fscrypt metadata directories
+ // world-writable (with the sticky bit set).
+ WorldWritable
+)
+
func (m *Mount) String() string {
return fmt.Sprintf(`%s
FilesystemType: %s
}
// Run all the checks so we will always get all the warnings
baseGood := isDirCheckPerm(m.BaseDir(), basePermissions)
- policyGood := isDirCheckPerm(m.PolicyDir(), dirPermissions)
- protectorGood := isDirCheckPerm(m.ProtectorDir(), dirPermissions)
+ policyGood := isDir(m.PolicyDir())
+ protectorGood := isDir(m.ProtectorDir())
if baseGood && policyGood && protectorGood {
return nil
// makeDirectories creates the three metadata directories with the correct
// permissions. Note that this function overrides the umask.
-func (m *Mount) makeDirectories() error {
+func (m *Mount) makeDirectories(setupMode SetupMode) error {
// Zero the umask so we get the permissions we want
oldMask := unix.Umask(0)
defer func() {
if err := os.Mkdir(m.BaseDir(), basePermissions); err != nil {
return err
}
- if err := os.Mkdir(m.PolicyDir(), dirPermissions); err != nil {
+
+ var dirMode os.FileMode
+ switch setupMode {
+ case SingleUserWritable:
+ dirMode = 0755
+ case WorldWritable:
+ dirMode = os.ModeSticky | 0777
+ }
+ if err := os.Mkdir(m.PolicyDir(), dirMode); err != nil {
return err
}
- return os.Mkdir(m.ProtectorDir(), dirPermissions)
+ return os.Mkdir(m.ProtectorDir(), dirMode)
+}
+
+// GetSetupMode returns the current mode for fscrypt metadata creation on this
+// filesystem.
+func (m *Mount) GetSetupMode() (SetupMode, *user.User, error) {
+ info1, err1 := os.Stat(m.PolicyDir())
+ info2, err2 := os.Stat(m.ProtectorDir())
+
+ if err1 == nil && err2 == nil {
+ mask := os.ModeSticky | 0777
+ mode1 := info1.Mode() & mask
+ mode2 := info2.Mode() & mask
+ uid1 := info1.Sys().(*syscall.Stat_t).Uid
+ uid2 := info2.Sys().(*syscall.Stat_t).Uid
+ user, err := util.UserFromUID(int64(uid1))
+ if err == nil && mode1 == mode2 && uid1 == uid2 {
+ switch mode1 {
+ case mask:
+ return WorldWritable, nil, nil
+ case 0755:
+ return SingleUserWritable, user, nil
+ }
+ }
+ log.Printf("filesystem %s uses custom permissions on metadata directories", m.Path)
+ }
+ return -1, nil, errors.New("unable to determine setup mode")
}
// Setup sets up the filesystem for use with fscrypt. Note that this merely
// creates the appropriate files on the filesystem. It does not actually modify
// the filesystem's feature flags. This operation is atomic; it either succeeds
// or no files in the baseDir are created.
-func (m *Mount) Setup() error {
+func (m *Mount) Setup(mode SetupMode) error {
if m.CheckSetup() == nil {
return &ErrAlreadySetup{m}
}
}
defer os.RemoveAll(temp.Path)
- if err = temp.makeDirectories(); err != nil {
+ if err = temp.makeDirectories(mode); err != nil {
return err
}
log.Printf("trying non-atomic overwrite of %q", path)
return m.overwriteDataNonAtomic(path, data)
}
+ return &ErrNoCreatePermission{m}
}
return err
}
if err != nil {
return nil, err
}
- return mnt, mnt.Setup()
+ return mnt, mnt.Setup(WorldWritable)
}
// Tests that the setup works and creates the correct files
}
defer os.Remove(rawBaseDir)
- if err := mnt.Setup(); err != nil {
+ if err := mnt.Setup(WorldWritable); err != nil {
t.Fatal(err)
}
defer mnt.RemoveAllMetadata()
testSetupWithSymlink(t, mnt, ".fscrypt-real", realDir)
}
+func testSetupMode(t *testing.T, mnt *Mount, setupMode SetupMode, expectedPerms os.FileMode) {
+ mnt.RemoveAllMetadata()
+ if err := mnt.Setup(setupMode); err != nil {
+ t.Fatal(err)
+ }
+ dirNames := []string{"policies", "protectors"}
+ for _, dirName := range dirNames {
+ fi, err := os.Stat(filepath.Join(mnt.Path, ".fscrypt", dirName))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if fi.Mode()&(os.ModeSticky|0777) != expectedPerms {
+ t.Errorf("directory %s doesn't have permissions %o", dirName, expectedPerms)
+ }
+ }
+}
+
+// Tests that the supported setup modes (WorldWritable and SingleUserWritable)
+// work as intended.
+func TestSetupModes(t *testing.T) {
+ mnt, err := getTestMount(t)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer mnt.RemoveAllMetadata()
+ testSetupMode(t, mnt, WorldWritable, os.ModeSticky|0777)
+ testSetupMode(t, mnt, SingleUserWritable, 0755)
+}
+
// Adding a good Protector should succeed, adding a bad one should fail
func TestAddProtector(t *testing.T) {
mnt, err := getSetupMount(t)
return
}
fakeMnt = &Mount{Path: fakeMountpoint, FilesystemType: realMnt.FilesystemType}
- err = fakeMnt.Setup()
+ err = fakeMnt.Setup(WorldWritable)
return
}