diff --git a/sys/vfs/hammer/hammer_recover.c b/sys/vfs/hammer/hammer_recover.c --- a/sys/vfs/hammer/hammer_recover.c +++ b/sys/vfs/hammer/hammer_recover.c @@ -1321,6 +1321,26 @@ switch(redo->redo_flags) { case HAMMER_REDO_WRITE: + /* + * Validate redo_data_bytes against the record capacity, + * mirroring the UNDO path validation above + * (hammer_recover.c:1053-1060). redo_data_bytes is an + * attacker-controllable int32 from disk; without this + * check vn_rdwr() copies past the record into adjacent + * kernel heap (info leak) or unmapped pages (panic). + */ + { + int redo_cap = redo->head.hdr_size - + (int)sizeof(struct hammer_fifo_redo) - + (int)sizeof(struct hammer_fifo_tail); + if (redo_cap < 0 || redo->redo_data_bytes < 0 || + redo->redo_data_bytes > redo_cap) { + hkprintf("Corrupt REDO record, " + "redo_data_bytes %d/%d\n", + redo->redo_data_bytes, redo_cap); + break; + } + } error = VOP_OPEN(vp, FREAD|FWRITE, proc0.p_ucred, NULL); if (error) { hkprintf("vn_rdwr open %016jx:%08x returned %d\n",