Files
apfstests/common/encrypt
T
David Oberhollenzer cc34c5f81f fstests: Add support for UBIFS
UBIFS is a filesystem for unmanaged flash memory devices. It works
on top of UBI (Unsorted Block Images) which is a wear leveling and
volume management layer on top of flash memory devices, which are
handled by the MTD subsystem (memory technology device).

Since the semantics of flash devices are drastically different from
regular block devices (blocks or "pages" must be erased before
writing, only larger groups of pages or "erase blocks" can be erased
at once, page write must be in order within an erase block, etc...)
it was decided to expose MTD devices as character devices with
ioctls for operations like erase.

Since erasing a flash erase block causes physical wear on the
device, eventually causing the erase blocks to go bad, the UBI layer
provides mainly transparent wear leveling on top of MTD devices. UBI
does not attempt to emulate a regular block device, but rather
something like a flash memory with idealized characteristics that
can be partitioned into multiple UBI volumes in a fashion somewhat
similar to LVM. UBI volumes are also exposed to user space as
character devices.

This patch mainly deals with some quirks of UBIFS like working on
top of character devices instead of block devices. Also UBIFS
automatically formats UBI devices when trying to mount an empty
device. The mkfs.ubifs program is mainly used for creating images.
This patch changes _scratch_mkfs and _scratch_mkfs_encrypted to
truncate the UBI volume instead, relying on the kernel to reformat
it on the next mount.

For _scratch_mkfs_encrypted this is actually required to get the
encryption tests to run, because mkfs.ubifs, at the time of writing
this, the kernel support for UBIFS encryption is fairly recent and
mkfs.ubifs does not have proper support yet.

The necessity of an additional -ubifs switch was discussed but auto
detection of UBIFS formated UBI devices could not be reproduced on
my end and is unlikely to work with empty UBI volumes anyway.

Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Reviewed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Eryu Guan <eguan@redhat.com>
2017-06-08 10:53:27 +08:00

183 lines
5.7 KiB
Plaintext

#-----------------------------------------------------------------------
#
# 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
;;
ubifs)
# erase the UBI volume; reformated automatically on next mount
$UBIUPDATEVOL_PROG ${SCRATCH_DEV} -t
;;
*)
_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 key descriptor (16 character hex string)
_generate_key_descriptor()
{
local keydesc=""
local i
for ((i = 0; i < 8; i++)); do
keydesc="${keydesc}$(printf "%02x" $(( $RANDOM % 256 )))"
done
echo $keydesc
}
# Generate a raw encryption key, but don't add it to the keyring yet.
_generate_raw_encryption_key()
{
local raw=""
local i
for ((i = 0; i < 64; i++)); do
raw="${raw}\\x$(printf "%02x" $(( $RANDOM % 256 )))"
done
echo $raw
}
# Add the specified raw encryption key to the session keyring, using the
# specified key descriptor.
_add_encryption_key()
{
local keydesc=$1
local raw=$2
#
# 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
}
#
# 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()
{
local keydesc=$(_generate_key_descriptor)
local raw=$(_generate_raw_encryption_key)
_add_encryption_key $keydesc $raw
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
}
# Revoke an encryption key from the keyring, given its key descriptor.
_revoke_encryption_key()
{
local keydesc=$1
local keyid=$($KEYCTL_PROG search @s logon $FSTYP:$keydesc)
$KEYCTL_PROG revoke $keyid >>$seqres.full
}