aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Richey <joerichey@google.com>2020-03-23 14:24:23 -0700
committerGitHub <noreply@github.com>2020-03-23 14:24:23 -0700
commitab531eea551598170e4dd973fa5955f01b5c0318 (patch)
treead01ed9d6ffa3d9715c40ff14041f95978107ba7
parentb43cb6970da16fea7aa2c073a83891909a2833b1 (diff)
parent02ec13d8d96fc16282998f8355074dad53271591 (diff)
Merge pull request #205 from ebiggers/autoselect-v2
Automatically enable policy_version 2 when kernel support is detected
-rw-r--r--README.md149
-rw-r--r--actions/config.go20
-rw-r--r--actions/config_test.go26
-rw-r--r--actions/context.go19
-rw-r--r--actions/context_test.go2
-rw-r--r--actions/policy.go11
-rw-r--r--cmd/fscrypt/commands.go2
-rw-r--r--cmd/fscrypt/errors.go11
-rw-r--r--cmd/fscrypt/flags.go8
-rw-r--r--cmd/fscrypt/format.go7
-rw-r--r--cmd/fscrypt/setup.go16
-rw-r--r--filesystem/path.go6
-rw-r--r--filesystem/path_test.go27
-rw-r--r--keyring/fs_keyring.go4
-rw-r--r--keyring/keyring.go68
-rw-r--r--keyring/keyring_test.go28
-rw-r--r--metadata/config.go14
-rw-r--r--metadata/config_test.go8
-rw-r--r--metadata/metadata.pb.go124
-rw-r--r--metadata/metadata.proto5
-rw-r--r--util/util.go23
-rw-r--r--util/util_test.go7
22 files changed, 342 insertions, 243 deletions
diff --git a/README.md b/README.md
index 5bcc7eb..d1bb9cb 100644
--- a/README.md
+++ b/README.md
@@ -173,6 +173,10 @@ To check whether the needed option is enabled in your kernel, run:
zgrep -h ENCRYPTION /proc/config.gz /boot/config-$(uname -r) | sort | uniq
```
+It is also recommended to use Linux kernel v5.4 or later, since this
+allows the use of v2 encryption policies. v2 policies have several
+security and usability improvements over v1 policies.
+
Be careful when using encryption on removable media, since filesystems with the
`encrypt` feature cannot be mounted on systems with kernel versions older than
the minimums listed above -- even to access unencrypted files!
@@ -195,12 +199,11 @@ that looks like the following:
"memory": "131072",
"parallelism": "32"
},
- "compatibility": "legacy",
"options": {
"padding": "32",
"contents": "AES_256_XTS",
"filenames": "AES_256_CTS",
- "policy_version": "1"
+ "policy_version": "2"
},
"use_fs_keyring_for_v1_policies": false
}
@@ -216,9 +219,6 @@ The fields are:
and take about 1 second. The `--time` option to `fscrypt setup` can
be used to customize this time when creating the configuration file.
-* "compatibility" can be "legacy" to support kernels older than v4.8,
- or the empty string to only support kernels v4.8 and later.
-
* "options" are the encryption options to use for new encrypted
directories:
@@ -245,9 +245,10 @@ The fields are:
for more details about the supported algorithms.
* "policy\_version" is the version of encryption policy to use.
- The choices are "1" and "2". Directories created with policy
- version "2" are only usable on kernel v5.4 or later, but are
- preferable to version "1" if you don't mind this restriction.
+ The choices are "1" and "2". If unset, "1" is assumed.
+ Directories created with policy version "2" are only usable on
+ kernel v5.4 or later, but are preferable to version "1" if you
+ don't mind this restriction.
* "use\_fs\_keyring\_for\_v1\_policies" specifies whether to add keys
for v1 encryption policies to the filesystem keyring, rather than to
@@ -366,6 +367,7 @@ MOUNTPOINT DEVICE FILESYSTEM ENCRYPTION FSCRYPT
# Create the global configuration file. Nothing else necessarily needs root.
>>>>> sudo fscrypt setup
+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".
@@ -394,8 +396,8 @@ ext4 filesystem "/mnt/disk" has 1 protector and 1 policy
PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"
-POLICY UNLOCKED PROTECTORS
-7626382168311a9d Yes 7626382168311a9d
+POLICY UNLOCKED PROTECTORS
+16382f282d7b29ee27e6460151d03382 Yes 7626382168311a9d
```
#### Quiet Version
@@ -413,24 +415,23 @@ POLICY UNLOCKED PROTECTORS
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: Yes
Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"
-# Lock the directory. 'sudo' and the '--user' argument are only
-# required if the directory uses a v1 encryption policy.
->>>>> sudo fscrypt lock /mnt/disk/dir1 --user=$USER
-Encrypted data removed from filesystem cache.
+# Lock the directory. Note: if using a v1 encryption policy instead
+# of v2, you'll need 'sudo fscrypt lock /mnt/disk/dir1 --user=$USER'.
+>>>>> fscrypt lock /mnt/disk/dir1
"/mnt/disk/dir1" is now locked.
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: No
Protected with 1 protector:
@@ -450,8 +451,8 @@ Enter custom passphrase for protector "Super Secret":
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: Yes
Protected with 1 protector:
@@ -463,7 +464,7 @@ Hello World
#### Quiet Version
```bash
->>>>> sudo fscrypt lock /mnt/disk/dir1 --quiet --user=$USER
+>>>>> fscrypt lock /mnt/disk/dir1 --quiet
>>>>> echo "hunter2" | fscrypt unlock /mnt/disk/dir1 --quiet
```
@@ -486,8 +487,8 @@ Enter login passphrase for joerichey:
>>>>> fscrypt status /mnt/disk/dir2
"/mnt/disk/dir2" is encrypted with fscrypt.
-Policy: fe1c92009abc1cff
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: fe1c92009abc1cff4f3257c77e8134e3
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: Yes
Protected with 1 protector:
@@ -500,9 +501,9 @@ PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"
6891f0a901f0065e Yes (/) login protector for joerichey
-POLICY UNLOCKED PROTECTORS
-16382f282d7b29ee Yes 7626382168311a9d
-fe1c92009abc1cff Yes 6891f0a901f0065e
+POLICY UNLOCKED PROTECTORS
+16382f282d7b29ee27e6460151d03382 Yes 7626382168311a9d
+fe1c92009abc1cff4f3257c77e8134e3 Yes 6891f0a901f0065e
>>>>> fscrypt status /
ext4 filesystem "/" has 1 protector(s) and 0 policy(ies)
@@ -522,8 +523,8 @@ PROTECTOR LINKED DESCRIPTION
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: Yes
Protected with 1 protector:
@@ -577,9 +578,9 @@ PROTECTOR LINKED DESCRIPTION
2c75f519b9c9959d No raw key protector "Skeleton"
6891f0a901f0065e Yes (/) login protector for joerichey
-POLICY UNLOCKED PROTECTORS
-16382f282d7b29ee Yes 7626382168311a9d
-fe1c92009abc1cff Yes 6891f0a901f0065e
+POLICY UNLOCKED PROTECTORS
+16382f282d7b29ee27e6460151d03382 Yes 7626382168311a9d
+fe1c92009abc1cff4f3257c77e8134e3 Yes 6891f0a901f0065e
# Finally, we could apply this key to a directory
>>>>> mkdir /mnt/disk/dir3
@@ -611,31 +612,31 @@ PROTECTOR LINKED DESCRIPTION
2c75f519b9c9959d No raw key protector "Skeleton"
6891f0a901f0065e Yes (/) login protector for joerichey
-POLICY UNLOCKED PROTECTORS
-d03fb894584a4318 No 2c75f519b9c9959d
-16382f282d7b29ee No 7626382168311a9d
-fe1c92009abc1cff No 6891f0a901f0065e
+POLICY UNLOCKED PROTECTORS
+d03fb894584a4318d1780e9a7b0b47eb No 2c75f519b9c9959d
+16382f282d7b29ee27e6460151d03382 No 7626382168311a9d
+fe1c92009abc1cff4f3257c77e8134e3 No 6891f0a901f0065e
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: No
Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"
->>>>> fscrypt metadata add-protector-to-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee
+>>>>> fscrypt metadata add-protector-to-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee27e6460151d03382
WARNING: All files using this policy will be accessible with this protector!!
-Protect policy 16382f282d7b29ee with protector 2c75f519b9c9959d? [Y/n]
+Protect policy 16382f282d7b29ee27e6460151d03382 with protector 2c75f519b9c9959d? [Y/n]
Enter key file for protector "Skeleton": secret.key
Enter custom passphrase for protector "Super Secret":
-Protector 2c75f519b9c9959d now protecting policy 16382f282d7b29ee.
+Protector 2c75f519b9c9959d now protecting policy 16382f282d7b29ee27e6460151d03382.
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.
-Policy: 16382f282d7b29ee
-Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
+Policy: 16382f282d7b29ee27e6460151d03382
+Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2
Unlocked: No
Protected with 2 protectors:
@@ -653,16 +654,16 @@ Enter key file for protector "Skeleton": secret.key
"/mnt/disk/dir1" is now unlocked and ready for use.
# The protector can also be removed from the policy (if it is not the only one)
->>>>> fscrypt metadata remove-protector-from-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee
+>>>>> fscrypt metadata remove-protector-from-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee27e6460151d03382
WARNING: All files using this policy will NO LONGER be accessible with this protector!!
-Stop protecting policy 16382f282d7b29ee with protector 2c75f519b9c9959d? [y/N] y
-Protector 2c75f519b9c9959d no longer protecting policy 16382f282d7b29ee.
+Stop protecting policy 16382f282d7b29ee27e6460151d03382 with protector 2c75f519b9c9959d? [y/N] y
+Protector 2c75f519b9c9959d no longer protecting policy 16382f282d7b29ee27e6460151d03382.
```
#### Quiet Version
```bash
->>>>> echo "hunter2" | fscrypt metadata add-protector-to-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee --key=secret.key --quiet
->>>>> fscrypt metadata remove-protector-from-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee --quiet --force
+>>>>> echo "hunter2" | fscrypt metadata add-protector-to-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee27e6460151d03382 --key=secret.key --quiet
+>>>>> fscrypt metadata remove-protector-from-policy --protector=/mnt/disk:2c75f519b9c9959d --policy=/mnt/disk:16382f282d7b29ee27e6460151d03382 --quiet --force
```
## Contributing
@@ -777,27 +778,49 @@ manifest in other ways such as Docker containers being unable to
access encrypted files, or NetworkManager being unable to access
certificates if they are located in an encrypted directory.
-If you are using kernel v5.4 or later, you can fix this by setting the
-following in `/etc/fscrypt.conf`:
+The recommended way to fix this is by creating your encrypted
+directories using v2 encryption policies rather than v1. This
+requires Linux v5.4 or later and `fscrypt` v0.2.6 or later. If these
+prerequisites are met, enable v2 policies for new directories by
+setting `"policy_version": "2"` in `/etc/fscrypt.conf`. For example:
+
+```
+ "options": {
+ "padding": "32",
+ "contents": "AES_256_XTS",
+ "filenames": "AES_256_CTS",
+ "policy_version": "2"
+ },
+```
- "use_fs_keyring_for_v1_policies": true
+This only affects new directories. If you want to upgrade an existing
+encrypted directory to use a v2 policy, you'll need to re-create it by
+using `fscrypt encrypt` to encrypt a new empty directory, copying your
+files into it, and replacing the original directory with it.
-However, this makes manually unlocking and locking encrypted
-directories start to require root. (The PAM module will still work.)
-E.g., you'll need to run `sudo fscrypt unlock`, not `fscrypt unlock`.
+In `fscrypt` v0.2.7 and later, the `fscrypt setup` command
+automatically sets `"policy_version": "2"` when creating
+`/etc/fscrypt.conf` if kernel support is present.
-Alternatively, you can upgrade your encrypted directories to use v2
-encryption policies by setting the following in the "options" section
-of `/etc/fscrypt.conf`:
+__IMPORTANT:__ directories that use v2 encryption policies are
+unusable on Linux v5.3 and earlier. If this will be a problem for you
+(for example, if your encrypted directories are on removable storage
+that needs to work on computers with both old and new kernels), you'll
+need to use v1 policies instead. In this case, you can enable a
+fallback option to make `fscrypt` use the filesystem keyring for v1
+policies:
- "policy_version": "2"
+```
+ "use_fs_keyring_for_v1_policies": true
+```
-... and then for each of your encrypted directories, using `fscrypt
-encrypt` to encrypt a new empty directory, copying your files into it,
-and replacing the original directory with it. This will fix the key
-access problems, while also keeping `fscrypt unlock` and `fscrypt
-lock` usable by non-root users. This is the recommended solution if
-you don't need to access your files on kernels older than v5.4.
+This fallback option only has an effect if the kernel supports using
+the filesystem keyring. This option is also useful if you simply
+don't want to re-create your old, v1 directories. However, this
+option makes manually unlocking and locking encrypted directories
+start to require root. (The PAM module will still work.) E.g.,
+you'll need to run `sudo fscrypt unlock`, not `fscrypt unlock`. Most
+people should just use v2 policies instead.
## Legal
diff --git a/actions/config.go b/actions/config.go
index 6b019df..2463b95 100644
--- a/actions/config.go
+++ b/actions/config.go
@@ -36,10 +36,6 @@ import (
"github.com/google/fscrypt/util"
)
-// LegacyConfig indicates that keys should be inserted into the keyring with the
-// legacy service prefixes. Needed for kernels before v4.8.
-const LegacyConfig = "legacy"
-
// ConfigFileLocation is the location of fscrypt's global settings. This can be
// overridden by the user of this package.
var ConfigFileLocation = "/etc/fscrypt.conf"
@@ -61,12 +57,10 @@ var (
)
// CreateConfigFile creates a new config file at the appropriate location with
-// the appropriate hashing costs and encryption parameters. This creation is
-// configurable in two ways. First, a time target must be specified. This target
-// will determine the hashing costs, by picking parameters that make the hashing
-// take as long as the specified target. Second, the config can include the
-// legacy option, which is needed for systems with kernels older than v4.8.
-func CreateConfigFile(target time.Duration, useLegacy bool) error {
+// the appropriate hashing costs and encryption parameters. The hashing will be
+// 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,
@@ -83,9 +77,9 @@ func CreateConfigFile(target time.Duration, useLegacy bool) error {
Source: metadata.DefaultSource,
Options: metadata.DefaultOptions,
}
- if useLegacy {
- config.Compatibility = LegacyConfig
- log.Printf("Using %q compatibility option\n", LegacyConfig)
+
+ if policyVersion != 0 {
+ config.Options.PolicyVersion = policyVersion
}
if config.HashCosts, err = getHashingCosts(target); err != nil {
diff --git a/actions/config_test.go b/actions/config_test.go
index 037e433..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, false); 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.go b/actions/context.go
index f07f225..0db0671 100644
--- a/actions/context.go
+++ b/actions/context.go
@@ -32,8 +32,6 @@ import (
"log"
"os/user"
- "golang.org/x/sys/unix"
-
"github.com/pkg/errors"
"github.com/google/fscrypt/filesystem"
@@ -133,27 +131,10 @@ func (ctx *Context) checkContext() error {
return ctx.Mount.CheckSetup()
}
-// getService returns the keyring service for this context. We use the presence
-// of the LegacyConfig flag to determine if we should use the legacy services.
-// For ext4 systems before v4.8 and f2fs systems before v4.6, filesystem
-// specific services must be used (these legacy services will still work with
-// later kernels).
-func (ctx *Context) getService() string {
- // For legacy configurations, we may need non-standard services
- if ctx.Config.HasCompatibilityOption(LegacyConfig) {
- switch ctx.Mount.FilesystemType {
- case "ext4", "f2fs":
- return ctx.Mount.FilesystemType + ":"
- }
- }
- 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(),
}
}
diff --git a/actions/context_test.go b/actions/context_test.go
index e8aefd7..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, true); err != nil {
+ if err = CreateConfigFile(testTime, 0); err != nil {
return nil, err
}
defer func() {
diff --git a/actions/policy.go b/actions/policy.go
index b7fe5a6..3baad72 100644
--- a/actions/policy.go
+++ b/actions/policy.go
@@ -22,6 +22,7 @@ package actions
import (
"fmt"
"log"
+ "os"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
@@ -41,6 +42,7 @@ var (
ErrOnlyProtector = errors.New("cannot remove the only protector for a policy")
ErrAlreadyProtected = errors.New("policy already protected by protector")
ErrNotProtected = errors.New("policy not protected by protector")
+ ErrAccessDeniedPossiblyV2 = errors.New("permission denied")
)
// PurgeAllPolicies removes all policy keys on the filesystem from the kernel
@@ -152,6 +154,15 @@ func GetPolicyFromPath(ctx *Context, path string) (*Policy, error) {
// the path, and the data we get from the mountpoint.
pathData, err := metadata.GetPolicy(path)
if err != nil {
+ // On kernels that don't support v2 encryption policies, trying
+ // to open a directory with a v2 policy simply gave EACCES. This
+ // is ambiguous with other errors, but try to detect this case
+ // and show a better error message.
+ if os.IsPermission(err) &&
+ filesystem.HaveReadAccessTo(path) &&
+ !keyring.IsFsKeyringSupported(ctx.Mount) {
+ return nil, errors.Wrapf(ErrAccessDeniedPossiblyV2, "open %s", path)
+ }
return nil, err
}
descriptor := pathData.KeyDescriptor
diff --git a/cmd/fscrypt/commands.go b/cmd/fscrypt/commands.go
index 4a59d30..f84102e 100644
--- a/cmd/fscrypt/commands.go
+++ b/cmd/fscrypt/commands.go
@@ -62,7 +62,7 @@ var Setup = cli.Command{
the README). This may require root privileges.`,
mountpointArg, actions.ConfigFileLocation,
shortDisplay(timeTargetFlag)),
- Flags: []cli.Flag{timeTargetFlag, legacyFlag, forceFlag},
+ Flags: []cli.Flag{timeTargetFlag, forceFlag},
Action: setupAction,
}
diff --git a/cmd/fscrypt/errors.go b/cmd/fscrypt/errors.go
index bef6c2a..8bda921 100644
--- a/cmd/fscrypt/errors.go
+++ b/cmd/fscrypt/errors.go
@@ -113,6 +113,10 @@ func getErrorSuggestions(err error) string {
return fmt.Sprintf(`You can only use %s to access the user
keyring of another user if you are running as root.`,
shortDisplay(userFlag))
+ case keyring.ErrV2PoliciesUnsupported:
+ return fmt.Sprintf(`v2 encryption policies are only supported by kernel
+ version 5.4 and later. Either use a newer kernel, or change
+ policy_version to 1 in %s.`, actions.ConfigFileLocation)
case actions.ErrBadConfigFile:
return `Run "sudo fscrypt setup" to recreate the file.`
case actions.ErrNoConfigFile:
@@ -127,6 +131,13 @@ func getErrorSuggestions(err error) string {
metadata is corrupted.`
case actions.ErrMissingProtectorName:
return fmt.Sprintf("Use %s to specify a protector name.", shortDisplay(nameFlag))
+ case actions.ErrAccessDeniedPossiblyV2:
+ return fmt.Sprintf(`This may be caused by the directory using a v2
+ encryption policy and the current kernel not supporting it. If
+ indeed the case, then this directory can only be used on kernel
+ v5.4 and later. You can create directories accessible on older
+ kernels by changing policy_version to 1 in %s.`,
+ actions.ConfigFileLocation)
case ErrNoDestructiveOps:
return fmt.Sprintf("Use %s to automatically run destructive operations.", shortDisplay(forceFlag))
case ErrSpecifyProtector:
diff --git a/cmd/fscrypt/flags.go b/cmd/fscrypt/flags.go
index ce2f30e..9679a8d 100644
--- a/cmd/fscrypt/flags.go
+++ b/cmd/fscrypt/flags.go
@@ -114,7 +114,7 @@ var (
// UPDATE THIS ARRAY WHEN ADDING NEW FLAGS!!!
// TODO(joerichey) add presubmit rule to enforce this
allFlags = []prettyFlag{helpFlag, versionFlag, verboseFlag, quietFlag,
- forceFlag, legacyFlag, skipUnlockFlag, timeTargetFlag,
+ forceFlag, skipUnlockFlag, timeTargetFlag,
sourceFlag, nameFlag, keyFileFlag, protectorFlag,
unlockWithFlag, policyFlag, allUsersFlag, noRecoveryFlag}
// universalFlags contains flags that should be on every command
@@ -148,12 +148,6 @@ var (
WARNING: This bypasses confirmations for protective
operations, use with care.`),
}
- legacyFlag = &boolFlag{
- Name: "legacy",
- Usage: `Allow for support of older kernels with ext4 (before
- v4.8) and F2FS (before v4.6) filesystems.`,
- Default: true,
- }
skipUnlockFlag = &boolFlag{
Name: "skip-unlock",
Usage: `Leave the directory in a locked state after setup.
diff --git a/cmd/fscrypt/format.go b/cmd/fscrypt/format.go
index 48a5a86..cc268aa 100644
--- a/cmd/fscrypt/format.go
+++ b/cmd/fscrypt/format.go
@@ -98,11 +98,10 @@ func shortDisplay(f prettyFlag) string {
//
// --help Prints help screen for commands and subcommands.
//
-// If a default is specified, this if appended to the usage. Example:
+// If a default is specified, then it is appended to the usage. Example:
//
-// --legacy Allow for support of older kernels with ext4
-// (before v4.8) and F2FS (before v4.6) filesystems.
-// (default: true)
+// --time=TIME Calibrate passphrase hashing to take the
+// specified amount of TIME (default: 1s)
//
func longDisplay(f prettyFlag, defaultString ...string) string {
usage := f.GetUsage()
diff --git a/cmd/fscrypt/setup.go b/cmd/fscrypt/setup.go
index 69787bb..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, legacyFlag.Value)
+ err = actions.CreateConfigFile(timeTargetFlag.Value, policyVersion)
if err != nil {
return err
}
diff --git a/filesystem/path.go b/filesystem/path.go
index b9b403d..274dc0a 100644
--- a/filesystem/path.go
+++ b/filesystem/path.go
@@ -78,6 +78,12 @@ func isRegularFile(path string) bool {
return err == nil && info.Mode().IsRegular()
}
+// HaveReadAccessTo returns true if the process has read access to a file or
+// directory, without actually opening it.
+func HaveReadAccessTo(path string) bool {
+ return unix.Access(path, unix.R_OK) == nil
+}
+
// DeviceNumber represents a combined major:minor device number.
type DeviceNumber uint64
diff --git a/filesystem/path_test.go b/filesystem/path_test.go
index eef5ce3..4152037 100644
--- a/filesystem/path_test.go
+++ b/filesystem/path_test.go
@@ -20,6 +20,8 @@ package filesystem
import (
"fmt"
+ "io/ioutil"
+ "os"
"testing"
)
@@ -52,3 +54,28 @@ func TestDeviceNumber(t *testing.T) {
t.Error("Should have failed to parse invalid device number")
}
}
+
+func TestHaveReadAccessTo(t *testing.T) {
+ file, err := ioutil.TempFile("", "fscrypt_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ file.Close()
+ defer os.Remove(file.Name())
+
+ testCases := map[os.FileMode]bool{
+ 0444: true,
+ 0400: true,
+ 0000: false,
+ 0040: false, // user bits take priority in Linux
+ 0004: false, // user bits take priority in Linux
+ }
+ for mode, readable := range testCases {
+ if err := os.Chmod(file.Name(), mode); err != nil {
+ t.Error(err)
+ }
+ if HaveReadAccessTo(file.Name()) != readable {
+ t.Errorf("Expected readable=%v on mode=0%03o", readable, mode)
+ }
+ }
+}
diff --git a/keyring/fs_keyring.go b/keyring/fs_keyring.go
index 42c1648..f0016a4 100644
--- a/keyring/fs_keyring.go
+++ b/keyring/fs_keyring.go
@@ -79,10 +79,10 @@ func checkForFsKeyringSupport(mount *filesystem.Mount) bool {
return true
}
-// isFsKeyringSupported returns true if the kernel supports the ioctls to
+// IsFsKeyringSupported returns true if the kernel supports the ioctls to
// add/remove fscrypt keys directly to/from the filesystem. For support to be
// detected, the given Mount must be for a filesystem that supports fscrypt.
-func isFsKeyringSupported(mount *filesystem.Mount) bool {
+func IsFsKeyringSupported(mount *filesystem.Mount) bool {
fsKeyringSupportedLock.Lock()
defer fsKeyringSupportedLock.Unlock()
if !fsKeyringSupportedKnown {
diff --git a/keyring/keyring.go b/keyring/keyring.go
index 5a75153..6623943 100644
--- a/keyring/keyring.go
+++ b/keyring/keyring.go
@@ -43,15 +43,16 @@ import (
// Keyring error values
var (
- ErrKeyAdd = util.SystemError("could not add key to the keyring")
- ErrKeyRemove = util.SystemError("could not remove key from the keyring")
- ErrKeyNotPresent = errors.New("key not present or already removed")
- ErrKeyFilesOpen = errors.New("some files using the key are still open")
- ErrKeyAddedByOtherUsers = errors.New("other users have added the key too")
- ErrKeySearch = errors.New("could not find key with descriptor")
- ErrSessionUserKeying = errors.New("user keyring not linked into session keyring")
- ErrAccessUserKeyring = errors.New("could not access user keyring")
- ErrLinkUserKeyring = util.SystemError("could not link user keyring into root keyring")
+ ErrKeyAdd = util.SystemError("could not add key to the keyring")
+ ErrKeyRemove = util.SystemError("could not remove key from the keyring")
+ ErrKeyNotPresent = errors.New("key not present or already removed")
+ ErrKeyFilesOpen = errors.New("some files using the key are still open")
+ ErrKeyAddedByOtherUsers = errors.New("other users have added the key too")
+ ErrKeySearch = errors.New("could not find key with descriptor")
+ ErrSessionUserKeying = errors.New("user keyring not linked into session keyring")
+ ErrAccessUserKeyring = errors.New("could not access user keyring")
+ ErrLinkUserKeyring = util.SystemError("could not link user keyring into root keyring")
+ ErrV2PoliciesUnsupported = errors.New("kernel is too old to support v2 encryption policies")
)
// Options are the options which specify *which* keyring the key should be
@@ -62,9 +63,6 @@ type Options struct {
Mount *filesystem.Mount
// User is the user for whom the key should be added/removed/gotten.
User *user.User
- // Service is the prefix to prepend to the description of the keys in
- // user keyrings. Not relevant for filesystem keyrings.
- Service string
// UseFsKeyringForV1Policies is true if keys for v1 encryption policies
// should be put in the filesystem's keyring (if supported) rather than
// in the user's keyring. Note that this makes AddEncryptionKey and
@@ -72,16 +70,32 @@ type Options struct {
UseFsKeyringForV1Policies bool
}
-func shouldUseFsKeyring(descriptor string, options *Options) bool {
+func shouldUseFsKeyring(descriptor string, options *Options) (bool, error) {
// For v1 encryption policy keys, use the filesystem keyring if
// use_fs_keyring_for_v1_policies is set in /etc/fscrypt.conf and the
// kernel supports it.
if len(descriptor) == hex.EncodedLen(unix.FSCRYPT_KEY_DESCRIPTOR_SIZE) {
- return options.UseFsKeyringForV1Policies && isFsKeyringSupported(options.Mount)
+ return options.UseFsKeyringForV1Policies && IsFsKeyringSupported(options.Mount), nil
}
// For v2 encryption policy keys, always use the filesystem keyring; the
// kernel doesn't support any other way.
- return true
+ if !IsFsKeyringSupported(options.Mount) {
+ return true, ErrV2PoliciesUnsupported
+ }
+ return true, nil
+}
+
+// buildKeyDescription builds the description for an fscrypt key of type
+// "logon". For ext4 and f2fs, it uses the legacy filesystem-specific prefixes
+// for compatibility with kernels before v4.8 and v4.6 respectively. For other
+// filesystems it uses the generic prefix "fscrypt".
+func buildKeyDescription(options *Options, descriptor string) string {
+ switch options.Mount.FilesystemType {
+ case "ext4", "f2fs":
+ return options.Mount.FilesystemType + ":" + descriptor
+ default:
+ return unix.FSCRYPT_KEY_DESC_PREFIX + descriptor
+ }
}
// AddEncryptionKey adds an encryption policy key to a kernel keyring. It uses
@@ -91,24 +105,32 @@ func AddEncryptionKey(key *crypto.Key, descriptor string, options *Options) erro
if err := util.CheckValidLength(metadata.PolicyKeyLen, key.Len()); err != nil {
return errors.Wrap(err, "policy key")
}
- if shouldUseFsKeyring(descriptor, options) {
+ useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
+ if err != nil {
+ return err
+ }
+ if useFsKeyring {
return fsAddEncryptionKey(key, descriptor, options.Mount, options.User)
}
- return userAddKey(key, options.Service+descriptor, options.User)
+ return userAddKey(key, buildKeyDescription(options, descriptor), options.User)
}
// RemoveEncryptionKey removes an encryption policy key from a kernel keyring.
// It uses either the filesystem keyring for the target Mount or the user
// keyring for the target User.
func RemoveEncryptionKey(descriptor string, options *Options, allUsers bool) error {
- if shouldUseFsKeyring(descriptor, options) {
+ useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
+ if err != nil {
+ return err
+ }
+ if useFsKeyring {
user := options.User
if allUsers {
user = nil
}
return fsRemoveEncryptionKey(descriptor, options.Mount, user)
}
- return userRemoveKey(options.Service+descriptor, options.User)
+ return userRemoveKey(buildKeyDescription(options, descriptor), options.User)
}
// KeyStatus is an enum that represents the status of a key in a kernel keyring.
@@ -144,10 +166,14 @@ func (status KeyStatus) String() string {
// kernel keyring. It uses either the filesystem keyring for the target Mount
// or the user keyring for the target User.
func GetEncryptionKeyStatus(descriptor string, options *Options) (KeyStatus, error) {
- if shouldUseFsKeyring(descriptor, options) {
+ useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
+ if err != nil {
+ return KeyStatusUnknown, err
+ }
+ if useFsKeyring {
return fsGetEncryptionKeyStatus(descriptor, options.Mount, options.User)
}
- _, err := userFindKey(options.Service+descriptor, options.User)
+ _, err = userFindKey(buildKeyDescription(options, descriptor), options.User)
if err != nil {
return KeyAbsent, nil
}
diff --git a/keyring/keyring_test.go b/keyring/keyring_test.go
index 8912556..26f6036 100644
--- a/keyring/keyring_test.go
+++ b/keyring/keyring_test.go
@@ -23,8 +23,6 @@ import (
"strconv"
"testing"
- "golang.org/x/sys/unix"
-
"github.com/google/fscrypt/crypto"
"github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/metadata"
@@ -47,7 +45,6 @@ func makeKey(b byte, n int) (*crypto.Key, error) {
}
var (
- defaultService = unix.FSCRYPT_KEY_DESC_PREFIX
testUser, _ = util.EffectiveUser()
fakeValidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen)
fakeInvalidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen-1)
@@ -84,7 +81,7 @@ func getTestMount(t *testing.T) *filesystem.Mount {
// filesystem keyring and v2 encryption policies are supported.
func getTestMountV2(t *testing.T) *filesystem.Mount {
mount := getTestMount(t)
- if !isFsKeyringSupported(mount) {
+ if !IsFsKeyringSupported(mount) {
t.Skip("No support for fs keyring, skipping test.")
}
return mount
@@ -166,28 +163,11 @@ func testAddAndRemoveKey(t *testing.T, descriptor string, options *Options) {
assertKeyStatus(t, descriptor, options, KeyAbsent)
}
-func TestUserKeyringDefaultService(t *testing.T) {
- options := &Options{
- User: testUser,
- Service: defaultService,
- UseFsKeyringForV1Policies: false,
- }
- testAddAndRemoveKey(t, fakeV1Descriptor, options)
-}
-
-func TestUserKeyringExt4Service(t *testing.T) {
- options := &Options{
- User: testUser,
- Service: "ext4:",
- UseFsKeyringForV1Policies: false,
- }
- testAddAndRemoveKey(t, fakeV1Descriptor, options)
-}
-
-func TestUserKeyringF2fsService(t *testing.T) {
+func TestUserKeyring(t *testing.T) {
+ mount := getTestMount(t)
options := &Options{
+ Mount: mount,
User: testUser,
- Service: "f2fs:",
UseFsKeyringForV1Policies: false,
}
testAddAndRemoveKey(t, fakeV1Descriptor, options)
diff --git a/metadata/config.go b/metadata/config.go
index 0f95fbe..b3c8726 100644
--- a/metadata/config.go
+++ b/metadata/config.go
@@ -28,7 +28,6 @@ package metadata
import (
"io"
- "strings"
"github.com/golang/protobuf/jsonpb"
)
@@ -58,16 +57,3 @@ func ReadConfig(in io.Reader) (*Config, error) {
}
return config, u.Unmarshal(in, config)
}
-
-// HasCompatibilityOption returns true if the specified string is in the list of
-// compatibility options. This assumes the compatibility options are in a comma
-// separated string.
-func (c *Config) HasCompatibilityOption(option string) bool {
- options := strings.Split(c.Compatibility, ",")
- for _, o := range options {
- if o == option {
- return true
- }
- }
- return false
-}
diff --git a/metadata/config_test.go b/metadata/config_test.go
index 83c1eb0..52f83f2 100644
--- a/metadata/config_test.go
+++ b/metadata/config_test.go
@@ -33,8 +33,7 @@ var testConfig = &Config{
Memory: 1 << 12,
Parallelism: 8,
},
- Compatibility: "",
- Options: DefaultOptions,
+ Options: DefaultOptions,
}
var testConfigString = `{
@@ -44,7 +43,6 @@ var testConfigString = `{
"memory": "4096",
"parallelism": "8"
},
- "compatibility": "",
"options": {
"padding": "32",
"contents": "AES_256_XTS",
@@ -81,7 +79,7 @@ func TestRead(t *testing.T) {
}
// Makes sure we can parse a legacy config file that doesn't have the fields
-// that were added later.
+// that were added later and that has the removed "compatibility" field.
func TestOptionalFields(t *testing.T) {
contents := `{
"source": "custom_passphrase",
@@ -90,7 +88,7 @@ func TestOptionalFields(t *testing.T) {
"memory": "4096",
"parallelism": "8"
},
- "compatibility": "",
+ "compatibility": "legacy",
"options": {
"padding": "32",
"contents": "AES_256_XTS",
diff --git a/metadata/metadata.pb.go b/metadata/metadata.pb.go
index e6067f9..a2148ce 100644
--- a/metadata/metadata.pb.go
+++ b/metadata/metadata.pb.go
@@ -45,7 +45,7 @@ func (x SourceType) String() string {
return proto.EnumName(SourceType_name, int32(x))
}
func (SourceType) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{0}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{0}
}
// Type of encryption; should match declarations of unix.FSCRYPT_MODE
@@ -87,7 +87,7 @@ func (x EncryptionOptions_Mode) String() string {
return proto.EnumName(EncryptionOptions_Mode_name, int32(x))
}
func (EncryptionOptions_Mode) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{3, 0}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{3, 0}
}
// Cost parameters to be used in our hashing functions.
@@ -104,7 +104,7 @@ func (m *HashingCosts) Reset() { *m = HashingCosts{} }
func (m *HashingCosts) String() string { return proto.CompactTextString(m) }
func (*HashingCosts) ProtoMessage() {}
func (*HashingCosts) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{0}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{0}
}
func (m *HashingCosts) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HashingCosts.Unmarshal(m, b)
@@ -159,7 +159,7 @@ func (m *WrappedKeyData) Reset() { *m = WrappedKeyData{} }
func (m *WrappedKeyData) String() string { return proto.CompactTextString(m) }
func (*WrappedKeyData) ProtoMessage() {}
func (*WrappedKeyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{1}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{1}
}
func (m *WrappedKeyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedKeyData.Unmarshal(m, b)
@@ -219,7 +219,7 @@ func (m *ProtectorData) Reset() { *m = ProtectorData{} }
func (m *ProtectorData) String() string { return proto.CompactTextString(m) }
func (*ProtectorData) ProtoMessage() {}
func (*ProtectorData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{2}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{2}
}
func (m *ProtectorData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProtectorData.Unmarshal(m, b)
@@ -303,7 +303,7 @@ func (m *EncryptionOptions) Reset() { *m = EncryptionOptions{} }
func (m *EncryptionOptions) String() string { return proto.CompactTextString(m) }
func (*EncryptionOptions) ProtoMessage() {}
func (*EncryptionOptions) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{3}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{3}
}
func (m *EncryptionOptions) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptionOptions.Unmarshal(m, b)
@@ -363,7 +363,7 @@ func (m *WrappedPolicyKey) Reset() { *m = WrappedPolicyKey{} }
func (m *WrappedPolicyKey) String() string { return proto.CompactTextString(m) }
func (*WrappedPolicyKey) ProtoMessage() {}
func (*WrappedPolicyKey) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{4}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{4}
}
func (m *WrappedPolicyKey) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedPolicyKey.Unmarshal(m, b)
@@ -411,7 +411,7 @@ func (m *PolicyData) Reset() { *m = PolicyData{} }
func (m *PolicyData) String() string { return proto.CompactTextString(m) }
func (*PolicyData) ProtoMessage() {}
func (*PolicyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{5}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{5}
}
func (m *PolicyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PolicyData.Unmarshal(m, b)
@@ -456,7 +456,6 @@ func (m *PolicyData) GetWrappedPolicyKeys() []*WrappedPolicyKey {
type Config struct {
Source SourceType `protobuf:"varint,1,opt,name=source,proto3,enum=metadata.SourceType" json:"source,omitempty"`
HashCosts *HashingCosts `protobuf:"bytes,2,opt,name=hash_costs,json=hashCosts,proto3" json:"hash_costs,omitempty"`
- Compatibility string `protobuf:"bytes,3,opt,name=compatibility,proto3" json:"compatibility,omitempty"`
Options *EncryptionOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
UseFsKeyringForV1Policies bool `protobuf:"varint,5,opt,name=use_fs_keyring_for_v1_policies,json=useFsKeyringForV1Policies,proto3" json:"use_fs_keyring_for_v1_policies,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -468,7 +467,7 @@ func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_0a34c99c54153da9, []int{6}
+ return fileDescriptor_metadata_20fa0d9b7a38c428, []int{6}
}
func (m *Config) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config.Unmarshal(m, b)
@@ -502,13 +501,6 @@ func (m *Config) GetHashCosts() *HashingCosts {
return nil
}
-func (m *Config) GetCompatibility() string {
- if m != nil {
- return m.Compatibility
- }
- return ""
-}
-
func (m *Config) GetOptions() *EncryptionOptions {
if m != nil {
return m.Options
@@ -535,53 +527,53 @@ func init() {
proto.RegisterEnum("metadata.EncryptionOptions_Mode", EncryptionOptions_Mode_name, EncryptionOptions_Mode_value)
}
-func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_0a34c99c54153da9) }
-
-var fileDescriptor_metadata_0a34c99c54153da9 = []byte{
- // 717 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x5d, 0x6b, 0x13, 0x4d,
- 0x14, 0xc7, 0x9f, 0xdd, 0xa4, 0x79, 0x39, 0x79, 0x79, 0xb6, 0xd3, 0x3e, 0x7d, 0x56, 0x05, 0x09,
- 0xd1, 0x42, 0x91, 0x52, 0x49, 0xa4, 0xa2, 0x20, 0x42, 0x4d, 0x5b, 0xad, 0xa5, 0x58, 0x37, 0x21,
- 0x2a, 0x08, 0xcb, 0x74, 0x77, 0x92, 0x0c, 0xd9, 0xdd, 0x59, 0x66, 0x26, 0x0d, 0x7b, 0xe7, 0x9d,
- 0x57, 0x5e, 0xf9, 0x5d, 0xfc, 0x34, 0x7e, 0x18, 0x99, 0xd9, 0xcd, 0x5b, 0x0b, 0xa5, 0xf5, 0x66,
- 0x39, 0xf3, 0x9f, 0x33, 0xe7, 0x9c, 0xf9, 0x9d, 0x39, 0x0b, 0xff, 0x87, 0x44, 0x62, 0x1f, 0x4b,
- 0xfc, 0x74, 0x66, 0xec, 0xc5, 0x9c, 0x49, 0x86, 0x4a, 0xb3, 0x75, 0xf3, 0x2b, 0x54, 0xdf, 0x61,
- 0x31, 0xa2, 0xd1, 0xb0, 0xc3, 0x84, 0x14, 0x08, 0x41, 0x5e, 0xd2, 0x90, 0xd8, 0x66, 0xc3, 0xd8,
- 0xc9, 0x39, 0xda, 0x46, 0x5b, 0x50, 0x08, 0x49, 0xc8, 0x78, 0x62, 0xe7, 0xb4, 0x9a, 0xad, 0x50,
- 0x03, 0x2a, 0x31, 0xe6, 0x38, 0x08, 0x48, 0x40, 0x45, 0x68, 0xe7, 0xf5, 0xe6, 0xb2, 0xd4, 0xfc,
- 0x02, 0xf5, 0x4f, 0x1c, 0xc7, 0x31, 0xf1, 0x4f, 0x49, 0x72, 0x88, 0x25, 0x46, 0x75, 0x30, 0x4f,
- 0xfa, 0xb6, 0xd1, 0x30, 0x76, 0xaa, 0x8e, 0x79, 0xd2, 0x47, 0x8f, 0xa0, 0x46, 0x22, 0x8f, 0x27,
- 0xb1, 0x24, 0xbe, 0x3b, 0x26, 0x89, 0x4e, 0x5c, 0x75, 0xaa, 0x73, 0xf1, 0x94, 0x24, 0xaa, 0xa8,
- 0x51, 0x88, 0x3d, 0x9d, 0xbe, 0xea, 0x68, 0xbb, 0xf9, 0xd3, 0x84, 0xda, 0x39, 0x67, 0x92, 0x78,
- 0x92, 0x71, 0x1d, 0xba, 0x05, 0x9b, 0xf1, 0x4c, 0x70, 0x7d, 0x22, 0x3c, 0x4e, 0x63, 0xc9, 0xb8,
- 0x4e, 0x56, 0x76, 0x36, 0xe6, 0x7b, 0x87, 0xf3, 0x2d, 0xb4, 0x0b, 0x05, 0xc1, 0x26, 0xdc, 0x4b,
- 0xef, 0x5b, 0x6f, 0x6f, 0xee, 0xcd, 0x41, 0x75, 0xb5, 0xde, 0x4b, 0x62, 0xe2, 0x64, 0x3e, 0xaa,
- 0x8c, 0x08, 0x87, 0x44, 0x97, 0x51, 0x76, 0xb4, 0x8d, 0x76, 0x61, 0xcd, 0x53, 0xe0, 0xf4, 0xed,
- 0x2b, 0xed, 0xad, 0x45, 0x80, 0x65, 0xac, 0x4e, 0xea, 0xa4, 0x22, 0x08, 0x1c, 0x48, 0x7b, 0x2d,
- 0xbd, 0x88, 0xb2, 0x91, 0x05, 0xb9, 0x09, 0xf5, 0xed, 0x82, 0xa6, 0xa7, 0x4c, 0xf4, 0x12, 0x2a,
- 0xd3, 0x94, 0x9a, 0x26, 0x52, 0xd4, 0x91, 0xed, 0x45, 0xe4, 0x55, 0xa4, 0x0e, 0x4c, 0xe7, 0xeb,
- 0xe6, 0x6f, 0x13, 0xd6, 0x8f, 0x52, 0x74, 0x94, 0x45, 0x1f, 0xf4, 0x57, 0x20, 0x1b, 0x8a, 0x31,
- 0xf6, 0x7d, 0x1a, 0x0d, 0x35, 0x8c, 0x9c, 0x33, 0x5b, 0xa2, 0x57, 0x50, 0xf2, 0x58, 0x24, 0x49,
- 0x24, 0x45, 0x86, 0xa0, 0xb1, 0xc8, 0x73, 0x2d, 0xd0, 0xde, 0x19, 0xf3, 0x89, 0x33, 0x3f, 0x81,
- 0x5e, 0x43, 0x79, 0x40, 0x03, 0xa2, 0x40, 0x08, 0x4d, 0xe5, 0x36, 0xc7, 0x17, 0x47, 0xd0, 0x36,
- 0xd4, 0x63, 0x16, 0x50, 0x2f, 0x71, 0x2f, 0x09, 0x17, 0x94, 0x45, 0xd9, 0x1b, 0xaa, 0xa5, 0x6a,
- 0x3f, 0x15, 0x9b, 0xdf, 0x0d, 0xc8, 0xab, 0xa3, 0xa8, 0x02, 0x45, 0x9f, 0x0c, 0xf0, 0x24, 0x90,
- 0xd6, 0x3f, 0xe8, 0x5f, 0xa8, 0x1c, 0x1c, 0x75, 0xdd, 0xf6, 0xfe, 0x73, 0xf7, 0x73, 0xaf, 0x6b,
- 0x19, 0xcb, 0xc2, 0xdb, 0xce, 0x99, 0x65, 0x2e, 0x0b, 0x9d, 0x37, 0x1d, 0x2b, 0xb7, 0x22, 0xf4,
- 0xba, 0x56, 0x7e, 0x26, 0xb4, 0xda, 0x2f, 0xb4, 0xc7, 0xda, 0x8a, 0xd0, 0xeb, 0x5a, 0x05, 0x54,
- 0x85, 0xd2, 0x81, 0x4f, 0x71, 0x24, 0x27, 0xa1, 0x55, 0x6e, 0x7e, 0x33, 0xc0, 0xca, 0xe8, 0x9f,
- 0xeb, 0x12, 0xd5, 0xeb, 0xfc, 0x8b, 0x77, 0x77, 0xa5, 0xc3, 0xe6, 0x1d, 0x3a, 0xfc, 0xcb, 0x00,
- 0x48, 0x73, 0xeb, 0x47, 0xbf, 0x0d, 0xf5, 0x31, 0x49, 0xae, 0xa7, 0xad, 0x8d, 0x49, 0xb2, 0x94,
- 0x70, 0x1f, 0x8a, 0x2c, 0x6d, 0x42, 0x96, 0xec, 0xc1, 0x0d, 0x7d, 0x72, 0x66, 0xbe, 0xe8, 0x3d,
- 0x6c, 0xcc, 0xea, 0xcc, 0x1a, 0x35, 0x26, 0x89, 0x6a, 0x75, 0x6e, 0xa7, 0xd2, 0xbe, 0x7f, 0xad,
- 0xde, 0x39, 0x13, 0x67, 0x7d, 0x7a, 0x45, 0x11, 0xcd, 0x1f, 0x26, 0x14, 0x3a, 0x2c, 0x1a, 0xd0,
- 0xe1, 0xd2, 0xd8, 0x19, 0xb7, 0x18, 0xbb, 0x7d, 0x80, 0x11, 0x16, 0x23, 0x37, 0x9d, 0x33, 0xf3,
- 0xc6, 0x39, 0x2b, 0x2b, 0xcf, 0xf4, 0x4f, 0xf6, 0x18, 0x6a, 0x1e, 0x0b, 0x63, 0x2c, 0xe9, 0x05,
- 0x0d, 0xa8, 0x4c, 0xb2, 0xb1, 0x5d, 0x15, 0x97, 0xc1, 0xe4, 0xef, 0x00, 0xe6, 0x00, 0x1e, 0x4e,
- 0x04, 0x71, 0x07, 0x42, 0x01, 0xe1, 0x34, 0x1a, 0xba, 0x03, 0xc6, 0xdd, 0xcb, 0x56, 0x8a, 0x89,
- 0x12, 0xa1, 0x47, 0xbc, 0xe4, 0xdc, 0x9b, 0x08, 0x72, 0x2c, 0x4e, 0x53, 0x9f, 0x63, 0xc6, 0xfb,
- 0xad, 0xf3, 0xcc, 0xe1, 0xc9, 0x47, 0x80, 0xc5, 0x65, 0x57, 0x9f, 0x36, 0x82, 0x7a, 0x8c, 0x43,
- 0x37, 0xc6, 0x42, 0xc4, 0x23, 0x8e, 0x05, 0xb1, 0x0c, 0xf4, 0x1f, 0xac, 0x7b, 0x13, 0x21, 0xd9,
- 0x8a, 0x6c, 0xaa, 0x73, 0x1c, 0x4f, 0x55, 0x15, 0x56, 0xee, 0xa2, 0xa0, 0xff, 0xee, 0xcf, 0xfe,
- 0x04, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x97, 0x5e, 0xdf, 0xf8, 0x05, 0x00, 0x00,
+func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_20fa0d9b7a38c428) }
+
+var fileDescriptor_metadata_20fa0d9b7a38c428 = []byte{
+ // 716 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xdd, 0x6a, 0xdb, 0x48,
+ 0x14, 0x5e, 0x49, 0x8e, 0x7f, 0x8e, 0x7f, 0x56, 0x99, 0x64, 0xb3, 0xda, 0x5d, 0x58, 0x8c, 0x97,
+ 0x40, 0x58, 0x42, 0x16, 0x7b, 0x49, 0x69, 0xa1, 0x14, 0x52, 0x27, 0x69, 0x93, 0x10, 0x9a, 0x8e,
+ 0x8d, 0xdb, 0x42, 0x41, 0x4c, 0xa4, 0xb1, 0x3d, 0x58, 0xd2, 0x88, 0x99, 0x71, 0x8c, 0xee, 0x7a,
+ 0xd7, 0x07, 0xe8, 0xbb, 0xf4, 0x69, 0xfa, 0x28, 0xbd, 0x28, 0x1a, 0xc9, 0x7f, 0x09, 0x84, 0xa4,
+ 0x37, 0xe2, 0x9c, 0x6f, 0xce, 0xef, 0x77, 0xce, 0x11, 0xfc, 0x1e, 0x52, 0x45, 0x7c, 0xa2, 0xc8,
+ 0x7f, 0x73, 0xe1, 0x20, 0x16, 0x5c, 0x71, 0x54, 0x9e, 0xeb, 0xad, 0x8f, 0x50, 0x7b, 0x4d, 0xe4,
+ 0x98, 0x45, 0xa3, 0x2e, 0x97, 0x4a, 0x22, 0x04, 0x05, 0xc5, 0x42, 0xea, 0x98, 0x4d, 0x63, 0xcf,
+ 0xc2, 0x5a, 0x46, 0x3b, 0x50, 0x0c, 0x69, 0xc8, 0x45, 0xe2, 0x58, 0x1a, 0xcd, 0x35, 0xd4, 0x84,
+ 0x6a, 0x4c, 0x04, 0x09, 0x02, 0x1a, 0x30, 0x19, 0x3a, 0x05, 0xfd, 0xb8, 0x0a, 0xb5, 0x3e, 0x40,
+ 0xe3, 0x9d, 0x20, 0x71, 0x4c, 0xfd, 0x0b, 0x9a, 0x1c, 0x13, 0x45, 0x50, 0x03, 0xcc, 0xb3, 0x81,
+ 0x63, 0x34, 0x8d, 0xbd, 0x1a, 0x36, 0xcf, 0x06, 0xe8, 0x1f, 0xa8, 0xd3, 0xc8, 0x13, 0x49, 0xac,
+ 0xa8, 0xef, 0x4e, 0x68, 0xa2, 0x13, 0xd7, 0x70, 0x6d, 0x01, 0x5e, 0xd0, 0x24, 0x2d, 0x6a, 0x1c,
+ 0x12, 0x4f, 0xa7, 0xaf, 0x61, 0x2d, 0xb7, 0xbe, 0x98, 0x50, 0xbf, 0x12, 0x5c, 0x51, 0x4f, 0x71,
+ 0xa1, 0x43, 0xb7, 0x61, 0x3b, 0x9e, 0x03, 0xae, 0x4f, 0xa5, 0x27, 0x58, 0xac, 0xb8, 0xd0, 0xc9,
+ 0x2a, 0x78, 0x6b, 0xf1, 0x76, 0xbc, 0x78, 0x42, 0xfb, 0x50, 0x94, 0x7c, 0x2a, 0xbc, 0xac, 0xdf,
+ 0x46, 0x67, 0xfb, 0x60, 0x41, 0x54, 0x4f, 0xe3, 0xfd, 0x24, 0xa6, 0x38, 0xb7, 0x49, 0xcb, 0x88,
+ 0x48, 0x48, 0x75, 0x19, 0x15, 0xac, 0x65, 0xb4, 0x0f, 0x1b, 0x5e, 0x4a, 0x9c, 0xee, 0xbe, 0xda,
+ 0xd9, 0x59, 0x06, 0x58, 0xa5, 0x15, 0x67, 0x46, 0x69, 0x04, 0x49, 0x02, 0xe5, 0x6c, 0x64, 0x8d,
+ 0xa4, 0x32, 0xb2, 0xc1, 0x9a, 0x32, 0xdf, 0x29, 0x6a, 0xf6, 0x52, 0x11, 0x3d, 0x83, 0xea, 0x2c,
+ 0x63, 0x4d, 0x33, 0x52, 0xd2, 0x91, 0x9d, 0x65, 0xe4, 0x75, 0x4a, 0x31, 0xcc, 0x16, 0x7a, 0xeb,
+ 0x9b, 0x09, 0x9b, 0x27, 0x19, 0x75, 0x8c, 0x47, 0x6f, 0xf4, 0x57, 0x22, 0x07, 0x4a, 0x31, 0xf1,
+ 0x7d, 0x16, 0x8d, 0x34, 0x19, 0x16, 0x9e, 0xab, 0xe8, 0x39, 0x94, 0x3d, 0x1e, 0x29, 0x1a, 0x29,
+ 0x99, 0x53, 0xd0, 0x5c, 0xe6, 0xb9, 0x13, 0xe8, 0xe0, 0x92, 0xfb, 0x14, 0x2f, 0x3c, 0xd0, 0x0b,
+ 0xa8, 0x0c, 0x59, 0x40, 0x53, 0x22, 0xa4, 0x66, 0xe5, 0x21, 0xee, 0x4b, 0x17, 0xb4, 0x0b, 0x8d,
+ 0x98, 0x07, 0xcc, 0x4b, 0xdc, 0x1b, 0x2a, 0x24, 0xe3, 0x51, 0xbe, 0x43, 0xf5, 0x0c, 0x1d, 0x64,
+ 0x60, 0xeb, 0xb3, 0x01, 0x85, 0xd4, 0x15, 0x55, 0xa1, 0xe4, 0xd3, 0x21, 0x99, 0x06, 0xca, 0xfe,
+ 0x05, 0xfd, 0x0a, 0xd5, 0xa3, 0x93, 0x9e, 0xdb, 0x39, 0x7c, 0xe2, 0xbe, 0xef, 0xf7, 0x6c, 0x63,
+ 0x15, 0x78, 0xd5, 0xbd, 0xb4, 0xcd, 0x55, 0xa0, 0xfb, 0xb2, 0x6b, 0x5b, 0x6b, 0x40, 0xbf, 0x67,
+ 0x17, 0xe6, 0x40, 0xbb, 0xf3, 0x54, 0x5b, 0x6c, 0xac, 0x01, 0xfd, 0x9e, 0x5d, 0x44, 0x35, 0x28,
+ 0x1f, 0xf9, 0x8c, 0x44, 0x6a, 0x1a, 0xda, 0x95, 0xd6, 0x27, 0x03, 0xec, 0x9c, 0xfd, 0x2b, 0x5d,
+ 0x62, 0xba, 0x9d, 0x3f, 0xb1, 0x77, 0xb7, 0x26, 0x6c, 0x3e, 0x62, 0xc2, 0x5f, 0x0d, 0x80, 0x2c,
+ 0xb7, 0x5e, 0xfa, 0x5d, 0x68, 0x4c, 0x68, 0x72, 0x37, 0x6d, 0x7d, 0x42, 0x93, 0x95, 0x84, 0x87,
+ 0x50, 0xe2, 0xd9, 0x10, 0xf2, 0x64, 0x7f, 0xdd, 0x33, 0x27, 0x3c, 0xb7, 0x45, 0xe7, 0xb0, 0x35,
+ 0xaf, 0x33, 0x1f, 0xd4, 0x84, 0x26, 0xe9, 0xa8, 0xad, 0xbd, 0x6a, 0xe7, 0xcf, 0x3b, 0xf5, 0x2e,
+ 0x38, 0xc1, 0x9b, 0xb3, 0x5b, 0x88, 0x6c, 0x7d, 0x37, 0xa0, 0xd8, 0xe5, 0xd1, 0x90, 0x8d, 0x56,
+ 0xce, 0xce, 0x78, 0xc0, 0xd9, 0x1d, 0x02, 0x8c, 0x89, 0x1c, 0xbb, 0xd9, 0x9d, 0x99, 0xf7, 0xde,
+ 0x59, 0x25, 0xb5, 0xcc, 0xfe, 0x64, 0x2b, 0x2d, 0x17, 0x1e, 0xd1, 0xf2, 0x11, 0xfc, 0x3d, 0x95,
+ 0xd4, 0x1d, 0xca, 0xb4, 0x55, 0xc1, 0xa2, 0x91, 0x3b, 0xe4, 0xc2, 0xbd, 0x69, 0x67, 0x04, 0x30,
+ 0x2a, 0xf5, 0xf1, 0x96, 0xf1, 0x1f, 0x53, 0x49, 0x4f, 0xe5, 0x45, 0x66, 0x73, 0xca, 0xc5, 0xa0,
+ 0x7d, 0x95, 0x1b, 0x9c, 0x17, 0xca, 0x96, 0x5d, 0xc0, 0x75, 0x8f, 0x87, 0x31, 0x51, 0xec, 0x9a,
+ 0x05, 0x4c, 0x25, 0xff, 0xbe, 0x05, 0x58, 0xf6, 0xb6, 0xbe, 0xc9, 0x08, 0x1a, 0x31, 0x09, 0xdd,
+ 0x98, 0x48, 0x19, 0x8f, 0x05, 0x91, 0xd4, 0x36, 0xd0, 0x6f, 0xb0, 0xe9, 0x4d, 0xa5, 0xe2, 0x6b,
+ 0xb0, 0x99, 0xfa, 0x09, 0x32, 0x4b, 0x4b, 0xb3, 0xad, 0xeb, 0xa2, 0xfe, 0x99, 0xff, 0xff, 0x23,
+ 0x00, 0x00, 0xff, 0xff, 0x3d, 0x33, 0x9f, 0x0d, 0xe7, 0x05, 0x00, 0x00,
}
diff --git a/metadata/metadata.proto b/metadata/metadata.proto
index 81b3bf9..8ffb4f6 100644
--- a/metadata/metadata.proto
+++ b/metadata/metadata.proto
@@ -97,7 +97,10 @@ message PolicyData {
message Config {
SourceType source = 1;
HashingCosts hash_costs = 2;
- string compatibility = 3;
EncryptionOptions options = 4;
bool use_fs_keyring_for_v1_policies = 5;
+
+ // reserve the removed field 'string compatibility = 3;'
+ reserved 3;
+ reserved "compatibility";
}
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")
+ }
+}