nat44_get_log() compared the user buffer length against the request
header plus another ipfw_obj_header instead of the request header plus
the log buffer. A buffer that passed this check but was shorter than
the full reply left too little room in the sockopt window, so
ipfw_get_sopt_space() returned NULL and the following memcpy() of the
log wrote through a NULL pointer, panicking the kernel.
The handler was cloned from nat44_get_cfg() in the commit below, under
the convention of that time where ucfg->size held the payload only and
the ipfw_obj_header was added back in the length check. 9f925e8a920e
("Fix IP_FW_NAT44_LIST_NAT size calculation.") later switched
nat44_get_cfg() to count the header in ucfg->size and reduced its check
to "valsize < size", but nat44_get_log() was not updated. It kept the
stale idiom, whose check counts the header twice, and by coincidence of
the struct sizes that never leaves room for the log.
Compare against the full reply length and check the result of
ipfw_get_sopt_space(). Also report the full reply length, including
the ipfw_obj_header, in the size field returned with ENOMEM, as
nat44_get_cfg() now does: ipfw(8) retries with that value, and the old
one was itself too short to pass the check.
Add tests:
getlog_short_buffer - every buffer shorter than the reply gets ENOMEM
and the reply length; the reply length works.
getlog_retry - a retry with the length reported along with
ENOMEM succeeds.Without the fix, getlog_short_buffer panics the kernel and getlog_retry
fails.
Fixes: d6164b77f8b7 ("Make ipfw_nat module use IP_FW3 codes.")
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MFC after: 1 week