aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--actions/config.go9
-rw-r--r--actions/config_test.go26
-rw-r--r--actions/context_test.go2
-rw-r--r--cmd/fscrypt/setup.go16
-rw-r--r--util/util.go23
-rw-r--r--util/util_test.go7
6 files changed, 78 insertions, 5 deletions
diff --git a/actions/config.go b/actions/config.go
index 3433438..2463b95 100644
--- a/actions/config.go
+++ b/actions/config.go
@@ -58,8 +58,9 @@ var (
// CreateConfigFile creates a new config file at the appropriate location with
// the appropriate hashing costs and encryption parameters. The hashing will be
-// configured to take as long as the specified time target.
-func CreateConfigFile(target time.Duration) error {
+// configured to take as long as the specified time target. In addition, the
+// version of encryption policy to use may be overridden from the default of v1.
+func CreateConfigFile(target time.Duration, policyVersion int64) error {
// Create the config file before computing the hashing costs, so we fail
// immediately if the program has insufficient permissions.
configFile, err := filesystem.OpenFileOverridingUmask(ConfigFileLocation,
@@ -77,6 +78,10 @@ func CreateConfigFile(target time.Duration) error {
Options: metadata.DefaultOptions,
}
+ if policyVersion != 0 {
+ config.Options.PolicyVersion = policyVersion
+ }
+
if config.HashCosts, err = getHashingCosts(target); err != nil {
return err
}
diff --git a/actions/config_test.go b/actions/config_test.go
index 02c89e6..3599667 100644
--- a/actions/config_test.go
+++ b/actions/config_test.go
@@ -26,6 +26,8 @@ import (
"time"
"golang.org/x/sys/unix"
+
+ "github.com/google/fscrypt/metadata"
)
// Test that the global config file is created with mode 0644, regardless of the
@@ -42,7 +44,7 @@ func TestConfigFileIsCreatedWithCorrectMode(t *testing.T) {
defer os.RemoveAll(tempDir)
ConfigFileLocation = filepath.Join(tempDir, "test.conf")
- if err = CreateConfigFile(time.Millisecond); err != nil {
+ if err = CreateConfigFile(time.Millisecond, 0); err != nil {
t.Fatal(err)
}
fileInfo, err := os.Stat(ConfigFileLocation)
@@ -53,3 +55,25 @@ func TestConfigFileIsCreatedWithCorrectMode(t *testing.T) {
t.Error("Expected newly created config file to have mode 0644")
}
}
+
+func TestCreateConfigFileV2Policy(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "fscrypt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempDir)
+ ConfigFileLocation = filepath.Join(tempDir, "test.conf")
+
+ if err = CreateConfigFile(time.Millisecond, 2); err != nil {
+ t.Fatal(err)
+ }
+
+ var config *metadata.Config
+ config, err = getConfig()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if config.Options.PolicyVersion != 2 {
+ t.Error("Expected PolicyVersion 2")
+ }
+}
diff --git a/actions/context_test.go b/actions/context_test.go
index 4f93776..4488a6b 100644
--- a/actions/context_test.go
+++ b/actions/context_test.go
@@ -52,7 +52,7 @@ func setupContext() (ctx *Context, err error) {
return nil, fmt.Errorf("created context at %q without config file", badCtx.Mount.Path)
}
- if err = CreateConfigFile(testTime); err != nil {
+ if err = CreateConfigFile(testTime, 0); err != nil {
return nil, err
}
defer func() {
diff --git a/cmd/fscrypt/setup.go b/cmd/fscrypt/setup.go
index 328788a..7b9bebb 100644
--- a/cmd/fscrypt/setup.go
+++ b/cmd/fscrypt/setup.go
@@ -50,8 +50,22 @@ func createGlobalConfig(w io.Writer, path string) error {
return err
}
+ // v2 encryption policies are recommended, so set policy_version 2 when
+ // the kernel supports it. v2 policies are supported by upstream Linux
+ // v5.4 and later. For now we simply check the kernel version. Ideally
+ // we'd instead check whether setting a v2 policy actually works, in
+ // order to also detect backports of the kernel patches. However, that's
+ // hard because from this context (creating /etc/fscrypt.conf) we may
+ // not yet have access to a filesystem that supports encryption.
+ var policyVersion int64
+ if util.IsKernelVersionAtLeast(5, 4) {
+ fmt.Fprintln(w, "Defaulting to policy_version 2 because kernel supports it.")
+ policyVersion = 2
+ } else {
+ fmt.Fprintln(w, "Defaulting to policy_version 1 because kernel doesn't support v2.")
+ }
fmt.Fprintln(w, "Customizing passphrase hashing difficulty for this system...")
- err = actions.CreateConfigFile(timeTargetFlag.Value)
+ err = actions.CreateConfigFile(timeTargetFlag.Value, policyVersion)
if err != nil {
return err
}
diff --git a/util/util.go b/util/util.go
index 97ee33c..d97a7ae 100644
--- a/util/util.go
+++ b/util/util.go
@@ -25,10 +25,14 @@ package util
import (
"bufio"
+ "fmt"
+ "log"
"os"
"os/user"
"strconv"
"unsafe"
+
+ "golang.org/x/sys/unix"
)
// Ptr converts a Go byte array to a pointer to the start of the array.
@@ -126,3 +130,22 @@ func EffectiveUser() (*user.User, error) {
func IsUserRoot() bool {
return os.Geteuid() == 0
}
+
+// IsKernelVersionAtLeast returns true if the Linux kernel version is at least
+// major.minor. If something goes wrong it assumes false.
+func IsKernelVersionAtLeast(major, minor int) bool {
+ var uname unix.Utsname
+ if err := unix.Uname(&uname); err != nil {
+ log.Printf("Uname failed [%v], assuming old kernel", err)
+ return false
+ }
+ release := string(uname.Release[:])
+ log.Printf("Kernel version is %s", release)
+ var actualMajor, actualMinor int
+ if n, _ := fmt.Sscanf(release, "%d.%d", &actualMajor, &actualMinor); n != 2 {
+ log.Printf("Unrecognized uname format %q, assuming old kernel", release)
+ return false
+ }
+ return actualMajor > major ||
+ (actualMajor == major && actualMinor >= minor)
+}
diff --git a/util/util_test.go b/util/util_test.go
index 7739edd..70e7070 100644
--- a/util/util_test.go
+++ b/util/util_test.go
@@ -91,3 +91,10 @@ func TestNeverErrorNoPanic(t *testing.T) {
NeverError(nil)
}
+
+func TestIsKernelVersionAtLeast(t *testing.T) {
+ // Even just running Go requires at least v2.6.23, so...
+ if !IsKernelVersionAtLeast(2, 6) {
+ t.Error("IsKernelVersionAtLeast() is broken")
+ }
+}