]> git.apps.os.sepia.ceph.com Git - fscrypt.git/commitdiff
cmd/fscrypt: fix isDirUnlockedHeuristic() on latest kernels
authorEric Biggers <ebiggers@google.com>
Sat, 7 Nov 2020 22:20:45 +0000 (14:20 -0800)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 7 Nov 2020 22:49:02 +0000 (14:49 -0800)
On an "incompletely locked" directory, isDirUnlockedHeuristic() is
supposed to return true, but on Linux v5.10-rc1 and later it returns
false since now creating a subdirectory fails rather than succeeds.
This change was intentional, so make isDirUnlockedHeuristic() apply a
second heuristic too: also return true if any filenames in the directory
don't appear to be valid no-key names.

This fixes cli-tests/t_v1_encrypt on Linux v5.10-rc1 and later.

cmd/fscrypt/commands.go

index 7c123563f75c59e4c2a9fdb1ed7d472aa651de13..e6c8ecc370052297ff47c99f89df8113f32c463d 100644 (file)
@@ -25,6 +25,7 @@ import (
        "log"
        "os"
        "path/filepath"
+       "strings"
 
        "github.com/pkg/errors"
        "github.com/urfave/cli"
@@ -532,8 +533,25 @@ func lockAction(c *cli.Context) error {
        return nil
 }
 
-// isDirUnlockedHeuristic returns true if we can create a subdirectory of the
-// given directory and therefore it is definitely still unlocked.  It returns
+func isPossibleNoKeyName(filename string) bool {
+       // No-key names are at least 22 bytes long, since they are
+       // base64-encoded and ciphertext filenames are at least 16 bytes.
+       if len(filename) < 22 {
+               return false
+       }
+       // No-key names contain only base64 characters and underscore.
+       validChars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,_"
+       for _, char := range filename {
+               if !strings.ContainsRune(validChars, char) {
+                       return false
+               }
+       }
+       return true
+}
+
+// isDirUnlockedHeuristic returns true if the directory is definitely still
+// unlocked.  This is the case if we can create a subdirectory or if the
+// directory contains filenames that aren't valid no-key names.  It returns
 // false if the directory is probably locked (though it could also be unlocked).
 //
 // This is only useful if the directory's policy uses the user keyring, since
@@ -544,6 +562,21 @@ func isDirUnlockedHeuristic(dirPath string) bool {
                os.Remove(subdirPath)
                return true
        }
+       dir, err := os.Open(dirPath)
+       if err != nil {
+               return false
+       }
+       defer dir.Close()
+
+       names, err := dir.Readdirnames(-1)
+       if err != nil {
+               return false
+       }
+       for _, name := range names {
+               if !isPossibleNoKeyName(name) {
+                       return true
+               }
+       }
        return false
 }