From 0185defb7f2e2a76b2ec5fb77cec2f1aeb412682 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 13 Dec 2016 13:52:05 +0100 Subject: [PATCH] Check for data device and hash device area overlap in veritysetup. Thanks Michal Virgovic for tests. --- lib/internal.h | 1 + lib/setup.c | 6 ++++++ lib/utils_device.c | 15 +++++++++++++++ tests/verity-compat-test | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/lib/internal.h b/lib/internal.h index 521398a9..ada1c5c6 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -76,6 +76,7 @@ int device_read_ahead(struct device *device, uint32_t *read_ahead); int device_size(struct device *device, uint64_t *size); int device_open(struct device *device, int flags); void device_disable_direct_io(struct device *device); +int device_is_identical(struct device *device1, struct device *device2); enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 }; diff --git a/lib/setup.c b/lib/setup.c index 4b303601..84da6181 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -1188,6 +1188,12 @@ static int _crypt_format_verity(struct crypt_device *cd, } else cd->u.verity.hdr.data_size = params->data_size; + if (device_is_identical(crypt_metadata_device(cd), crypt_data_device(cd)) && + (cd->u.verity.hdr.data_size * params->data_block_size) > params->hash_area_offset) { + log_err(cd, _("Data area overlaps with hash area.\n")); + return -EINVAL; + } + hash_size = crypt_hash_size(params->hash_name); if (hash_size <= 0) { log_err(cd, _("Hash algorithm %s not supported.\n"), diff --git a/lib/utils_device.c b/lib/utils_device.c index 8c4d4349..b3ea8ac3 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -535,3 +535,18 @@ void device_disable_direct_io(struct device *device) { device->o_direct = 0; } + +int device_is_identical(struct device *device1, struct device *device2) +{ + if (device1 == device2) + return 1; + + if (!device1 || !device2 || !device_path(device1) || !device_path(device2)) + return 0; + + /* This should be better check - major/minor for block device etc */ + if (!strcmp(device_path(device1), device_path(device2))) + return 1; + + return 0; +} diff --git a/tests/verity-compat-test b/tests/verity-compat-test index cb90edaf..a6264f6d 100755 --- a/tests/verity-compat-test +++ b/tests/verity-compat-test @@ -171,6 +171,31 @@ function valgrind_run() INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${VERITYSETUP} "$@" } +function checkOffsetBug() # $1 size, $2 hash-offset, $3 data-blocks +{ + echo -n "Size :: $1 B | Hash-offset :: $2 blocks | Data-blocks :: $3 " + dd if=/dev/zero of=$IMG bs=1 count=0 seek=$1 >/dev/null 2>&1 + $VERITYSETUP --data-blocks=$3 --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1 || fail "Test [hash-offset greater than 2G] failed" + echo "[OK]" + remove_mapping +} +function checkOverlapBug() # $1 size, $2 hash-offset, $3 data-blocks +{ + echo -n "Size :: $1 B | Hash-offset :: $2 blocks | " + + dd if=/dev/zero of=$IMG bs=1 count=0 seek=$1 >/dev/null 2>&1 + if [ -z $3 ] ; then + # veritysetup must fail + $VERITYSETUP --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1 && fail "Test [overlap with option \"--data-blocks\" not entered] failed" + else + $VERITYSETUP --data-blocks=$3 --hash-offset=$2 format $IMG $IMG >/dev/null 2>&1 || fail "Test [overlap with option \"--data-blocks\" entered] failed" + RET=$? + [ "$3" -gt "$(($2 / 4096))" ] && [ "$RET" -eq "0" ] && fail "Test [overlap - hash-offset in data area] failed" + fi + echo "[OK]" + remove_mapping +} + [ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." [ ! -x "$VERITYSETUP" ] && skip "Cannot find $VERITYSETUP, test skipped." @@ -208,6 +233,7 @@ check_root_hash 4096 ef29c902d87350f1da4bfa536e16cebc162a909bf89abe448b81ec500d4 check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1 8388608 check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1 8388608 + if check_version ; then echo "Verity data corruption options test." SALT=e48da609055204e89ae53b655ca2216dd983cf3cb829f34f63a297d106d53e2d @@ -219,5 +245,13 @@ if check_version ; then check_option 512 $HASH $SALT 1 sha256 "--ignore-corruption --ignore-zero-blocks" "ignore_corruption" fi +echo "Veritysetup [hash-offset bigger than 2G works] " +checkOffsetBug 3000000000 2499997696 256 +checkOffsetBug 10000000000 8000000000 128 + +echo "Veritysetup [overlap-detection] " +checkOverlapBug 2097152 1433600 +checkOverlapBug 2097152 1433600 350 + remove_mapping exit 0