diff --git a/src/libltfs/tape.c b/src/libltfs/tape.c index f971cb79..a3280fd6 100644 --- a/src/libltfs/tape.c +++ b/src/libltfs/tape.c @@ -1665,6 +1665,13 @@ int tape_get_volume_change_reference(struct device_data *dev, uint64_t *volume_c int ret; unsigned char vcr_data[TC_MAM_PAGE_VCR_SIZE + TC_MAM_PAGE_HEADER_SIZE]; + /* The VCR is read as a 32-bit field at offset 5 (just past the page + * header), so the buffer must hold at least 5 + 4 bytes. Lock that at + * compile time so a change to the page-size constants cannot make the + * read below run off the end of the buffer. */ + _Static_assert(sizeof(vcr_data) >= 5 + sizeof(uint32_t), + "MAM VCR page too small to hold the volume change reference"); + CHECK_ARG_NULL(dev, -LTFS_NULL_ARG); CHECK_ARG_NULL(dev->backend, -LTFS_NULL_ARG); @@ -1741,7 +1748,8 @@ int tape_get_cart_coherency(struct device_data *dev, const tape_partition_t part if (ap_clent_specific_len != 42 && ap_clent_specific_len != 43) { ltfsmsg(LTFS_WARN, 12061W, ap_clent_specific_len); return -LTFS_UNEXPECTED_VALUE; - } else if (strncmp((char *)coh_data + 32, "LTFS", sizeof("LTFS")) != 0) { + } else if (strncmp((char *)coh_data + 32, TC_MAM_COHERENCY_SIGNATURE, + sizeof(TC_MAM_COHERENCY_SIGNATURE)) != 0) { ltfsmsg(LTFS_WARN, 12062W); return -LTFS_UNEXPECTED_VALUE; } @@ -1769,6 +1777,18 @@ int tape_set_cart_coherency(struct device_data *dev, const tape_partition_t part int ret; unsigned char coh_data[TC_MAM_PAGE_COHERENCY_SIZE + TC_MAM_PAGE_HEADER_SIZE]; + /* The coherency record is written below at fixed byte offsets; the version + * byte at offset 74 is the highest, so the page must be at least 75 bytes. + * Lock that invariant at compile time so a future change to the page-size + * constants cannot silently overflow this stack buffer. */ + _Static_assert(sizeof(coh_data) > 74, + "MAM coherency page too small for the coherency record layout"); + + /* Zero unwritten bytes for deterministic on-medium content. The "LTFS" + * signature's NUL terminator is written explicitly below, so correctness of + * the signature no longer depends on this memset. */ + memset(coh_data, 0, sizeof(coh_data)); + CHECK_ARG_NULL(dev, -LTFS_NULL_ARG); CHECK_ARG_NULL(dev->backend, -LTFS_NULL_ARG); @@ -1782,8 +1802,13 @@ int tape_set_cart_coherency(struct device_data *dev, const tape_partition_t part /* APPLICATION CLIENT SPECIFIC INFORMATION LENGTH */ coh_data[30] = 0; /* Size of APPLICATION CLIENT SPECIFIC INFORMATION (Byte 1) */ coh_data[31] = 43; /* Size of APPLICATION CLIENT SPECIFIC INFORMATION (Byte 0) */ - /* Size of the buffer to insert 'LTFS' needs to be size of 5 for the 4 letters and the null terminator*/ - arch_strncpy((char *)coh_data + 32,"LTFS", 5, 4); + /* Volume coherency signature: the 4 letters "LTFS" plus a trailing NUL at + * offset 36. The reader compares all 5 bytes, so copy the NUL terminator + * explicitly (an earlier strncpy-based write copied only 4 bytes and left + * byte 36 uninitialised, triggering a full consistency check on every mount). */ + _Static_assert(sizeof(TC_MAM_COHERENCY_SIGNATURE) == 5, + "LTFS coherency signature must be 4 characters plus a NUL terminator"); + memcpy(coh_data + 32, TC_MAM_COHERENCY_SIGNATURE, sizeof(TC_MAM_COHERENCY_SIGNATURE)); memcpy(coh_data + 37, coh->uuid, 37); /* Version field @@ -1803,6 +1828,13 @@ int tape_get_cart_volume_lock_status(struct device_data *dev, int *status) int ret; unsigned char attr_data[TC_MAM_LOCKED_MAM_SIZE + TC_MAM_PAGE_HEADER_SIZE]; + /* The lock status byte is read at offset TC_MAM_PAGE_HEADER_SIZE, so the + * buffer must extend past the page header. Lock that at compile time so a + * change to the page-size constants cannot make the read below run off the + * end of the buffer. */ + _Static_assert(sizeof(attr_data) > TC_MAM_PAGE_HEADER_SIZE, + "MAM locked-MAM page too small to hold the lock status byte"); + CHECK_ARG_NULL(dev, -LTFS_NULL_ARG); CHECK_ARG_NULL(status, -LTFS_NULL_ARG); diff --git a/src/libltfs/tape_ops.h b/src/libltfs/tape_ops.h index 34c7a128..75160422 100644 --- a/src/libltfs/tape_ops.h +++ b/src/libltfs/tape_ops.h @@ -250,6 +250,7 @@ typedef enum { #define TC_MAM_PAGE_VCR_SIZE (0x4) /* Size of Volume Change Reference */ #define TC_MAM_PAGE_COHERENCY (0x080C) #define TC_MAM_PAGE_COHERENCY_SIZE (0x46) +#define TC_MAM_COHERENCY_SIGNATURE "LTFS" /* Volume coherency signature; 4 chars + NUL, reader compares all 5 */ #define TC_MAM_APP_VENDER (0x0800) #define TC_MAM_APP_VENDER_SIZE (0x8)