* [PATCH v4 1/6] generic: add utilities for testing filesystem encryption
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-15 20:26 ` [PATCH v4 2/6] generic: test setting and getting encryption policies Eric Biggers
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Add utility functions for testing filesystem-level encryption via the
common API currently supported by ext4 and f2fs, in development for
ubifs and planned for xfs. Setting and getting encryption policies will
use new commands being added to xfs_io, while adding and removing
encryption keys will use keyctl.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
common/config | 1 +
common/encrypt | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+)
create mode 100644 common/encrypt
diff --git a/common/config b/common/config
index f0f08d2..3727ec0 100644
--- a/common/config
+++ b/common/config
@@ -202,6 +202,7 @@ export DEBUGFS_PROG="`set_prog_path debugfs`"
export UUIDGEN_PROG="`set_prog_path uuidgen`"
export GETRICHACL_PROG="`set_prog_path getrichacl`"
export SETRICHACL_PROG="`set_prog_path setrichacl`"
+export KEYCTL_PROG="`set_prog_path keyctl`"
# use 'udevadm settle' or 'udevsettle' to wait for lv to be settled.
# newer systems have udevadm command but older systems like RHEL5 don't.
diff --git a/common/encrypt b/common/encrypt
new file mode 100644
index 0000000..f09104d
--- /dev/null
+++ b/common/encrypt
@@ -0,0 +1,146 @@
+#-----------------------------------------------------------------------
+#
+# Common functions for testing filesystem-level encryption
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+
+_require_scratch_encryption()
+{
+ _require_scratch
+
+ _require_xfs_io_command "set_encpolicy"
+
+ # The 'test_dummy_encryption' mount option interferes with trying to use
+ # encryption for real, even if we are just trying to get/set policies
+ # and never put any keys in the keyring. So skip the real encryption
+ # tests if the 'test_dummy_encryption' mount option was specified.
+ _exclude_scratch_mount_option "test_dummy_encryption"
+
+ # Make a filesystem on the scratch device with the encryption feature
+ # enabled. If this fails then probably the userspace tools (e.g.
+ # e2fsprogs or f2fs-tools) are too old to understand encryption.
+ if ! _scratch_mkfs_encrypted &>>$seqres.full; then
+ _notrun "$FSTYP userspace tools do not support encryption"
+ fi
+
+ # Try to mount the filesystem. If this fails then either the kernel
+ # isn't aware of encryption, or the mkfs options were not compatible
+ # with encryption (e.g. ext4 with block size != PAGE_SIZE).
+ if ! _scratch_mount &>>$seqres.full; then
+ _notrun "kernel is unaware of $FSTYP encryption feature," \
+ "or mkfs options are not compatible with encryption"
+ fi
+
+ # The kernel may be aware of encryption without supporting it. For
+ # example, for ext4 this is the case with kernels configured with
+ # CONFIG_EXT4_FS_ENCRYPTION=n. Detect support for encryption by trying
+ # to set an encryption policy. (For ext4 we could instead check for the
+ # presence of /sys/fs/ext4/features/encryption, but this is broken on
+ # some older kernels and is ext4-specific anyway.)
+ mkdir $SCRATCH_MNT/tmpdir
+ if $XFS_IO_PROG -c set_encpolicy $SCRATCH_MNT/tmpdir \
+ 2>&1 >>$seqres.full | \
+ egrep -q 'Inappropriate ioctl for device|Operation not supported'
+ then
+ _notrun "kernel does not support $FSTYP encryption"
+ fi
+ rmdir $SCRATCH_MNT/tmpdir
+ _scratch_unmount
+}
+
+_scratch_mkfs_encrypted()
+{
+ case $FSTYP in
+ ext4|f2fs)
+ _scratch_mkfs -O encrypt
+ ;;
+ *)
+ _notrun "No encryption support for $FSTYP"
+ ;;
+ esac
+}
+
+# Give the invoking shell a new session keyring. This makes any keys we add to
+# the session keyring scoped to the lifetime of the test script.
+_new_session_keyring()
+{
+ $KEYCTL_PROG new_session >>$seqres.full
+}
+
+#
+# Generate a random encryption key, add it to the session keyring, and print out
+# the resulting key descriptor (example: "8bf798e1a494e1ec"). Requires the
+# keyctl program. It's assumed the caller has already set up a test-scoped
+# session keyring using _new_session_keyring.
+#
+_generate_encryption_key()
+{
+ # Generate a key descriptor (16 character hex string)
+ local keydesc=""
+ for ((i = 0; i < 8; i++)); do
+ keydesc="${keydesc}$(printf "%02x" $(( $RANDOM % 256 )))"
+ done
+
+ # Generate the actual encryption key (64 bytes)
+ local raw=""
+ for ((i = 0; i < 64; i++)); do
+ raw="${raw}\\x$(printf "%02x" $(( $RANDOM % 256 )))"
+ done
+
+ #
+ # Add the key to the session keyring. The required structure is:
+ #
+ # #define FS_MAX_KEY_SIZE 64
+ # struct fscrypt_key {
+ # u32 mode;
+ # u8 raw[FS_MAX_KEY_SIZE];
+ # u32 size;
+ # } __packed;
+ #
+ # The kernel ignores 'mode' but requires that 'size' be 64.
+ #
+ # Keys are named $FSTYP:KEYDESC where KEYDESC is the 16-character key
+ # descriptor hex string. Newer kernels (ext4 4.8 and later, f2fs 4.6
+ # and later) also allow the common key prefix "fscrypt:" in addition to
+ # their filesystem-specific key prefix ("ext4:", "f2fs:"). It would be
+ # nice to use the common key prefix, but for now use the filesystem-
+ # specific prefix to make it possible to test older kernels...
+ #
+ local big_endian=$(echo -ne '\x11' | od -tx2 | head -1 | \
+ cut -f2 -d' ' | cut -c1 )
+ if (( big_endian )); then
+ local mode='\x00\x00\x00\x00'
+ local size='\x00\x00\x00\x40'
+ else
+ local mode='\x00\x00\x00\x00'
+ local size='\x40\x00\x00\x00'
+ fi
+ echo -n -e "${mode}${raw}${size}" |
+ $KEYCTL_PROG padd logon $FSTYP:$keydesc @s >>$seqres.full
+ echo $keydesc
+}
+
+# Unlink an encryption key from the session keyring, given its key descriptor.
+_unlink_encryption_key()
+{
+ local keydesc=$1
+ local keyid=$($KEYCTL_PROG search @s logon $FSTYP:$keydesc)
+ $KEYCTL_PROG unlink $keyid >>$seqres.full
+}
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 2/6] generic: test setting and getting encryption policies
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
2016-12-15 20:26 ` [PATCH v4 1/6] generic: add utilities for testing filesystem encryption Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-15 20:26 ` [PATCH v4 3/6] generic: test validation of encryption policy structure Eric Biggers
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Several kernel bugs were recently fixed regarding the constraints for
setting encryption policies. Add tests for these cases and a few more.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
tests/generic/400 | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/400.out | 43 ++++++++++++++++
tests/generic/group | 1 +
3 files changed, 179 insertions(+)
create mode 100755 tests/generic/400
create mode 100644 tests/generic/400.out
diff --git a/tests/generic/400 b/tests/generic/400
new file mode 100755
index 0000000..9dbc024
--- /dev/null
+++ b/tests/generic/400
@@ -0,0 +1,135 @@
+#! /bin/bash
+# FS QA Test generic/400
+#
+# Test setting and getting encryption policies.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/encrypt
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch_encryption
+_require_xfs_io_command "get_encpolicy"
+_require_xfs_io_command "set_encpolicy"
+_require_user
+
+_scratch_mkfs_encrypted &>> $seqres.full
+_scratch_mount
+
+check_no_policy()
+{
+ # When a file is unencrypted, FS_IOC_GET_ENCRYPTION_POLICY currently
+ # fails with ENOENT on ext4 but with ENODATA on f2fs. TODO: it's
+ # planned to consistently use ENODATA. For now this test accepts both.
+ $XFS_IO_PROG -c "get_encpolicy" $1 |&
+ sed -e 's/No such file or directory/No data available/'
+}
+
+# Should be able to set an encryption policy on an empty directory
+empty_dir=$SCRATCH_MNT/empty_dir
+echo -e "\n*** Setting encryption policy on empty directory ***"
+mkdir $empty_dir
+check_no_policy $empty_dir |& _filter_scratch
+$XFS_IO_PROG -c "set_encpolicy 0000111122223333" $empty_dir
+$XFS_IO_PROG -c "get_encpolicy" $empty_dir | _filter_scratch
+
+# Should be able to set the same policy again, but not a different one.
+# TODO: the error code for "already has a different policy" is planned to switch
+# from EINVAL to EEXIST. For now this test accepts both.
+echo -e "\n*** Setting encryption policy again ***"
+$XFS_IO_PROG -c "set_encpolicy 0000111122223333" $empty_dir
+$XFS_IO_PROG -c "get_encpolicy" $empty_dir | _filter_scratch
+$XFS_IO_PROG -c "set_encpolicy 4444555566667777" $empty_dir |& \
+ _filter_scratch | sed -e 's/Invalid argument/File exists/'
+$XFS_IO_PROG -c "get_encpolicy" $empty_dir | _filter_scratch
+
+# Should *not* be able to set an encryption policy on a nonempty directory
+nonempty_dir=$SCRATCH_MNT/nonempty_dir
+echo -e "\n*** Setting encryption policy on nonempty directory ***"
+mkdir $nonempty_dir
+touch $nonempty_dir/file
+$XFS_IO_PROG -c "set_encpolicy" $nonempty_dir |& _filter_scratch
+check_no_policy $nonempty_dir |& _filter_scratch
+
+# Should *not* be able to set an encryption policy on a nondirectory file, even
+# an empty one. Regression test for 002ced4be642: "fscrypto: only allow setting
+# encryption policy on directories".
+# TODO: the error code for "not a directory" is planned to switch from EINVAL to
+# ENOTDIR. For now this test accepts both.
+nondirectory=$SCRATCH_MNT/nondirectory
+echo -e "\n*** Setting encryption policy on nondirectory ***"
+touch $nondirectory
+$XFS_IO_PROG -c "set_encpolicy" $nondirectory |& \
+ _filter_scratch | sed -e 's/Invalid argument/Not a directory/'
+check_no_policy $nondirectory |& _filter_scratch
+
+# Should *not* be able to set an encryption policy on another user's directory.
+# Regression test for 163ae1c6ad62: "fscrypto: add authorization check for
+# setting encryption policy".
+unauthorized_dir=$SCRATCH_MNT/unauthorized_dir
+echo -e "\n*** Setting encryption policy on another user's directory ***"
+mkdir $unauthorized_dir
+su $qa_user -c "$XFS_IO_PROG -c \"set_encpolicy\" $unauthorized_dir" |& \
+ _filter_scratch
+check_no_policy $unauthorized_dir |& _filter_scratch
+
+# Should *not* be able to set an encryption policy on a directory on a
+# filesystem mounted readonly. Regression test for ba63f23d69a3: "fscrypto:
+# require write access to mount to set encryption policy". Test both a regular
+# readonly filesystem and a readonly bind mount of a read-write filesystem.
+echo -e "\n*** Setting encryption policy on readonly filesystem ***"
+mkdir $SCRATCH_MNT/ro_dir $SCRATCH_MNT/ro_bind_mnt
+_scratch_remount ro
+$XFS_IO_PROG -c "set_encpolicy" $SCRATCH_MNT/ro_dir |& _filter_scratch
+check_no_policy $SCRATCH_MNT/ro_dir |& _filter_scratch
+_scratch_remount rw
+mount --bind $SCRATCH_MNT $SCRATCH_MNT/ro_bind_mnt
+mount -o remount,ro,bind $SCRATCH_MNT/ro_bind_mnt
+$XFS_IO_PROG -c "set_encpolicy" $SCRATCH_MNT/ro_bind_mnt/ro_dir |& _filter_scratch
+check_no_policy $SCRATCH_MNT/ro_bind_mnt/ro_dir |& _filter_scratch
+umount $SCRATCH_MNT/ro_bind_mnt
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/400.out b/tests/generic/400.out
new file mode 100644
index 0000000..631c023
--- /dev/null
+++ b/tests/generic/400.out
@@ -0,0 +1,43 @@
+QA output created by 400
+
+*** Setting encryption policy on empty directory ***
+SCRATCH_MNT/empty_dir: failed to get encryption policy: No data available
+Encryption policy for SCRATCH_MNT/empty_dir:
+ Policy version: 0
+ Master key descriptor: 0000111122223333
+ Contents encryption mode: 1 (AES-256-XTS)
+ Filenames encryption mode: 4 (AES-256-CTS)
+ Flags: 0x02
+
+*** Setting encryption policy again ***
+Encryption policy for SCRATCH_MNT/empty_dir:
+ Policy version: 0
+ Master key descriptor: 0000111122223333
+ Contents encryption mode: 1 (AES-256-XTS)
+ Filenames encryption mode: 4 (AES-256-CTS)
+ Flags: 0x02
+SCRATCH_MNT/empty_dir: failed to set encryption policy: File exists
+Encryption policy for SCRATCH_MNT/empty_dir:
+ Policy version: 0
+ Master key descriptor: 0000111122223333
+ Contents encryption mode: 1 (AES-256-XTS)
+ Filenames encryption mode: 4 (AES-256-CTS)
+ Flags: 0x02
+
+*** Setting encryption policy on nonempty directory ***
+SCRATCH_MNT/nonempty_dir: failed to set encryption policy: Directory not empty
+SCRATCH_MNT/nonempty_dir: failed to get encryption policy: No data available
+
+*** Setting encryption policy on nondirectory ***
+SCRATCH_MNT/nondirectory: failed to set encryption policy: Not a directory
+SCRATCH_MNT/nondirectory: failed to get encryption policy: No data available
+
+*** Setting encryption policy on another user's directory ***
+SCRATCH_MNT/unauthorized_dir: failed to set encryption policy: Permission denied
+SCRATCH_MNT/unauthorized_dir: failed to get encryption policy: No data available
+
+*** Setting encryption policy on readonly filesystem ***
+SCRATCH_MNT/ro_dir: failed to set encryption policy: Read-only file system
+SCRATCH_MNT/ro_dir: failed to get encryption policy: No data available
+SCRATCH_MNT/ro_bind_mnt/ro_dir: failed to set encryption policy: Read-only file system
+SCRATCH_MNT/ro_bind_mnt/ro_dir: failed to get encryption policy: No data available
diff --git a/tests/generic/group b/tests/generic/group
index f4af986..e6619ca 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -396,3 +396,4 @@
391 auto quick rw
392 auto quick metadata
393 auto quick rw
+400 auto quick encrypt
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 3/6] generic: test validation of encryption policy structure
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
2016-12-15 20:26 ` [PATCH v4 1/6] generic: add utilities for testing filesystem encryption Eric Biggers
2016-12-15 20:26 ` [PATCH v4 2/6] generic: test setting and getting encryption policies Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-15 20:26 ` [PATCH v4 4/6] generic: test encrypted file access Eric Biggers
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Add an xfstest which verifies the kernel performs basic validation of
the encryption policy structure.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
tests/generic/401 | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/401.out | 18 +++++++++++
tests/generic/group | 1 +
3 files changed, 101 insertions(+)
create mode 100755 tests/generic/401
create mode 100644 tests/generic/401.out
diff --git a/tests/generic/401 b/tests/generic/401
new file mode 100755
index 0000000..1c9d964
--- /dev/null
+++ b/tests/generic/401
@@ -0,0 +1,82 @@
+#! /bin/bash
+# FS QA Test generic/401
+#
+# Test that FS_IOC_SET_ENCRYPTION_POLICY correctly validates the fscrypt_policy
+# structure that userspace passes to it.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/encrypt
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch_encryption
+_require_xfs_io_command "set_encpolicy"
+
+_scratch_mkfs_encrypted &>> $seqres.full
+_scratch_mount
+dir=$SCRATCH_MNT/dir
+mkdir $dir
+
+echo -e "\n*** Invalid contents encryption mode ***"
+$XFS_IO_PROG -c "set_encpolicy -c 0xFF" $dir |& _filter_scratch
+
+echo -e "\n*** Invalid filenames encryption mode ***"
+$XFS_IO_PROG -c "set_encpolicy -n 0xFF" $dir |& _filter_scratch
+
+echo -e "\n*** Invalid flags ***"
+$XFS_IO_PROG -c "set_encpolicy -f 0xFF" $dir |& _filter_scratch
+
+echo -e "\n*** Invalid policy version ***"
+$XFS_IO_PROG -c "set_encpolicy -v 0xFF" $dir |& _filter_scratch
+
+# Currently, the only supported combination of modes is AES-256-XTS for contents
+# and AES-256-CTS for filenames. Nothing else should be accepted.
+echo -e "\n*** Invalid combinations of modes ***"
+$XFS_IO_PROG -c "set_encpolicy -c AES-256-CTS -n AES-256-CTS" $dir |& _filter_scratch
+$XFS_IO_PROG -c "set_encpolicy -c AES-256-CTS -n AES-256-XTS" $dir |& _filter_scratch
+$XFS_IO_PROG -c "set_encpolicy -c AES-256-XTS -n AES-256-XTS" $dir |& _filter_scratch
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/401.out b/tests/generic/401.out
new file mode 100644
index 0000000..ea349cc
--- /dev/null
+++ b/tests/generic/401.out
@@ -0,0 +1,18 @@
+QA output created by 401
+
+*** Invalid contents encryption mode ***
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+
+*** Invalid filenames encryption mode ***
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+
+*** Invalid flags ***
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+
+*** Invalid policy version ***
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+
+*** Invalid combinations of modes ***
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
+SCRATCH_MNT/dir: failed to set encryption policy: Invalid argument
diff --git a/tests/generic/group b/tests/generic/group
index e6619ca..a455c29 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -397,3 +397,4 @@
392 auto quick metadata
393 auto quick rw
400 auto quick encrypt
+401 auto quick encrypt
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 4/6] generic: test encrypted file access
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
` (2 preceding siblings ...)
2016-12-15 20:26 ` [PATCH v4 3/6] generic: test validation of encryption policy structure Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-15 20:26 ` [PATCH v4 5/6] generic: test enforcement of one encryption policy per tree Eric Biggers
2016-12-15 20:26 ` [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption Eric Biggers
5 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Test accessing encrypted files and directories, both with and without
the encryption key.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
tests/generic/402 | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/402.out | 13 +++++
tests/generic/group | 1 +
3 files changed, 158 insertions(+)
create mode 100755 tests/generic/402
create mode 100644 tests/generic/402.out
diff --git a/tests/generic/402 b/tests/generic/402
new file mode 100755
index 0000000..8f37f9f
--- /dev/null
+++ b/tests/generic/402
@@ -0,0 +1,144 @@
+#! /bin/bash
+# FS QA Test generic/402
+#
+# Test accessing encrypted files and directories, both with and without the
+# encryption key. Access with the encryption key is more of a sanity check and
+# is not intended to fully test all the encrypted I/O paths; to do that you'd
+# need to run all the xfstests with encryption enabled. Access without the
+# encryption key, on the other hand, should result in some particular behaviors.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/encrypt
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch_encryption
+_require_xfs_io_command "set_encpolicy"
+_require_command "$KEYCTL_PROG" keyctl
+
+_new_session_keyring
+
+_scratch_mkfs_encrypted &>> $seqres.full
+_scratch_mount
+
+mkdir $SCRATCH_MNT/edir $SCRATCH_MNT/ref_dir
+keydesc=$(_generate_encryption_key)
+$XFS_IO_PROG -c "set_encpolicy $keydesc" $SCRATCH_MNT/edir
+for dir in $SCRATCH_MNT/edir $SCRATCH_MNT/ref_dir; do
+ touch $dir/empty > /dev/null
+ $XFS_IO_PROG -t -f -c "pwrite 0 4k" $dir/a > /dev/null
+ $XFS_IO_PROG -t -f -c "pwrite 0 33k" $dir/abcdefghijklmnopqrstuvwxyz > /dev/null
+ maxname=$(yes | head -255 | tr -d '\n') # 255 character filename
+ $XFS_IO_PROG -t -f -c "pwrite 0 1k" $dir/$maxname > /dev/null
+ ln -s a $dir/symlink
+ ln -s abcdefghijklmnopqrstuvwxyz $dir/symlink2
+ ln -s $maxname $dir/symlink3
+ mkdir $dir/subdir
+ mkdir $dir/subdir/subsubdir
+done
+# Diff encrypted directory with unencrypted reference directory
+diff -r $SCRATCH_MNT/edir $SCRATCH_MNT/ref_dir
+# Cycle mount and diff again
+_scratch_cycle_mount
+diff -r $SCRATCH_MNT/edir $SCRATCH_MNT/ref_dir
+
+#
+# Now try accessing the files without the encryption key. It should still be
+# possible to list the directory and remove files. But filenames should be
+# encrypted, and it should not be possible to read regular files or to create
+# new files or subdirectories.
+#
+# Note that we cannot simply use ls -R to verify the files because the encrypted
+# filenames are unpredictable. By design, the key used to encrypt a directory's
+# filenames is derived from the master key (the key in the keyring) and a nonce
+# generated by the kernel. Hence, the encrypted filenames will be different
+# every time this test is run, even if we were to put a fixed key into the
+# keyring instead of a random one. The same applies to symlink targets.
+#
+# TODO: there are some inconsistencies in which error codes are returned on
+# different kernel versions and filesystems when trying to create a file or
+# subdirectory without access to the parent directory's encryption key. It's
+# planned to consistently use ENOKEY, but for now make this test accept multiple
+# error codes...
+#
+
+filter_create_errors()
+{
+ sed -e 's/No such file or directory/Required key not available/' \
+ -e 's/Permission denied/Required key not available/' \
+ -e 's/Operation not permitted/Required key not available/'
+}
+
+_unlink_encryption_key $keydesc
+_scratch_cycle_mount
+
+# Check that unencrypted names aren't there
+stat $SCRATCH_MNT/edir/empty |& _filter_scratch
+stat $SCRATCH_MNT/edir/symlink |& _filter_scratch
+
+# Check that the correct numbers of files and subdirectories are there
+ls $SCRATCH_MNT/edir | wc -l
+find $SCRATCH_MNT/edir -mindepth 2 -maxdepth 2 -type d | wc -l
+
+# Try to read a nondirectory file (should fail with ENOKEY)
+md5sum $(find $SCRATCH_MNT/edir -maxdepth 1 -type f | head -1) |& \
+ cut -d ' ' -f3-
+
+# Try to create new files, directories, and symlinks in the encrypted directory,
+# both with and without using correctly base-64 encoded filenames. These should
+# all fail with ENOKEY.
+$XFS_IO_PROG -f $SCRATCH_MNT/edir/newfile |& filter_create_errors | _filter_scratch
+$XFS_IO_PROG -f $SCRATCH_MNT/edir/0123456789abcdef |& filter_create_errors | _filter_scratch
+mkdir $SCRATCH_MNT/edir/newdir |& filter_create_errors | _filter_scratch
+mkdir $SCRATCH_MNT/edir/0123456789abcdef |& filter_create_errors | _filter_scratch
+ln -s foo $SCRATCH_MNT/edir/newlink |& filter_create_errors | _filter_scratch
+ln -s foo $SCRATCH_MNT/edir/0123456789abcdef |& filter_create_errors | _filter_scratch
+
+# Delete the encrypted directory (should succeed)
+rm -r $SCRATCH_MNT/edir
+stat $SCRATCH_MNT/edir |& _filter_scratch
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/402.out b/tests/generic/402.out
new file mode 100644
index 0000000..8573474
--- /dev/null
+++ b/tests/generic/402.out
@@ -0,0 +1,13 @@
+QA output created by 402
+stat: cannot stat 'SCRATCH_MNT/edir/empty': No such file or directory
+stat: cannot stat 'SCRATCH_MNT/edir/symlink': No such file or directory
+8
+1
+Required key not available
+SCRATCH_MNT/edir/newfile: Required key not available
+SCRATCH_MNT/edir/0123456789abcdef: Required key not available
+mkdir: cannot create directory 'SCRATCH_MNT/edir/newdir': Required key not available
+mkdir: cannot create directory 'SCRATCH_MNT/edir/0123456789abcdef': Required key not available
+ln: failed to create symbolic link 'SCRATCH_MNT/edir/newlink': Required key not available
+ln: failed to create symbolic link 'SCRATCH_MNT/edir/0123456789abcdef': Required key not available
+stat: cannot stat 'SCRATCH_MNT/edir': No such file or directory
diff --git a/tests/generic/group b/tests/generic/group
index a455c29..e218380 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -398,3 +398,4 @@
393 auto quick rw
400 auto quick encrypt
401 auto quick encrypt
+402 auto quick encrypt
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 5/6] generic: test enforcement of one encryption policy per tree
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
` (3 preceding siblings ...)
2016-12-15 20:26 ` [PATCH v4 4/6] generic: test encrypted file access Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-15 20:26 ` [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption Eric Biggers
5 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Add an xfstest which verifies that the filesystem forbids operations
that would violate the constraint that all files in an encrypted
directory tree use the same encryption policy.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
tests/generic/403 | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/403.out | 45 ++++++++++++++
tests/generic/group | 1 +
3 files changed, 204 insertions(+)
create mode 100644 tests/generic/403
create mode 100644 tests/generic/403.out
diff --git a/tests/generic/403 b/tests/generic/403
new file mode 100644
index 0000000..0e06cc5
--- /dev/null
+++ b/tests/generic/403
@@ -0,0 +1,158 @@
+#! /bin/bash
+# FS QA Test generic/403
+#
+# Filesystem encryption is designed to enforce that a consistent encryption
+# policy is used within a given encrypted directory tree and that an encrypted
+# directory tree does not contain any unencrypted files. This test verifies
+# that filesystem operations that would violate this constraint fail with EPERM.
+# This does not test enforcement of this constraint on lookup, which is still
+# needed to detect offline changes.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/encrypt
+. ./common/renameat2
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch_encryption
+_require_xfs_io_command "set_encpolicy"
+_requires_renameat2
+
+_new_session_keyring
+_scratch_mkfs_encrypted &>> $seqres.full
+_scratch_mount
+
+# Set up two encrypted directories, with different encryption policies,
+# and one unencrypted directory.
+edir1=$SCRATCH_MNT/edir1
+edir2=$SCRATCH_MNT/edir2
+udir=$SCRATCH_MNT/udir
+mkdir $edir1 $edir2 $udir
+keydesc1=$(_generate_encryption_key)
+keydesc2=$(_generate_encryption_key)
+$XFS_IO_PROG -c "set_encpolicy $keydesc1" $edir1
+$XFS_IO_PROG -c "set_encpolicy $keydesc2" $edir2
+touch $edir1/efile1
+touch $edir2/efile2
+touch $udir/ufile
+
+
+# Test linking and moving an encrypted file into an encrypted directory with a
+# different encryption policy. Should fail with EPERM.
+
+echo -e "\n*** Link encrypted <= encrypted ***"
+ln $edir1/efile1 $edir2/efile1 |& _filter_scratch
+
+echo -e "\n*** Rename encrypted => encrypted ***"
+mv $edir1/efile1 $edir2/efile1 |& _filter_scratch
+
+
+# Test linking and moving an unencrypted file into an encrypted directory.
+# Should fail with EPERM.
+
+echo -e "\n\n*** Link unencrypted <= encrypted ***"
+ln $udir/ufile $edir1/ufile |& _filter_scratch
+
+echo -e "\n*** Rename unencrypted => encrypted ***"
+mv $udir/ufile $edir1/ufile |& _filter_scratch
+
+
+# Test linking and moving an encrypted file into an unencrypted directory.
+# Should succeed.
+
+echo -e "\n\n*** Link encrypted <= unencrypted ***"
+ln -v $edir1/efile1 $udir/efile1 |& _filter_scratch
+rm $udir/efile1 # undo
+
+echo -e "\n*** Rename encrypted => unencrypted ***"
+mv -v $edir1/efile1 $udir/efile1 |& _filter_scratch
+mv $udir/efile1 $edir1/efile1 # undo
+
+
+# Test moving a forbidden (unencrypted, or encrypted with a different encryption
+# policy) file into an encrypted directory via an exchange (cross rename)
+# operation. Should fail with EPERM.
+
+echo -e "\n\n*** Exchange encrypted <=> encrypted ***"
+src/renameat2 -x $edir1/efile1 $edir2/efile2 |& _filter_scratch
+
+echo -e "\n*** Exchange unencrypted <=> encrypted ***"
+src/renameat2 -x $udir/ufile $edir1/efile1 |& _filter_scratch
+
+echo -e "\n*** Exchange encrypted <=> unencrypted ***"
+src/renameat2 -x $edir1/efile1 $udir/ufile |& _filter_scratch
+
+
+# Test a file with a special type, i.e. not regular, directory, or symlink.
+# Since such files are not subject to encryption, there should be no
+# restrictions on linking or moving them into encrypted directories.
+
+echo -e "\n\n*** Special file tests ***"
+mkfifo $edir1/fifo
+mv -v $edir1/fifo $edir2/fifo | _filter_scratch
+mv -v $edir2/fifo $udir/fifo | _filter_scratch
+mv -v $udir/fifo $edir1/fifo | _filter_scratch
+mkfifo $udir/fifo
+src/renameat2 -x $udir/fifo $edir1/fifo
+ln -v $edir1/fifo $edir2/fifo | _filter_scratch
+rm $edir1/fifo $edir2/fifo $udir/fifo
+
+
+# Now test that *without* access to the encrypted key, we cannot use an exchange
+# (cross rename) operation to move a forbidden file into an encrypted directory.
+
+_unlink_encryption_key $keydesc1
+_unlink_encryption_key $keydesc2
+_scratch_cycle_mount
+efile1=$(find $edir1 -type f)
+efile2=$(find $edir2 -type f)
+
+echo -e "\n\n*** Exchange encrypted <=> encrypted without key ***"
+src/renameat2 -x $efile1 $efile2
+echo -e "\n*** Exchange encrypted <=> unencrypted without key ***"
+src/renameat2 -x $efile1 $udir/ufile
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/403.out b/tests/generic/403.out
new file mode 100644
index 0000000..22d3255
--- /dev/null
+++ b/tests/generic/403.out
@@ -0,0 +1,45 @@
+QA output created by 403
+
+*** Link encrypted <= encrypted ***
+ln: failed to create hard link 'SCRATCH_MNT/edir2/efile1' => 'SCRATCH_MNT/edir1/efile1': Operation not permitted
+
+*** Rename encrypted => encrypted ***
+mv: cannot move 'SCRATCH_MNT/edir1/efile1' to 'SCRATCH_MNT/edir2/efile1': Operation not permitted
+
+
+*** Link unencrypted <= encrypted ***
+ln: failed to create hard link 'SCRATCH_MNT/edir1/ufile' => 'SCRATCH_MNT/udir/ufile': Operation not permitted
+
+*** Rename unencrypted => encrypted ***
+mv: cannot move 'SCRATCH_MNT/udir/ufile' to 'SCRATCH_MNT/edir1/ufile': Operation not permitted
+
+
+*** Link encrypted <= unencrypted ***
+'SCRATCH_MNT/udir/efile1' => 'SCRATCH_MNT/edir1/efile1'
+
+*** Rename encrypted => unencrypted ***
+'SCRATCH_MNT/edir1/efile1' -> 'SCRATCH_MNT/udir/efile1'
+
+
+*** Exchange encrypted <=> encrypted ***
+Operation not permitted
+
+*** Exchange unencrypted <=> encrypted ***
+Operation not permitted
+
+*** Exchange encrypted <=> unencrypted ***
+Operation not permitted
+
+
+*** Special file tests ***
+'SCRATCH_MNT/edir1/fifo' -> 'SCRATCH_MNT/edir2/fifo'
+'SCRATCH_MNT/edir2/fifo' -> 'SCRATCH_MNT/udir/fifo'
+'SCRATCH_MNT/udir/fifo' -> 'SCRATCH_MNT/edir1/fifo'
+'SCRATCH_MNT/edir2/fifo' => 'SCRATCH_MNT/edir1/fifo'
+
+
+*** Exchange encrypted <=> encrypted without key ***
+Operation not permitted
+
+*** Exchange encrypted <=> unencrypted without key ***
+Operation not permitted
diff --git a/tests/generic/group b/tests/generic/group
index e218380..a0d6e84 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -399,3 +399,4 @@
400 auto quick encrypt
401 auto quick encrypt
402 auto quick encrypt
+403 auto quick encrypt
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption
2016-12-15 20:26 [PATCH v4 0/6] Add filesystem-level encryption tests Eric Biggers
` (4 preceding siblings ...)
2016-12-15 20:26 ` [PATCH v4 5/6] generic: test enforcement of one encryption policy per tree Eric Biggers
@ 2016-12-15 20:26 ` Eric Biggers
2016-12-19 7:26 ` Eryu Guan
5 siblings, 1 reply; 9+ messages in thread
From: Eric Biggers @ 2016-12-15 20:26 UTC (permalink / raw)
To: fstests
Cc: Theodore Ts'o, Jaegeuk Kim, Richard Weinberger, David Gstir,
Michael Halcrow, Eric Sandeen, Eric Biggers
From: Eric Biggers <ebiggers@google.com>
Add an xfstest which can detect some basic crypto mistakes that would
reduce the confidentiality guarantee provided by filesystem encryption.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
common/config | 1 +
tests/generic/404 | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/404.out | 3 +
tests/generic/group | 1 +
4 files changed, 167 insertions(+)
create mode 100755 tests/generic/404
create mode 100644 tests/generic/404.out
diff --git a/common/config b/common/config
index 3727ec0..6cce7ce 100644
--- a/common/config
+++ b/common/config
@@ -203,6 +203,7 @@ export UUIDGEN_PROG="`set_prog_path uuidgen`"
export GETRICHACL_PROG="`set_prog_path getrichacl`"
export SETRICHACL_PROG="`set_prog_path setrichacl`"
export KEYCTL_PROG="`set_prog_path keyctl`"
+export XZ_PROG="`set_prog_path xz`"
# use 'udevadm settle' or 'udevsettle' to wait for lv to be settled.
# newer systems have udevadm command but older systems like RHEL5 don't.
diff --git a/tests/generic/404 b/tests/generic/404
new file mode 100755
index 0000000..3d96f8f
--- /dev/null
+++ b/tests/generic/404
@@ -0,0 +1,162 @@
+#! /bin/bash
+# FS QA Test generic/404
+#
+# Check for weaknesses in filesystem encryption involving the same ciphertext
+# being repeated. For file contents, we fill a small filesystem with large
+# files of 0's and verify the filesystem is incompressible. For filenames, we
+# create an identical symlink in two different directories and verify the
+# ciphertext filenames and symlink targets are different.
+#
+# This test can detect some basic cryptographic mistakes such as nonce reuse
+# (across files), initialization vector reuse (across blocks), or data somehow
+# being left in plaintext by accident. For example, it detects the
+# initialization vector reuse bug fixed in commit 02fc59a0d28f ("f2fs/crypto:
+# fix xts_tweak initialization").
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016 Google, Inc. All Rights Reserved.
+#
+# Author: Eric Biggers <ebiggers@google.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/encrypt
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch_encryption
+_require_xfs_io_command "set_encpolicy"
+_require_command "$XZ_PROG" xz
+_require_command "$KEYCTL_PROG" keyctl
+
+_new_session_keyring
+
+# Set up a small filesystem containing an encrypted directory. 64 MB is enough
+# for both ext4 and f2fs. (f2fs doesn't support a 32 MB filesystem.)
+fs_size_in_mb=64
+fs_size=$((fs_size_in_mb * 1024 * 1024))
+dd if=/dev/zero of=$SCRATCH_DEV bs=$((1024 * 1024)) \
+ count=$fs_size_in_mb &>> $seqres.full
+MKFS_OPTIONS="$MKFS_OPTIONS -O encrypt" \
+ _scratch_mkfs_sized $fs_size &>> $seqres.full
+_scratch_mount
+
+keydesc=$(_generate_encryption_key)
+mkdir $SCRATCH_MNT/encrypted_dir
+$XFS_IO_PROG -c "set_encpolicy $keydesc" $SCRATCH_MNT/encrypted_dir
+
+# Create the "same" symlink in two different directories.
+# Later we'll check both the name and target of the symlink.
+mkdir $SCRATCH_MNT/encrypted_dir/subdir1
+mkdir $SCRATCH_MNT/encrypted_dir/subdir2
+ln -s symlink_target $SCRATCH_MNT/encrypted_dir/subdir1/symlink
+ln -s symlink_target $SCRATCH_MNT/encrypted_dir/subdir2/symlink
+
+#
+# Write files of 1 MB of all the same byte until we hit ENOSPC. Note that we
+# must not create sparse files, since the contents of sparse files are not
+# stored on-disk. Also, we create multiple files rather than one big file
+# because we want to test for reuse of per-file keys.
+#
+total_file_size=0
+i=1
+while true; do
+ file=$SCRATCH_MNT/encrypted_dir/file$i
+ if ! xfs_io -f $file -c 'pwrite 0 1M' &> $tmp.out; then
+ if ! grep -q 'No space left on device' $tmp.out; then
+ echo "FAIL: unexpected pwrite failure"
+ cat $tmp.out
+ elif [ -e $file ]; then
+ total_file_size=$((total_file_size + $(stat -c %s $file)))
+ fi
+ break
+ fi
+ total_file_size=$((total_file_size + $(stat -c %s $file)))
+ i=$((i + 1))
+ if [ $i -gt $fs_size_in_mb ]; then
+ echo "FAIL: filesystem never filled up!"
+ break
+ fi
+done
+
+# We shouldn't have been able to write more data than we had space for.
+if (( $total_file_size > $fs_size )); then
+ echo "FAIL: wrote $total_file_size bytes but should have only" \
+ "had space for $fs_size bytes at most"
+fi
+
+#
+# Unmount the filesystem and compute its compressed size. It must be no smaller
+# than the amount of data that was written; otherwise there was a compromise in
+# the confidentiality of the data. False positives should not be possible
+# because filesystem metadata will also contribute to the compressed size.
+#
+# Note: it's important to use a strong compressor such as xz which can detect
+# redundancy across most or all of the filesystem. We run xz with a 64 MB
+# sliding window but use some custom settings to make it faster and use less
+# memory than the '-9' preset. The memory needed with our settings will be
+# 64 * 6.5 = 416 MB; see xz(1).
+#
+_unlink_encryption_key $keydesc
+_scratch_unmount
+fs_compressed_size=$(head -c $fs_size $SCRATCH_DEV | \
+ xz --lzma2=dict=64M,mf=hc4,mode=fast,nice=16 | \
+ wc -c)
+
+if (( $fs_compressed_size < $total_file_size )); then
+ echo "FAIL: filesystem was compressible" \
+ "($total_file_size bytes => $fs_compressed_size bytes)"
+else
+ echo "PASS: ciphertexts were not repeated for contents"
+fi
+
+# Verify that encrypted filenames and symlink targets were not reused. Note
+# that since the ciphertexts should be unpredictable, we cannot simply include
+# the expected names in the expected output file.
+_scratch_mount
+find $SCRATCH_MNT/encrypted_dir -type l | wc -l
+link1=$(find $SCRATCH_MNT/encrypted_dir -type l | head -1)
+link2=$(find $SCRATCH_MNT/encrypted_dir -type l | tail -1)
+[ $(basename $link1) = $(basename $link2) ] && \
+ echo "Encrypted filenames were reused!"
+[ $(readlink $link1) = $(readlink $link2) ] && \
+ echo "Encrypted symlink targets were reused!"
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/404.out b/tests/generic/404.out
new file mode 100644
index 0000000..220edb4
--- /dev/null
+++ b/tests/generic/404.out
@@ -0,0 +1,3 @@
+QA output created by 404
+PASS: ciphertexts were not repeated for contents
+2
diff --git a/tests/generic/group b/tests/generic/group
index a0d6e84..d310654 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -400,3 +400,4 @@
401 auto quick encrypt
402 auto quick encrypt
403 auto quick encrypt
+404 auto encrypt
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption
2016-12-15 20:26 ` [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption Eric Biggers
@ 2016-12-19 7:26 ` Eryu Guan
2016-12-21 21:36 ` Eric Biggers
0 siblings, 1 reply; 9+ messages in thread
From: Eryu Guan @ 2016-12-19 7:26 UTC (permalink / raw)
To: Eric Biggers
Cc: fstests, Theodore Ts'o, Jaegeuk Kim, Richard Weinberger,
David Gstir, Michael Halcrow, Eric Sandeen, Eric Biggers
On Thu, Dec 15, 2016 at 12:26:25PM -0800, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
>
> Add an xfstest which can detect some basic crypto mistakes that would
> reduce the confidentiality guarantee provided by filesystem encryption.
>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> ---
> common/config | 1 +
> tests/generic/404 | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++
> tests/generic/404.out | 3 +
> tests/generic/group | 1 +
> 4 files changed, 167 insertions(+)
> create mode 100755 tests/generic/404
> create mode 100644 tests/generic/404.out
>
> diff --git a/common/config b/common/config
> index 3727ec0..6cce7ce 100644
> --- a/common/config
> +++ b/common/config
> @@ -203,6 +203,7 @@ export UUIDGEN_PROG="`set_prog_path uuidgen`"
> export GETRICHACL_PROG="`set_prog_path getrichacl`"
> export SETRICHACL_PROG="`set_prog_path setrichacl`"
> export KEYCTL_PROG="`set_prog_path keyctl`"
> +export XZ_PROG="`set_prog_path xz`"
>
> # use 'udevadm settle' or 'udevsettle' to wait for lv to be settled.
> # newer systems have udevadm command but older systems like RHEL5 don't.
> diff --git a/tests/generic/404 b/tests/generic/404
> new file mode 100755
> index 0000000..3d96f8f
> --- /dev/null
> +++ b/tests/generic/404
> @@ -0,0 +1,162 @@
> +#! /bin/bash
> +# FS QA Test generic/404
> +#
> +# Check for weaknesses in filesystem encryption involving the same ciphertext
> +# being repeated. For file contents, we fill a small filesystem with large
> +# files of 0's and verify the filesystem is incompressible. For filenames, we
> +# create an identical symlink in two different directories and verify the
> +# ciphertext filenames and symlink targets are different.
> +#
> +# This test can detect some basic cryptographic mistakes such as nonce reuse
> +# (across files), initialization vector reuse (across blocks), or data somehow
> +# being left in plaintext by accident. For example, it detects the
> +# initialization vector reuse bug fixed in commit 02fc59a0d28f ("f2fs/crypto:
> +# fix xts_tweak initialization").
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2016 Google, Inc. All Rights Reserved.
> +#
> +# Author: Eric Biggers <ebiggers@google.com>
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> +#-----------------------------------------------------------------------
> +#
> +
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1 # failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> + cd /
> + rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/encrypt
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +_supported_fs generic
> +_supported_os Linux
> +_require_scratch_encryption
> +_require_xfs_io_command "set_encpolicy"
> +_require_command "$XZ_PROG" xz
> +_require_command "$KEYCTL_PROG" keyctl
> +
> +_new_session_keyring
> +
> +# Set up a small filesystem containing an encrypted directory. 64 MB is enough
> +# for both ext4 and f2fs. (f2fs doesn't support a 32 MB filesystem.)
> +fs_size_in_mb=64
> +fs_size=$((fs_size_in_mb * 1024 * 1024))
> +dd if=/dev/zero of=$SCRATCH_DEV bs=$((1024 * 1024)) \
> + count=$fs_size_in_mb &>> $seqres.full
Why is zeroing out the first 64M of SCRATCH_DEV necessary? Better to
have some comments on it.
> +MKFS_OPTIONS="$MKFS_OPTIONS -O encrypt" \
> + _scratch_mkfs_sized $fs_size &>> $seqres.full
> +_scratch_mount
> +
> +keydesc=$(_generate_encryption_key)
> +mkdir $SCRATCH_MNT/encrypted_dir
> +$XFS_IO_PROG -c "set_encpolicy $keydesc" $SCRATCH_MNT/encrypted_dir
> +
> +# Create the "same" symlink in two different directories.
> +# Later we'll check both the name and target of the symlink.
> +mkdir $SCRATCH_MNT/encrypted_dir/subdir1
> +mkdir $SCRATCH_MNT/encrypted_dir/subdir2
> +ln -s symlink_target $SCRATCH_MNT/encrypted_dir/subdir1/symlink
> +ln -s symlink_target $SCRATCH_MNT/encrypted_dir/subdir2/symlink
> +
> +#
> +# Write files of 1 MB of all the same byte until we hit ENOSPC. Note that we
> +# must not create sparse files, since the contents of sparse files are not
> +# stored on-disk. Also, we create multiple files rather than one big file
> +# because we want to test for reuse of per-file keys.
> +#
> +total_file_size=0
> +i=1
> +while true; do
> + file=$SCRATCH_MNT/encrypted_dir/file$i
> + if ! xfs_io -f $file -c 'pwrite 0 1M' &> $tmp.out; then
Use $XFS_IO_PROG here.
Can you please send an updated patch 6/6? Otherwise the whole series
look good to me! I'm going to let the patchset sit in the list for
another week and push them out to upstream in next fstests update, if
there's no further comments from others.
Thanks,
Eryu
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v4 6/6] generic: test for weaknesses in filesystem encryption
2016-12-19 7:26 ` Eryu Guan
@ 2016-12-21 21:36 ` Eric Biggers
0 siblings, 0 replies; 9+ messages in thread
From: Eric Biggers @ 2016-12-21 21:36 UTC (permalink / raw)
To: Eryu Guan
Cc: fstests, Theodore Ts'o, Jaegeuk Kim, Richard Weinberger,
David Gstir, Michael Halcrow, Eric Sandeen, Eric Biggers,
linux-xfs
On Mon, Dec 19, 2016 at 03:26:28PM +0800, Eryu Guan wrote:
>
> Can you please send an updated patch 6/6? Otherwise the whole series
> look good to me! I'm going to let the patchset sit in the list for
> another week and push them out to upstream in next fstests update, if
> there's no further comments from others.
>
> Thanks,
> Eryu
I just changed patch 6/6 but I went ahead and sent out v5 of the series so that
people don't mix up the different patches.
+Cc linux-xfs@vger.kernel.org
Also, would it be possible to get the xfs_io patch merged into xfsprogs at about
the same time? Ultimately, both the xfstests and xfsprogs changes are needed to
run the new tests; without the xfsprogs change they'll all be skipped.
Thanks,
Eric
^ permalink raw reply [flat|nested] 9+ messages in thread