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.

Attachment: 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.

Reply via email to