]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: check for encrypted directory entries with too-short file names
authorTheodore Ts'o <tytso@mit.edu>
Thu, 16 Jul 2015 21:19:38 +0000 (17:19 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 16 Jul 2015 22:02:58 +0000 (18:02 -0400)
If there are directory entries with file names which are less than 16
bytes, it turns out that passing less than the crypto block size to
the kernel's crypto layer will cause the kernel to crash.

However, since there never should be encrypted directory entries where
the file name is less than 16 bytes (the AES block size), change
e2fsck to offer to address this corruption by deleting the directory
entry.

(We need to checks for this condition into the kernel as well.)

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass2.c
e2fsck/problem.c
e2fsck/problem.h
lib/ext2fs/ext2_fs.h
tests/f_short_encrypted_dirent/expect.1 [new file with mode: 0644]
tests/f_short_encrypted_dirent/expect.2 [new file with mode: 0644]
tests/f_short_encrypted_dirent/image.gz [new file with mode: 0644]
tests/f_short_encrypted_dirent/name [new file with mode: 0644]

index f4913f6ade212ed6bf9b2a9ace00f839f022a58c..2e9a90d48bcac62d42e45dd1f743e77b4f727143 100644 (file)
@@ -494,6 +494,20 @@ static int check_name(e2fsck_t ctx,
        return ret;
 }
 
+static int encrypted_check_name(e2fsck_t ctx,
+                               struct ext2_dir_entry *dirent,
+                               struct problem_context *pctx)
+{
+       if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) {
+               if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) {
+                       dirent->inode = 0;
+                       return 1;
+               }
+               ext2fs_unmark_valid(ctx->fs);
+       }
+       return 0;
+}
+
 /*
  * Check the directory filetype (if present)
  */
@@ -1383,6 +1397,12 @@ skip_checksum:
                if (!encrypted && check_name(ctx, dirent, &cd->pctx))
                        dir_modified++;
 
+               if (encrypted && (dot_state) > 1 &&
+                   encrypted_check_name(ctx, dirent, &cd->pctx)) {
+                       dir_modified++;
+                       goto next;
+               }
+
                if (check_filetype(ctx, dirent, ino, &cd->pctx))
                        dir_modified++;
 
index 084131abc902c5891b67d50fcec6444824b7346d..9ef689a20b58fa06058664ad051ead0c36f037e9 100644 (file)
@@ -1613,6 +1613,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Fixing size of inline @d @i %i failed.\n"),
          PROMPT_TRUNCATE, 0 },
 
+       /* Encrypted directory entry is too short */
+       { PR_2_BAD_ENCRYPTED_NAME,
+         N_("Encrypted @E is too short.\n"),
+         PROMPT_CLEAR, 0 },
+
        /* Pass 3 errors */
 
        /* Pass 3: Checking directory connectivity */
index 5af3edf0370ada07f65d5f0c5659cbc8e7c4771c..2ff0f5efa4a28c55edb7274f9b94f17ecd3f7213 100644 (file)
@@ -963,6 +963,9 @@ struct problem_context {
 /* fixing inline dir size failed */
 #define PR_2_FIX_INLINE_DIR_FAILED     0x02004F
 
+/* Encrypted directory entry is too short */
+#define PR_2_BAD_ENCRYPTED_NAME                0x020050
+
 /*
  * Pass 3 errors
  */
index 918ae707e349b747c4696ca5b49003d9679e57de..cfeaa050847eb339c65e62a1661315ddd0a9719d 100644 (file)
@@ -579,6 +579,7 @@ struct ext2_inode_large {
 #define EXT4_MAX_KEY_SIZE                      64
 
 #define EXT4_KEY_DESCRIPTOR_SIZE               8
+#define EXT4_CRYPTO_BLOCK_SIZE                 16
 
 /* Password derivation constants */
 #define EXT4_MAX_PASSPHRASE_SIZE               1024
diff --git a/tests/f_short_encrypted_dirent/expect.1 b/tests/f_short_encrypted_dirent/expect.1
new file mode 100644 (file)
index 0000000..bc64922
--- /dev/null
@@ -0,0 +1,17 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Encrypted entry 'motd' in /get_shorty (12) is too short.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Unattached inode 13
+Connect to /lost+found? yes
+
+Inode 13 ref count is 2, should be 1.  Fix? yes
+
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks
+Exit status is 1
diff --git a/tests/f_short_encrypted_dirent/expect.2 b/tests/f_short_encrypted_dirent/expect.2
new file mode 100644 (file)
index 0000000..636c6e9
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks
+Exit status is 0
diff --git a/tests/f_short_encrypted_dirent/image.gz b/tests/f_short_encrypted_dirent/image.gz
new file mode 100644 (file)
index 0000000..a35bfb2
Binary files /dev/null and b/tests/f_short_encrypted_dirent/image.gz differ
diff --git a/tests/f_short_encrypted_dirent/name b/tests/f_short_encrypted_dirent/name
new file mode 100644 (file)
index 0000000..a35028a
--- /dev/null
@@ -0,0 +1 @@
+short encrypted directory entry