|
|
b9c414 |
From 9576549fee9228cabd9ceee27739a30caab5a7f6 Mon Sep 17 00:00:00 2001
|
|
|
b9c414 |
From: Milan Broz <gmazyland@gmail.com>
|
|
|
b9c414 |
Date: Tue, 9 Nov 2021 11:54:27 +0100
|
|
|
b9c414 |
Subject: [PATCH] Fix bogus memory allocation if LUKS2 header size is invalid.
|
|
|
b9c414 |
|
|
|
b9c414 |
LUKS2 code read the whole header to buffer to verify checksum,
|
|
|
b9c414 |
so malloc is called on unvalidated input size parameter.
|
|
|
b9c414 |
|
|
|
b9c414 |
This can cause out of memory or unintentional device reads.
|
|
|
b9c414 |
(Header validation will fail later anyway - the size is unsupported.)
|
|
|
b9c414 |
|
|
|
b9c414 |
Just do not allow too small and too big allocations here and fail quickly.
|
|
|
b9c414 |
|
|
|
b9c414 |
Fixes: #683.
|
|
|
b9c414 |
---
|
|
|
b9c414 |
lib/luks2/luks2_disk_metadata.c | 20 +++-
|
|
|
b9c414 |
...ks2-metadata-size-invalid-secondary.img.sh | 96 +++++++++++++++++++
|
|
|
b9c414 |
...enerate-luks2-metadata-size-invalid.img.sh | 94 ++++++++++++++++++
|
|
|
b9c414 |
tests/luks2-validation-test | 2 +
|
|
|
b9c414 |
4 files changed, 208 insertions(+), 4 deletions(-)
|
|
|
b9c414 |
create mode 100755 tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh
|
|
|
b9c414 |
create mode 100755 tests/generators/generate-luks2-metadata-size-invalid.img.sh
|
|
|
b9c414 |
|
|
|
b9c414 |
diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c
|
|
|
b9c414 |
index 502b0226..0500d5c7 100644
|
|
|
b9c414 |
--- a/lib/luks2/luks2_disk_metadata.c
|
|
|
b9c414 |
+++ b/lib/luks2/luks2_disk_metadata.c
|
|
|
b9c414 |
@@ -195,6 +195,8 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
|
|
|
b9c414 |
size_t *hdr_json_size, int secondary,
|
|
|
b9c414 |
uint64_t offset)
|
|
|
b9c414 |
{
|
|
|
b9c414 |
+ uint64_t hdr_size;
|
|
|
b9c414 |
+
|
|
|
b9c414 |
if (memcmp(hdr->magic, secondary ? LUKS2_MAGIC_2ND : LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
|
|
|
b9c414 |
return -EINVAL;
|
|
|
b9c414 |
|
|
|
b9c414 |
@@ -209,19 +211,26 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
|
|
|
b9c414 |
return -EINVAL;
|
|
|
b9c414 |
}
|
|
|
b9c414 |
|
|
|
b9c414 |
- if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
|
|
|
b9c414 |
+ hdr_size = be64_to_cpu(hdr->hdr_size);
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ if (hdr_size < LUKS2_HDR_16K_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
|
|
|
b9c414 |
+ log_dbg(cd, "LUKS2 header has bogus size 0x%04x.", (unsigned)hdr_size);
|
|
|
b9c414 |
+ return -EINVAL;
|
|
|
b9c414 |
+ }
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ if (secondary && (offset != hdr_size)) {
|
|
|
b9c414 |
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
|
|
|
b9c414 |
- (unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
|
|
|
b9c414 |
+ (unsigned)offset, (unsigned)hdr_size);
|
|
|
b9c414 |
return -EINVAL;
|
|
|
b9c414 |
}
|
|
|
b9c414 |
|
|
|
b9c414 |
/* FIXME: sanity check checksum alg. */
|
|
|
b9c414 |
|
|
|
b9c414 |
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
|
|
|
b9c414 |
- (unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
|
|
|
b9c414 |
+ (unsigned)be16_to_cpu(hdr->version), (unsigned)hdr_size,
|
|
|
b9c414 |
hdr->checksum_alg);
|
|
|
b9c414 |
|
|
|
b9c414 |
- *hdr_json_size = be64_to_cpu(hdr->hdr_size) - LUKS2_HDR_BIN_LEN;
|
|
|
b9c414 |
+ *hdr_json_size = hdr_size - LUKS2_HDR_BIN_LEN;
|
|
|
b9c414 |
return 0;
|
|
|
b9c414 |
}
|
|
|
b9c414 |
|
|
|
b9c414 |
@@ -252,6 +261,9 @@ static int hdr_read_disk(struct crypt_device *cd,
|
|
|
b9c414 |
return -EIO;
|
|
|
b9c414 |
}
|
|
|
b9c414 |
|
|
|
b9c414 |
+ /*
|
|
|
b9c414 |
+ * hdr_json_size is validated if this call succeeds
|
|
|
b9c414 |
+ */
|
|
|
b9c414 |
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
|
|
|
b9c414 |
if (r < 0) {
|
|
|
b9c414 |
return r;
|
|
|
b9c414 |
diff --git a/tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh b/tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh
|
|
|
b9c414 |
new file mode 100755
|
|
|
b9c414 |
index 00000000..4dd484e9
|
|
|
b9c414 |
--- /dev/null
|
|
|
b9c414 |
+++ b/tests/generators/generate-luks2-metadata-size-invalid-secondary.img.sh
|
|
|
b9c414 |
@@ -0,0 +1,96 @@
|
|
|
b9c414 |
+#!/bin/bash
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+. lib.sh
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# *** Description ***
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# generate primary with predefined json_size. There's only limited
|
|
|
b9c414 |
+# set of values allowed as json size in config section of LUKS2
|
|
|
b9c414 |
+# metadata
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# secondary header is corrupted on purpose as well
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+# $1 full target dir
|
|
|
b9c414 |
+# $2 full source luks2 image
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function prepare()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ cp $SRC_IMG $TGT_IMG
|
|
|
b9c414 |
+ test -d $TMPDIR || mkdir $TMPDIR
|
|
|
b9c414 |
+ read_luks2_json0 $TGT_IMG $TMPDIR/json0
|
|
|
b9c414 |
+ read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
|
|
|
b9c414 |
+ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function generate()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
|
|
|
b9c414 |
+ TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
|
|
|
b9c414 |
+ TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
|
|
|
b9c414 |
+ KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
|
|
|
b9c414 |
+ JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
|
|
|
b9c414 |
+ JSON_SIZE=$((TEST_JSN_SIZE*512))
|
|
|
b9c414 |
+ DATA_OFFSET=16777216
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
|
|
|
b9c414 |
+ '.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
|
|
|
b9c414 |
+ .config.json_size = $jsize |
|
|
|
b9c414 |
+ .segments."0".offset = $off' $TMPDIR/json0)
|
|
|
b9c414 |
+ test -n "$json_str" || exit 2
|
|
|
b9c414 |
+ test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BYTES
|
|
|
b9c414 |
+ write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_bin_hdr_offset $TMPDIR/hdr1 $TEST_MDA_SIZE_BYTES
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
|
|
|
b9c414 |
+ merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ erase_checksum $TMPDIR/area0
|
|
|
b9c414 |
+ chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
|
|
|
b9c414 |
+ write_checksum $chks0 $TMPDIR/area0
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ erase_checksum $TMPDIR/area1
|
|
|
b9c414 |
+ chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
|
|
|
b9c414 |
+ write_checksum $chks0 $TMPDIR/area1
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ kill_bin_hdr $TMPDIR/area0
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
|
|
|
b9c414 |
+ write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function check()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr_res0 $TEST_MDA_SIZE
|
|
|
b9c414 |
+ local str_res0=$(head -c 6 $TMPDIR/hdr_res0)
|
|
|
b9c414 |
+ test "$str_res0" = "VACUUM" || exit 2
|
|
|
b9c414 |
+ read_luks2_json1 $TGT_IMG $TMPDIR/json_res1 $TEST_JSN_SIZE
|
|
|
b9c414 |
+ jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
|
|
|
b9c414 |
+ 'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
|
|
|
b9c414 |
+ (.config.json_size != $jsize)
|
|
|
b9c414 |
+ then error("Unexpected value in result json") else empty end' $TMPDIR/json_res1 || exit 5
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function cleanup()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ rm -f $TMPDIR/*
|
|
|
b9c414 |
+ rm -fd $TMPDIR
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+test $# -eq 2 || exit 1
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+TGT_IMG=$1/$(test_img_name $0)
|
|
|
b9c414 |
+SRC_IMG=$2
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+prepare
|
|
|
b9c414 |
+generate
|
|
|
b9c414 |
+check
|
|
|
b9c414 |
+cleanup
|
|
|
b9c414 |
diff --git a/tests/generators/generate-luks2-metadata-size-invalid.img.sh b/tests/generators/generate-luks2-metadata-size-invalid.img.sh
|
|
|
b9c414 |
new file mode 100755
|
|
|
b9c414 |
index 00000000..6b9c0cf7
|
|
|
b9c414 |
--- /dev/null
|
|
|
b9c414 |
+++ b/tests/generators/generate-luks2-metadata-size-invalid.img.sh
|
|
|
b9c414 |
@@ -0,0 +1,94 @@
|
|
|
b9c414 |
+#!/bin/bash
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+. lib.sh
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# *** Description ***
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# generate primary with predefined json_size. There's only limited
|
|
|
b9c414 |
+# set of values allowed as json size in config section of LUKS2
|
|
|
b9c414 |
+# metadata
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+# secondary header is corrupted on purpose as well
|
|
|
b9c414 |
+#
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+# $1 full target dir
|
|
|
b9c414 |
+# $2 full source luks2 image
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function prepare()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ cp $SRC_IMG $TGT_IMG
|
|
|
b9c414 |
+ test -d $TMPDIR || mkdir $TMPDIR
|
|
|
b9c414 |
+ read_luks2_json0 $TGT_IMG $TMPDIR/json0
|
|
|
b9c414 |
+ read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0
|
|
|
b9c414 |
+ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function generate()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ TEST_MDA_SIZE=$LUKS2_HDR_SIZE_1M
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ TEST_MDA_SIZE_BYTES=$((TEST_MDA_SIZE*512))
|
|
|
b9c414 |
+ TEST_MDA_SIZE_BOGUS_BYTES=$((TEST_MDA_SIZE*512*2*1024))
|
|
|
b9c414 |
+ TEST_JSN_SIZE=$((TEST_MDA_SIZE-LUKS2_BIN_HDR_SIZE))
|
|
|
b9c414 |
+ KEYSLOTS_OFFSET=$((TEST_MDA_SIZE*1024))
|
|
|
b9c414 |
+ JSON_DIFF=$(((TEST_MDA_SIZE-LUKS2_HDR_SIZE)*1024))
|
|
|
b9c414 |
+ JSON_SIZE=$((TEST_JSN_SIZE*512))
|
|
|
b9c414 |
+ DATA_OFFSET=16777216
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ json_str=$(jq -c --arg jdiff $JSON_DIFF --arg jsize $JSON_SIZE --arg off $DATA_OFFSET \
|
|
|
b9c414 |
+ '.keyslots[].area.offset |= ( . | tonumber + ($jdiff | tonumber) | tostring) |
|
|
|
b9c414 |
+ .config.json_size = $jsize |
|
|
|
b9c414 |
+ .segments."0".offset = $off' $TMPDIR/json0)
|
|
|
b9c414 |
+ test -n "$json_str" || exit 2
|
|
|
b9c414 |
+ test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_luks2_json "$json_str" $TMPDIR/json0 $TEST_JSN_SIZE
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_bin_hdr_size $TMPDIR/hdr0 $TEST_MDA_SIZE_BOGUS_BYTES
|
|
|
b9c414 |
+ write_bin_hdr_size $TMPDIR/hdr1 $TEST_MDA_SIZE_BOGUS_BYTES
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 $TEST_JSN_SIZE
|
|
|
b9c414 |
+ merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json0 $TMPDIR/area1 $TEST_JSN_SIZE
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ erase_checksum $TMPDIR/area0
|
|
|
b9c414 |
+ chks0=$(calc_sha256_checksum_file $TMPDIR/area0)
|
|
|
b9c414 |
+ write_checksum $chks0 $TMPDIR/area0
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ erase_checksum $TMPDIR/area1
|
|
|
b9c414 |
+ chks0=$(calc_sha256_checksum_file $TMPDIR/area1)
|
|
|
b9c414 |
+ write_checksum $chks0 $TMPDIR/area1
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ kill_bin_hdr $TMPDIR/area1
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+ write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG $TEST_MDA_SIZE
|
|
|
b9c414 |
+ write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG $TEST_MDA_SIZE
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function check()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 $TEST_MDA_SIZE
|
|
|
b9c414 |
+ local str_res1=$(head -c 6 $TMPDIR/hdr_res1)
|
|
|
b9c414 |
+ test "$str_res1" = "VACUUM" || exit 2
|
|
|
b9c414 |
+ read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 $TEST_JSN_SIZE
|
|
|
b9c414 |
+ jq -c --arg koff $KEYSLOTS_OFFSET --arg jsize $JSON_SIZE \
|
|
|
b9c414 |
+ 'if ([.keyslots[].area.offset] | map(tonumber) | min | tostring != $koff) or
|
|
|
b9c414 |
+ (.config.json_size != $jsize)
|
|
|
b9c414 |
+ then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+function cleanup()
|
|
|
b9c414 |
+{
|
|
|
b9c414 |
+ rm -f $TMPDIR/*
|
|
|
b9c414 |
+ rm -fd $TMPDIR
|
|
|
b9c414 |
+}
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+test $# -eq 2 || exit 1
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+TGT_IMG=$1/$(test_img_name $0)
|
|
|
b9c414 |
+SRC_IMG=$2
|
|
|
b9c414 |
+
|
|
|
b9c414 |
+prepare
|
|
|
b9c414 |
+generate
|
|
|
b9c414 |
+check
|
|
|
b9c414 |
+cleanup
|
|
|
b9c414 |
diff --git a/tests/luks2-validation-test b/tests/luks2-validation-test
|
|
|
b9c414 |
index 04183fbc..f771e1f9 100755
|
|
|
b9c414 |
--- a/tests/luks2-validation-test
|
|
|
b9c414 |
+++ b/tests/luks2-validation-test
|
|
|
b9c414 |
@@ -229,6 +229,8 @@ RUN luks2-metadata-size-512k-secondary.img "R" "Valid 512KiB metadata size in s
|
|
|
b9c414 |
RUN luks2-metadata-size-1m-secondary.img "R" "Valid 1MiB metadata size in secondary hdr failed to validate"
|
|
|
b9c414 |
RUN luks2-metadata-size-2m-secondary.img "R" "Valid 2MiB metadata size in secondary hdr failed to validate"
|
|
|
b9c414 |
RUN luks2-metadata-size-4m-secondary.img "R" "Valid 4MiB metadata size in secondary hdr failed to validate"
|
|
|
b9c414 |
+RUN luks2-metadata-size-invalid.img "F" "Invalid metadata size in secondary hdr not rejected"
|
|
|
b9c414 |
+RUN luks2-metadata-size-invalid-secondary.img "F" "Invalid metadata size in secondary hdr not rejected"
|
|
|
b9c414 |
|
|
|
b9c414 |
remove_mapping
|
|
|
b9c414 |
|
|
|
b9c414 |
--
|
|
|
b9c414 |
2.27.0
|
|
|
b9c414 |
|