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;

Reply via email to