Patch for the stack out-of-bounds write described in #1153070. Both merge loops in `wvApplysprmPChgTabsPapx()` (`sprm.c:1266`) and the copy-pasted one in `wvApplysprmPChgTabs()` (`sprm.c:1440`) are bounded only by the source lists, while the destination arrays `rgdxaTab[]` / `rgtbd[]` hold 64 entries. The patch adds `&& (k < itbdMax)` to both loop conditions, so writes stop at the array bound and `itbdMac` is then set from the clamped `k`.
Tested on a plain/optimised build of 1.2.9 with the patch applied: - patched-pchtabs.doc: "*** stack smashing detected ***" / SEGV before, rc=0 after - pchtabs-inbounds.doc (direct ASan `WRITE of size 4` sample): rc=0 after - merge-chpx-oob.doc and merge-chpx-write-207.doc from #1153069: rc=0 after - wv-corpus/backslash.doc: RTF output byte-identical before and after (1325 bytes) Patch attached. It is two one-line condition changes and covers both sibling functions. Happy to retest or rework the approach. Patch for the stack out-of-bounds write described in #1153070. Both merge loops in `wvApplysprmPChgTabsPapx()` (`sprm.c:1266`) and the copy-pasted one in `wvApplysprmPChgTabs()` (`sprm.c:1440`) are bounded only by the source lists, while the destination arrays `rgdxaTab[]` / `rgtbd[]` hold 64 entries. The patch adds `&& (k < itbdMax)` to both loop conditions, so writes stop at the array bound and `itbdMac` is then set from the clamped `k`. Tested on a plain/optimised build of 1.2.9 with the patch applied: - patched-pchtabs.doc: "*** stack smashing detected ***" / SEGV before, rc=0 after - pchtabs-inbounds.doc (direct ASan `WRITE of size 4` sample): rc=0 after - merge-chpx-oob.doc and merge-chpx-write-207.doc from #1153069: rc=0 after - wv-corpus/backslash.doc: RTF output byte-identical before and after (1325 bytes) Patch attached. It is two one-line condition changes and covers both sibling functions. Happy to retest or rework the approach.
fix-sprm-1153070.patch
Description: fix-sprm-1153070.patch
# Fix verification: BTS #1153069 and #1153070 Tree: `~/fuzz/wv-fix2` (copy of `wv-fixed`, which already carries the #1153067 fix) Patch: `wv-oob-fixes.patch` (chp.c + sprm.c, 95 lines) SHA-256 of patch: `f3463237bf925da799cc00c3c6e49186fd0b3150b7737101955ad27dbc83abfa` ## Change summary ### chp.c (`wvMergeCHPXFromBucket`) â #1153069 heap OOB write - accumulator `U8 len` â `size_t total` so the merged length no longer wraps at 256 - allocation uses `total`, copy loop bounded by a `left` counter that starts at `total` - stored `dest->cbGrpprl` (still `U8` by ABI) clamped to `0xff` ### sprm.c (`wvApplysprmPChgTabsPapx`, `wvApplysprmPChgTabs`) â #1153070 stack OOB write - both merge loops get `&& (k < itbdMax)` so writes stop at the 64-entry arrays ## Verification (patched build, plain/optimised) | input | before (wv-clean) | after (wv-fix2) | |---|---|---| | `merge-chpx-oob.doc` | SEGV 139 | rc=0 | | `merge-chpx-write-207.doc` | `double free or corruption`, abort | rc=0 | | `patched-pchtabs.doc` | `*** stack smashing detected ***` / SEGV | rc=0 | | `pchtabs-inbounds.doc` | SEGV 139 | rc=0 | | `simple-bkd-len4.doc` (#1153067) | `free(): invalid pointer`, 134 | rc=0 | Functional check: `wv-corpus/backslash.doc` produces byte-identical RTF before and after (1325 bytes, `cmp` clean), so the bound changes do not alter normal output. ## Note `wvMergeCHPXFromBucket6()` (the Word 6 variant in the same file) still keeps a `U16 len`; it did not overflow in any of the samples here and is left untouched to keep the patch minimal.

