Status: UNREPRODUCED — triage backlog, not findings
These are static observations from the same audit that produced the confirmed
issues. They were not attempted — the reproduction effort was timeboxed and
spent on the higher-severity candidates. Each is plausible and each has a
specific counter-hypothesis that could kill it. Please don't treat any of them
as a bug until someone has run it.
Filed as one issue so they are not lost, and so nobody spends the effort
rediscovering them. Reproducing any of these is cheap with the pattern the
confirmed ones used: drive Machine::system_call() directly on a fork and
compare the result against what Linux does.
Medium
ppoll does not clamp its timeout on non-forked machines —
system_calls.cpp:396. poll() clamps to 1 ms when !is_forked()
(:330); ppoll has no equivalent. If that clamp exists to stop a master
from blocking, ppoll is missing the same protection.
Low — wrong answer to the guest
pwrite64 returns the requested length, not the pwritev64() result —
system_calls.cpp:800. Wrong byte count on short writes.
lseek truncates the 64-bit result to int for its error check —
system_calls.cpp:286. A seek to an offset with bit 31 set in the low word
reports failure, with a stale errno.
accept4 returns without setting registers on policy denial —
system_calls.cpp:1294. The guest sees a garbage success value.
gettimeofday(NULL, …) writes the timeval to guest address 0 —
system_calls.cpp:2151.
flock reports LOCK_EX/LOCK_SH success without taking the lock —
system_calls.cpp:1781.
clock_nanosleep blocks the host thread on a guest-chosen timespec and
reports failure as success — system_calls.cpp:2378.
close() of a loaned (is_forked) fd returns success but keeps the
entry — system_calls.cpp:177. Use-after-close then succeeds.
Low — arithmetic and bookkeeping
mmap/mremap 64-bit addr + len wrap corrupts mmap-cache bookkeeping —
system_calls.cpp:415. Medium confidence.
m_total_fds_opened is uint16_t and wraps at 65536 — fds.cpp:138,
defeating the embedder's total-fd limit.
fcntl(F_DUPFD_CLOEXEC) hands an unchecked dup() to manage_duplicate() —
system_calls.cpp:1890.
translate() ignores KVM_TRANSLATE's valid bit — machine.cpp:370.
Medium confidence; the only consequence found was a spurious
MemoryException.
Low — no current caller
copy_from_cstring() over-reads up to offset bytes past each page end —
machine_utils.cpp:617. Zero callers today.
relocate_section() / relocate_relr_section() wrapped relocation
addresses, and elf_offset_array() count overflow — machine_elf.cpp:425.
Embedder-API-only; dynamic_linking() has been a no-op since 864ad8d. This
one was attempted in wave 2 and could not be reproduced.
close() returns early without setting registers when free_fd_callback
resets the VM — system_calls.cpp:170. Borderline out of scope, since it
needs an embedder callback.
- ARM64 nested signal delivery grows
SignalReturn::frames unboundedly —
signals.cpp:87. Low confidence, and needs an AArch64 host.
Cosmetic, noted in passing
Status: UNREPRODUCED — triage backlog, not findings
These are static observations from the same audit that produced the confirmed
issues. They were not attempted — the reproduction effort was timeboxed and
spent on the higher-severity candidates. Each is plausible and each has a
specific counter-hypothesis that could kill it. Please don't treat any of them
as a bug until someone has run it.
Filed as one issue so they are not lost, and so nobody spends the effort
rediscovering them. Reproducing any of these is cheap with the pattern the
confirmed ones used: drive
Machine::system_call()directly on a fork andcompare the result against what Linux does.
Medium
ppolldoes not clamp its timeout on non-forked machines —system_calls.cpp:396.poll()clamps to 1 ms when!is_forked()(
:330);ppollhas no equivalent. If that clamp exists to stop a masterfrom blocking,
ppollis missing the same protection.Low — wrong answer to the guest
pwrite64returns the requested length, not thepwritev64()result —system_calls.cpp:800. Wrong byte count on short writes.lseektruncates the 64-bit result tointfor its error check —system_calls.cpp:286. A seek to an offset with bit 31 set in the low wordreports failure, with a stale errno.
accept4returns without setting registers on policy denial —system_calls.cpp:1294. The guest sees a garbage success value.gettimeofday(NULL, …)writes the timeval to guest address 0 —system_calls.cpp:2151.flockreportsLOCK_EX/LOCK_SHsuccess without taking the lock —system_calls.cpp:1781.clock_nanosleepblocks the host thread on a guest-chosen timespec andreports failure as success —
system_calls.cpp:2378.close()of a loaned (is_forked) fd returns success but keeps theentry —
system_calls.cpp:177. Use-after-close then succeeds.Low — arithmetic and bookkeeping
mmap/mremap64-bitaddr + lenwrap corrupts mmap-cache bookkeeping —system_calls.cpp:415. Medium confidence.m_total_fds_openedisuint16_tand wraps at 65536 —fds.cpp:138,defeating the embedder's total-fd limit.
fcntl(F_DUPFD_CLOEXEC)hands an uncheckeddup()tomanage_duplicate()—system_calls.cpp:1890.translate()ignores KVM_TRANSLATE's valid bit —machine.cpp:370.Medium confidence; the only consequence found was a spurious
MemoryException.Low — no current caller
copy_from_cstring()over-reads up tooffsetbytes past each page end —machine_utils.cpp:617. Zero callers today.relocate_section()/relocate_relr_section()wrapped relocationaddresses, and
elf_offset_array()count overflow —machine_elf.cpp:425.Embedder-API-only;
dynamic_linking()has been a no-op since 864ad8d. Thisone was attempted in wave 2 and could not be reproduced.
close()returns early without setting registers whenfree_fd_callbackresets the VM —
system_calls.cpp:170. Borderline out of scope, since itneeds an embedder callback.
SignalReturn::framesunboundedly —signals.cpp:87. Low confidence, and needs an AArch64 host.Cosmetic, noted in passing
rt_sigactionoldacton a never-set handler returns0xFF…F0instead ofSIG_DFL—system_calls.cpp:608. Surfaced while reproducing thesignal-handler part of reset_to() does not restore signal handlers, cwd, brk or pipe2 flags (cross-request state leaks) #103.
is_writable_pathlacks the empty-path guard thatis_readable_pathhas —
fds.cpp:437vs:420. Relevant to unlinkat: path and flags read from swapped registers; policy checked on an empty path #96, where the policy layer iscurrently handed an empty path.
thread_countersigned-int overflow → tid reuse —threads.cpp:159.Needs ~2^31 clones; noted on No cap on guest thread creation (100k clones -> 429 MB host RSS) #105 since it is free to fix alongside the
thread cap.