From aadd0a457fca9ff2d17a85440cb0a2a9e40bcd90 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Wed, 21 Oct 2026 09:51:32 +0300 Subject: [PATCH] scst_lib: Decode unaligned LUN buffers safely Manual review found alignment-dependent loads in scst_unpack_lun; no saved analyzer diagnostic directly reports this defect. The helper accepts a byte pointer without an alignment contract, then casts it to 16-, 32- or 64-bit pointers. In particular, a six-byte LUN reads a 32-bit tail at offset two even when the start is aligned. Use unaligned big-endian loads for each supported length while retaining flat-address decoding and rejection of nonzero tail bytes. This preserves the public interface and avoids faults on strict-alignment architectures. Add KUnit coverage for all eight alignments and supported lengths, nonzero bytes outside the supplied length, and every rejected tail byte. --- scst/src/kunit/lib/suites/scst_kunit_lib.c | 28 ++++++++++++++++++++++ scst/src/scst_lib.c | 6 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/scst/src/kunit/lib/suites/scst_kunit_lib.c b/scst/src/kunit/lib/suites/scst_kunit_lib.c index e4ec17c08..eaa28d365 100644 --- a/scst/src/kunit/lib/suites/scst_kunit_lib.c +++ b/scst/src/kunit/lib/suites/scst_kunit_lib.c @@ -236,7 +236,35 @@ static void scst_cdb_trace_bounds(struct kunit *test) KUNIT_EXPECT_EQ(test, buf[1], 'x'); } +static void scst_lun_unaligned_encoding(struct kunit *test) +{ + u8 data[16] __aligned(8); + unsigned int offset, len, tail; + + for (offset = 0; offset < 8; offset++) { + for (len = 2; len <= 8; len += 2) { + u8 *lun = data + offset; + + /* Nonzero bytes outside len must not affect decoding. */ + memset(data, 0x5a, sizeof(data)); + memset(lun, 0, len); + lun[0] = 0x52; + lun[1] = 0x34; + KUNIT_EXPECT_EQ_MSG(test, scst_unpack_lun(lun, len), (u64)0x1234, + "offset=%u len=%u", offset, len); + for (tail = 2; tail < len; tail++) { + lun[tail] = 1; + KUNIT_EXPECT_EQ_MSG(test, scst_unpack_lun(lun, len), + (u64)NO_SUCH_LUN, "offset=%u len=%u tail=%u", + offset, len, tail); + lun[tail] = 0; + } + } + } +} + static struct kunit_case scst_lib_cases[] = { + KUNIT_CASE(scst_lun_unaligned_encoding), KUNIT_CASE(scst_cdb_trace_bounds), #if (defined(CONFIG_DLM) || defined(CONFIG_DLM_MODULE)) && !defined(CONFIG_SCST_NO_DLM) KUNIT_CASE(scst_dlm_directory_error_preserves_membership), diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 682ee69d9..3320731fa 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -12371,15 +12371,15 @@ uint64_t scst_unpack_lun(const uint8_t *lun, int len) case 2: break; case 8: - if ((*((__be64 const *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0) + if (get_unaligned_be64(lun) & 0x0000FFFFFFFFFFFFULL) goto out_err; break; case 4: - if (*((__be16 const *)&lun[2]) != 0) + if (get_unaligned_be16(lun + 2) != 0) goto out_err; break; case 6: - if (*((__be32 const *)&lun[2]) != 0) + if (get_unaligned_be32(lun + 2) != 0) goto out_err; break; case 1: