Summary:
In function sr_meta_init in softraid.c, there are two bugs which cause the
chunk checksum stored in scm_checksum to be incorrectly calculated. This
affects all newly created softraid volumes.
Details:
The MD5 checksum in scm_checksum should be calculated over the first 72 bytes
of struct sr_meta_chunk, that data being the contents of
struct sr_meta_chunk_invariant.
However, the current code, (since the bug was introduced in revision 1.262),
does the following:
sr_checksum(sc, scm, &scm->scm_checksum,
sizeof(scm->scm_checksum));
sizeof(scm->scm_checksum) always evaluates to MD5_DIGEST_LENGTH, or 16 bytes.
As a result, the checksum is calculated from just the members scm_volid,
scm_chunk_id, and the first eight bytes of the device name. This leaves the
two chunk size and uuid fields unprotected by checksum.
To make matters worse, there is a second bug, because the code to set
scm_coerced_size is not run until _after_ the checksum has been calculated.
As a result, simply fixing the last argument to sr_checksum isn't sufficient,
as the checksum would then be performed on incomplete data, since
scm_coerced_size remains unset at this point.
Fix:
The following patch moves the call to sr_checksum into the second loop, and
corrects it's arguments. This modified code produces valid checksums for the
whole of sr_meta_chunk_invariant.
Patch applies to -current and also applies cleanly to 7.0-release.
untrusted comment: verify with Exotic Silicon public signify key
RWRn5d3Yx35u0/6q18/WsBkdPkMziSWosd4n3NmI09dppZcyf653fXw7HzFxy+uACtRi1xC5uqg9w5bR/BtVWjonnA7t6diaoAQ=
--- softraid.c.dist Sat Mar 26 19:40:51 2022
+++ softraid.c Sat Mar 26 20:59:46 2022
@@ -567,8 +567,6 @@
sizeof(scm->scmi.scm_devname));
memcpy(&scm->scmi.scm_uuid, &sm->ssdi.ssd_uuid,
sizeof(scm->scmi.scm_uuid));
- sr_checksum(sc, scm, &scm->scm_checksum,
- sizeof(scm->scm_checksum));
if (min_chunk_sz == 0)
min_chunk_sz = scm->scmi.scm_size;
@@ -580,9 +578,12 @@
sm->ssdi.ssd_secsize = secsize;
- /* Equalize chunk sizes. */
- SLIST_FOREACH(chunk, cl, src_link)
+ /* Equalize chunk sizes and calculate chunk checksum. */
+ SLIST_FOREACH(chunk, cl, src_link) {
chunk->src_meta.scmi.scm_coerced_size = min_chunk_sz;
+ sr_checksum(sc, scm, &scm->scm_checksum,
+ sizeof(struct sr_meta_chunk_invariant));
+ }
sd->sd_vol.sv_chunk_minsz = min_chunk_sz;
sd->sd_vol.sv_chunk_maxsz = max_chunk_sz;