1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2016 Google, Inc. All Rights Reserved.
#
# FS QA Test generic/399
#
# 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").
#
. ./common/preamble
_begin_fstest auto encrypt
# Import common functions.
. ./common/filter
. ./common/encrypt
# real QA test starts here
_supported_fs generic
_require_scratch_encryption
_require_symlinks
_require_command "$XZ_PROG" xz
_require_command "$KEYCTL_PROG" keyctl
_init_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). Before
# creating the filesystem, zero out the needed portion of the device so that
# existing data on the device doesn't contribute to the compressed size.
#
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
_scratch_mkfs_sized_encrypted $fs_size &>> $seqres.full
_scratch_mount
keydesc=$(_generate_session_encryption_key)
mkdir $SCRATCH_MNT/encrypted_dir
_set_encpolicy $SCRATCH_MNT/encrypted_dir $keydesc
# 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
$XFS_IO_PROG -f $file -c 'pwrite 0 1M' &> $tmp.out
echo "Writing $file..." >> $seqres.full
cat $tmp.out >> $seqres.full
file_size=0
if [ -e $file ]; then
file_size=$(_get_filesize $file)
fi
# We shouldn't have been able to write more data than we had space for.
(( total_file_size += file_size ))
if (( total_file_size > fs_size )); then
_fail "Wrote $total_file_size bytes but should have only" \
"had space for $fs_size bytes at most!"
fi
# Stop if we hit ENOSPC.
if grep -q 'No space left on device' $tmp.out; then
break
fi
# Otherwise the file should have been successfully created.
if [ ! -e $file ]; then
_fail "$file failed to be created, but the fs isn't out of space yet!"
fi
if (( file_size != 1024 * 1024 )); then
_fail "Size of $file is wrong (possible write error?)." \
"Got $file_size, expected 1 MiB"
fi
(( i++ ))
done
#
# 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_session_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
|