[Fix] Close snapshot truncation race and query corruption
Two review findings.
rspamd_shmem_segment_map() mapped the selected window and copied out of
it. The backing object belongs to the client, so an ftruncate landing
between the fstat and the memcpy raised SIGBUS inside the copy and took
the worker down; the mapping was only dropped afterwards, so the earlier
regression test, which resized the object once the call had already
returned, never exercised that window at all.
Read the window straight into pool storage instead. A read cannot fault:
a concurrent truncation merely returns fewer bytes, and the payload
length now reflects what was actually read rather than what was asked
for. Short reads and EINTR are handled in the loop.
POSIX shared memory descriptors do not accept positional reads on every
platform - macOS reports ESPIPE and some BSDs ENODEV - so the mapping
path is kept as a fallback for exactly those descriptors. On Linux,
where shared memory objects live on tmpfs and HAVE_SANE_SHMEM is always
set, the read path is the one taken and the race is closed.
proxy_strip_query_args() rebuilt the url from a prefix of
u.field_data[UF_QUERY].off bytes. That offset addresses the first byte
after the '?', so the prefix already carried the delimiter and the
appended one produced '/checkv2??From=...'. Since the proxy turns query
arguments into request headers at the upstream, the first surviving
argument was then parsed as '?From' and its value silently lost. Stop
the prefix one byte short. The previous test stripped every argument
present, so nothing survived and the corruption stayed invisible.
Both regressions are now covered. A thread toggles the size of a backing
object while the snapshot is taken repeatedly, which faults on the old
code and passes on the new one, and a proxy request now carries an
ordinary query argument alongside a privileged one and asserts the
ordinary one reaches the upstream intact.