Skip to content

Commit b0cc3ae

Browse files
avasummerhailan94
authored andcommitted
md/raid5: validate payload size before accessing journal metadata
r5c_recovery_analyze_meta_block() and r5l_recovery_verify_data_checksum_for_mb() iterate over payloads in a journal metadata block using on-disk payload size fields without validating them against the remaining space in the metadata block. A corrupted journal contains payload sizes extending beyond the PAGE_SIZE boundary can cause out-of-bounds reads when accessing payload fields or computing offsets. Add bounds validation for each payload type to ensure the full payload fits within meta_size before processing. Fixes: b4c625c ("md/r5cache: r5cache recovery: part 1") Cc: stable@vger.kernel.org Signed-off-by: Junrui Luo <moonafterrain@outlook.com> Link: https://lore.kernel.org/linux-raid/SYBPR01MB78815E78D829BB86CD7C8015AF5FA@SYBPR01MB7881.ausprd01.prod.outlook.com/ Signed-off-by: Yu Kuai <yukuai@fnnas.com>
1 parent e4979f4 commit b0cc3ae

1 file changed

Lines changed: 33 additions & 15 deletions

File tree

drivers/md/raid5-cache.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,15 +2002,27 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
20022002
return -ENOMEM;
20032003

20042004
while (mb_offset < le32_to_cpu(mb->meta_size)) {
2005+
sector_t payload_len;
2006+
20052007
payload = (void *)mb + mb_offset;
20062008
payload_flush = (void *)mb + mb_offset;
20072009

20082010
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) {
2011+
payload_len = sizeof(struct r5l_payload_data_parity) +
2012+
(sector_t)sizeof(__le32) *
2013+
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
2014+
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
2015+
goto mismatch;
20092016
if (r5l_recovery_verify_data_checksum(
20102017
log, ctx, page, log_offset,
20112018
payload->checksum[0]) < 0)
20122019
goto mismatch;
20132020
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_PARITY) {
2021+
payload_len = sizeof(struct r5l_payload_data_parity) +
2022+
(sector_t)sizeof(__le32) *
2023+
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
2024+
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
2025+
goto mismatch;
20142026
if (r5l_recovery_verify_data_checksum(
20152027
log, ctx, page, log_offset,
20162028
payload->checksum[0]) < 0)
@@ -2023,22 +2035,18 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
20232035
payload->checksum[1]) < 0)
20242036
goto mismatch;
20252037
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
2026-
/* nothing to do for R5LOG_PAYLOAD_FLUSH here */
2038+
payload_len = sizeof(struct r5l_payload_flush) +
2039+
(sector_t)le32_to_cpu(payload_flush->size);
2040+
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
2041+
goto mismatch;
20272042
} else /* not R5LOG_PAYLOAD_DATA/PARITY/FLUSH */
20282043
goto mismatch;
20292044

2030-
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
2031-
mb_offset += sizeof(struct r5l_payload_flush) +
2032-
le32_to_cpu(payload_flush->size);
2033-
} else {
2034-
/* DATA or PARITY payload */
2045+
if (le16_to_cpu(payload->header.type) != R5LOG_PAYLOAD_FLUSH) {
20352046
log_offset = r5l_ring_add(log, log_offset,
20362047
le32_to_cpu(payload->size));
2037-
mb_offset += sizeof(struct r5l_payload_data_parity) +
2038-
sizeof(__le32) *
2039-
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
20402048
}
2041-
2049+
mb_offset += payload_len;
20422050
}
20432051

20442052
put_page(page);
@@ -2089,6 +2097,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
20892097
log_offset = r5l_ring_add(log, ctx->pos, BLOCK_SECTORS);
20902098

20912099
while (mb_offset < le32_to_cpu(mb->meta_size)) {
2100+
sector_t payload_len;
20922101
int dd;
20932102

20942103
payload = (void *)mb + mb_offset;
@@ -2097,6 +2106,12 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
20972106
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
20982107
int i, count;
20992108

2109+
payload_len = sizeof(struct r5l_payload_flush) +
2110+
(sector_t)le32_to_cpu(payload_flush->size);
2111+
if (mb_offset + payload_len >
2112+
le32_to_cpu(mb->meta_size))
2113+
return -EINVAL;
2114+
21002115
count = le32_to_cpu(payload_flush->size) / sizeof(__le64);
21012116
for (i = 0; i < count; ++i) {
21022117
stripe_sect = le64_to_cpu(payload_flush->flush_stripes[i]);
@@ -2110,12 +2125,17 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
21102125
}
21112126
}
21122127

2113-
mb_offset += sizeof(struct r5l_payload_flush) +
2114-
le32_to_cpu(payload_flush->size);
2128+
mb_offset += payload_len;
21152129
continue;
21162130
}
21172131

21182132
/* DATA or PARITY payload */
2133+
payload_len = sizeof(struct r5l_payload_data_parity) +
2134+
(sector_t)sizeof(__le32) *
2135+
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
2136+
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
2137+
return -EINVAL;
2138+
21192139
stripe_sect = (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) ?
21202140
raid5_compute_sector(
21212141
conf, le64_to_cpu(payload->location), 0, &dd,
@@ -2180,9 +2200,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
21802200
log_offset = r5l_ring_add(log, log_offset,
21812201
le32_to_cpu(payload->size));
21822202

2183-
mb_offset += sizeof(struct r5l_payload_data_parity) +
2184-
sizeof(__le32) *
2185-
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
2203+
mb_offset += payload_len;
21862204
}
21872205

21882206
return 0;

0 commit comments

Comments
 (0)