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.
This commit is contained in:
Gleb Chesnokov
2026-10-21 13:20:12 +03:00
parent b74e00e63b
commit aadd0a457f
2 changed files with 31 additions and 3 deletions
@@ -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),
+3 -3
View File
@@ -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: