diff options
author | Eric Biggers <ebiggers@google.com> | 2019-09-17 18:07:34 -0700 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2019-10-09 20:18:20 -0400 |
commit | 2ba05753f70db32618b4e97d5351aa4d359bcdee (patch) | |
tree | a7c284a2665acd6730dbd6275aea0ee69c827aec /tests | |
parent | 6c1433ba434021b457a9b6aefe57c0e8cb71f5fe (diff) | |
download | e2fsprogs-2ba05753f70db32618b4e97d5351aa4d359bcdee.tar.gz |
e2fsck: check for consistent encryption policies
By design, the kernel enforces that all files in an encrypted directory
use the same encryption policy as the directory. It's not possible to
violate this constraint using syscalls. Lookups of files that violate
this constraint also fail, in case the disk was manipulated.
But this constraint can also be violated by accidental filesystem
corruption. E.g., a power cut when using ext4 without a journal might
leave new files without the encryption bit and/or xattr. Thus, it's
important that e2fsck correct this condition.
Therefore, this patch makes the following changes to e2fsck:
- During pass 1 (inode table scan), create a map from inode number to
encryption policy for all encrypted inodes. But it's optimized so
that the full xattrs aren't saved but rather only 32-bit "policy IDs",
since usually many inodes share the same encryption policy. Also, if
an encryption xattr is missing, offer to clear the encrypt flag. If
an encryption xattr is clearly corrupt, offer to clear the inode.
- During pass 2 (directory structure check), use the map to verify that
all regular files, directories, and symlinks in encrypted directories
use the directory's encryption policy. Offer to clear any directory
entries for which this isn't the case.
Add a new test "f_bad_encryption" to test the new behavior.
Due to the new checks, it was also necessary to update the existing test
"f_short_encrypted_dirent" to add an encryption xattr to the test file,
since it was missing one before, which is now considered invalid.
Google-Bug-Id: 135138675
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/f_bad_encryption/expect.1 | 125 | ||||
-rw-r--r-- | tests/f_bad_encryption/expect.2 | 7 | ||||
-rw-r--r-- | tests/f_bad_encryption/image.gz | bin | 0 -> 2265 bytes | |||
-rwxr-xr-x | tests/f_bad_encryption/mkimage.sh | 169 | ||||
-rw-r--r-- | tests/f_bad_encryption/name | 1 | ||||
-rw-r--r-- | tests/f_short_encrypted_dirent/expect.1 | 2 | ||||
-rw-r--r-- | tests/f_short_encrypted_dirent/expect.2 | 2 | ||||
-rw-r--r-- | tests/f_short_encrypted_dirent/image.gz | bin | 925 -> 1008 bytes |
8 files changed, 304 insertions, 2 deletions
diff --git a/tests/f_bad_encryption/expect.1 b/tests/f_bad_encryption/expect.1 new file mode 100644 index 000000000..d743e66f7 --- /dev/null +++ b/tests/f_bad_encryption/expect.1 @@ -0,0 +1,125 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 17 has encrypt flag but no encryption extended attribute. +Clear flag? yes + +Inode 18 has encrypt flag but no encryption extended attribute. +Clear flag? yes + +Encrypted inode 19 has corrupt encryption extended attribute. +Clear inode? yes + +Encrypted inode 20 has corrupt encryption extended attribute. +Clear inode? yes + +Encrypted inode 21 has corrupt encryption extended attribute. +Clear inode? yes + +Encrypted inode 22 has corrupt encryption extended attribute. +Clear inode? yes + +Pass 2: Checking directory structure +Encrypted entry 'd6M->'M-#I^VM-^KM-F~^WSJ+M-uM-zM-zXM-^' in /edir (12) references unencrypted inode 17. +Clear? yes + +Encrypted entry '\M-!M-Y%DhM-OM-VM-zM-CM-gVM-R3M-^RM-IkE^JM-^S' in /edir (12) references unencrypted inode 18. +Clear? yes + +Entry 'M-{^Qp-M-sM-U7eM-^C^L^PG^ZM-FM-,M-B' in /edir (12) has deleted/unused inode 19. Clear? yes + +Entry 'M-f0M-f3/M-NM-GM-:M-^YM-jM-XM-91DM-^_M-V' in /edir (12) has deleted/unused inode 20. Clear? yes + +Entry '^M-R"M-^K^P7M-'M-EM-C}^MM-yM-^LwM-^N^Z' in /edir (12) has deleted/unused inode 21. Clear? yes + +Entry 'M-s^J_;uIvM-^Z[M-nIM-5vM-^AcM-o' in /edir (12) has deleted/unused inode 22. Clear? yes + +Encrypted entry 'kK=,M-bM-^AM-{M-YM-^J6M-hM-y^XM-^W}M-M' in /edir (12) references unencrypted inode 23. +Clear? yes + +Encrypted entry 'M-VM-cxM-jM-zM-b^WM-o*M-jM-uM-,R^PM-hM-2' in /edir (12) references unencrypted inode 24. +Clear? yes + +Encrypted entry 'UqM-AM-#KM-^PM-_^kM-9P0M-^FM-_^@;A^J"R' in /edir (12) references unencrypted inode 25. +Clear? yes + +Encrypted entry 'M-TM-N8^[M-3M-( M-[A^FR}^ZhkM-^?=M-c^Mo' in /edir (12) references inode 26, which has a different encryption policy. +Clear? yes + +Encrypted entry 'M--aM-^?~M-^\M-u^FM-/!^YM-OZM-^LM-)M-p1' in /edir (12) references inode 27, which has a different encryption policy. +Clear? yes + +Encrypted entry '(M-8RKM-LM-eM-^W^[M-'M-SM-@uM-^VM-|M-GiM-^JbM-nM-z' in /edir (12) references inode 28, which has a different encryption policy. +Clear? yes + +Encrypted entry '\M-ggCeM-/?M-^BM-{(M-^OM-9M-^QQAM-^N=M-c^Mo' in /edir (12) references inode 29, which has a different encryption policy. +Clear? yes + +Pass 3: Checking directory connectivity +Unconnected directory inode 18 (/edir/???) +Connect to /lost+found? yes + +Unconnected directory inode 24 (/edir/???) +Connect to /lost+found? yes + +Unconnected directory inode 27 (/edir/???) +Connect to /lost+found? yes + +Pass 4: Checking reference counts +Unattached inode 17 +Connect to /lost+found? yes + +Inode 17 ref count is 2, should be 1. Fix? yes + +Inode 18 ref count is 3, should be 2. Fix? yes + +Unattached inode 23 +Connect to /lost+found? yes + +Inode 23 ref count is 2, should be 1. Fix? yes + +Inode 24 ref count is 3, should be 2. Fix? yes + +Unattached inode 25 +Connect to /lost+found? yes + +Inode 25 ref count is 2, should be 1. Fix? yes + +Unattached inode 26 +Connect to /lost+found? yes + +Inode 26 ref count is 2, should be 1. Fix? yes + +Inode 27 ref count is 3, should be 2. Fix? yes + +Unattached inode 28 +Connect to /lost+found? yes + +Inode 28 ref count is 2, should be 1. Fix? yes + +Unattached inode 29 +Connect to /lost+found? yes + +Inode 29 ref count is 2, should be 1. Fix? yes + +Pass 5: Checking group summary information +Block bitmap differences: -(25--32) +Fix? yes + +Free blocks count wrong for group #0 (75, counted=83). +Fix? yes + +Free blocks count wrong (75, counted=83). +Fix? yes + +Inode bitmap differences: -(19--22) +Fix? yes + +Free inodes count wrong for group #0 (95, counted=99). +Fix? yes + +Free inodes count wrong (95, counted=99). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 29/128 files (0.0% non-contiguous), 45/128 blocks +Exit status is 1 diff --git a/tests/f_bad_encryption/expect.2 b/tests/f_bad_encryption/expect.2 new file mode 100644 index 000000000..fcfabdbd2 --- /dev/null +++ b/tests/f_bad_encryption/expect.2 @@ -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: 29/128 files (0.0% non-contiguous), 45/128 blocks +Exit status is 0 diff --git a/tests/f_bad_encryption/image.gz b/tests/f_bad_encryption/image.gz Binary files differnew file mode 100644 index 000000000..64b59b78b --- /dev/null +++ b/tests/f_bad_encryption/image.gz diff --git a/tests/f_bad_encryption/mkimage.sh b/tests/f_bad_encryption/mkimage.sh new file mode 100755 index 000000000..e58395dfc --- /dev/null +++ b/tests/f_bad_encryption/mkimage.sh @@ -0,0 +1,169 @@ +#!/bin/bash +# +# This is the script that was used to create the image.gz in this directory. +# +# This requires a patched version of debugfs that understands the "fscrypt." +# xattr name prefix, so that the encryption xattrs can be manipulated. + +set -e -u +umask 0022 + +do_debugfs() { + umount mnt + debugfs -w "$@" image + mount image mnt +} + +create_encrypted_file() { + local file=$1 + local ino + + echo foo > "$file" + + # not needed, but makes image more compressible + ino=$(stat -c %i "$file") + do_debugfs -R "zap_block -f <$ino> 0" +} + +set_encryption_xattr() { + local file=$1 + local value=$2 + local ino + + ino=$(stat -c %i "$file") + do_debugfs -R "ea_set <$ino> fscrypt.c $value" +} + +rm_encryption_xattr() { + local file=$1 + local ino + + ino=$(stat -c %i "$file") + do_debugfs -R "ea_rm <$ino> fscrypt.c" +} + +clear_encrypt_flag() { + local file=$1 + local ino + + ino=$(stat -c %i "$file") + do_debugfs -R "set_inode_field <$ino> flags 0" +} + +clear_encryption() { + local file=$1 + local ino + local is_symlink=false + + if [ -L "$file" ]; then + is_symlink=true + fi + ino=$(stat -c %i "$file") + + do_debugfs -R "ea_rm <$ino> fscrypt.c" + do_debugfs -R "set_inode_field <$ino> flags 0" + if $is_symlink; then + do_debugfs -R "set_inode_field <$ino> block[0] 0xAAAAAAAA" + do_debugfs -R "set_inode_field <$ino> block[1] 0" + do_debugfs -R "set_inode_field <$ino> size 4" + fi +} + +mkdir -p mnt +umount mnt &> /dev/null || true + +dd if=/dev/zero of=image bs=4096 count=128 +mke2fs -O encrypt -b 4096 -N 128 image +mount image mnt + +# Create an encrypted directory (ino 12) +dir=mnt/edir +mkdir $dir +echo password | e4crypt add_key $dir + +# Control cases: valid encrypted regular file, dir, and symlink (ino 13-15) +create_encrypted_file $dir/encrypted_file +mkdir $dir/encrypted_dir +ln -s target $dir/encrypted_symlink + +# Control case: file type that is never encrypted (ino 16) +mkfifo $dir/fifo + +# Inodes with missing encryption xattr (ino 17-18). +# e2fsck should offer to clear the encrypt flag on these inodes. + +create_encrypted_file $dir/missing_xattr_file +rm_encryption_xattr $dir/missing_xattr_file + +mkdir $dir/missing_xattr_dir +rm_encryption_xattr $dir/missing_xattr_dir + +# Inodes with corrupt encryption xattr (ino 19-22). +# e2fsck should offer to clear these inodes. + +create_encrypted_file $dir/corrupt_xattr_1 +set_encryption_xattr $dir/corrupt_xattr_1 '\0' + +create_encrypted_file $dir/corrupt_xattr_2 +set_encryption_xattr $dir/corrupt_xattr_2 \ + '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' + +create_encrypted_file $dir/corrupt_xattr_3 +set_encryption_xattr $dir/corrupt_xattr_3 '\1' + +create_encrypted_file $dir/corrupt_xattr_4 +set_encryption_xattr $dir/corrupt_xattr_4 '\2' + +# Unencrypted inodes in encrypted directory (ino 23-25). +# e2fsck should offer to clear these directory entries. + +create_encrypted_file $dir/unencrypted_file +clear_encryption $dir/unencrypted_file + +mkdir $dir/unencrypted_dir +clear_encryption $dir/unencrypted_dir + +ln -s target $dir/unencrypted_symlink +clear_encryption $dir/unencrypted_symlink + +# Inodes with different encryption policy in encrypted directory (ino 26-29). +# e2fsck should offer to clear these directory entries. + +xattr='\1\1\4\0AAAAAAAABBBBBBBBBBBBBBBB' + +create_encrypted_file $dir/inconsistent_file_1 +set_encryption_xattr $dir/inconsistent_file_1 $xattr + +mkdir $dir/inconsistent_dir +set_encryption_xattr $dir/inconsistent_dir $xattr + +ln -s target $dir/inconsistent_symlink +set_encryption_xattr $dir/inconsistent_symlink $xattr + +xattr='\2\1\4\0\0\0\0\0AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB' +create_encrypted_file $dir/inconsistent_file_2 +set_encryption_xattr $dir/inconsistent_file_2 $xattr + +# Encrypted file and directory with valid v2 encryption policy (ino 30-31). +# e2fsck shouldn't change these. +dir2=mnt/edir2 +mkdir $dir2 +echo password | e4crypt add_key $dir2 +xattr='\2\1\4\0\0\0\0\0AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB' +create_encrypted_file $dir2/file +set_encryption_xattr $dir2/file $xattr +set_encryption_xattr $dir2 $xattr + +# Encrypted file and directory with unrecognized encryption policy version +# (ino 32-33). e2fsck shouldn't change these. +dir3=mnt/edir3 +mkdir $dir3 +echo password | e4crypt add_key $dir3 +xattr='\3' +create_encrypted_file $dir3/file +set_encryption_xattr $dir3/file $xattr +set_encryption_xattr $dir3 $xattr + +umount mnt +rmdir mnt +gzip -9 -f image diff --git a/tests/f_bad_encryption/name b/tests/f_bad_encryption/name new file mode 100644 index 000000000..85b19eda1 --- /dev/null +++ b/tests/f_bad_encryption/name @@ -0,0 +1 @@ +missing, corrupt, and inconsistent encryption policies diff --git a/tests/f_short_encrypted_dirent/expect.1 b/tests/f_short_encrypted_dirent/expect.1 index bc649222e..29e1625c4 100644 --- a/tests/f_short_encrypted_dirent/expect.1 +++ b/tests/f_short_encrypted_dirent/expect.1 @@ -13,5 +13,5 @@ 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 +test_filesys: 13/16 files (0.0% non-contiguous), 24/100 blocks Exit status is 1 diff --git a/tests/f_short_encrypted_dirent/expect.2 b/tests/f_short_encrypted_dirent/expect.2 index 636c6e9ec..1ebd598ee 100644 --- a/tests/f_short_encrypted_dirent/expect.2 +++ b/tests/f_short_encrypted_dirent/expect.2 @@ -3,5 +3,5 @@ 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 +test_filesys: 13/16 files (0.0% non-contiguous), 24/100 blocks Exit status is 0 diff --git a/tests/f_short_encrypted_dirent/image.gz b/tests/f_short_encrypted_dirent/image.gz Binary files differindex a35bfb23b..7eb1c951f 100644 --- a/tests/f_short_encrypted_dirent/image.gz +++ b/tests/f_short_encrypted_dirent/image.gz |