openvmm: PIT restore accepts RW=0 and subsequent counter I/O can panic

Open Beginner friendly
#1,147 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
62/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
rust
Domain
backend

Research direction

Start in vm/devices/chipset/src/pit/mod.rs at PitDevice::restore, where the saved control byte becomes ControlWord in TimerState, then look at the counter I/O paths that hit the unreachable! access-mode branch. Add a check that rejects RW=0 with InvalidSavedState while keeping LOW, HIGH and LOW_HIGH valid. Done when a restore with bits 4-5 cleared returns an error and a test covers it.

Written by the indexing model from the issue text.

Description

A modified snapshot can restore a PIT timer with RW=0 in its control word. Restore succeeds, but the guest's next counter read or write can reach an unreachable! access-mode branch and panic the VM worker.

In vm/devices/chipset/src/pit/mod.rs, PitDevice::restore decodes the saved control byte directly into TimerState without validating its access mode:

                    out,
                    control: ControlWord::from(control), // no unused bits
                    gate,
                    null,
                    read_high,

RW occupies bits 4–5. Zero encodes a counter-latch command, not a programmed counter's access mode. Ordinary guest control writes handle that command by latching the count without storing it, so counter I/O assumes the stored mode is LOW, HIGH or LOW_HIGH. Restoring an unchecked byte bypasses that invariant.

Reproduction

Capture PIT state, clear bits 4–5 of any channel's saved control byte, then restore it. Access the corresponding counter port: 0x40, 0x41 or 0x42.

The restore accepts RW=0 instead of returning InvalidSavedState, leaving the invalid mode for the subsequent guest access. This state requires a modified saved-state payload; normal PIT programming cannot persist the latch-command encoding.

Fix

fix.patch decodes and checks the control word before assigning it to the timer. It rejects RW=0 with InvalidSavedState and retains the three valid access modes, preventing saved-state input from installing a counter mode that the I/O paths cannot handle.

Dominant language
Rust
Stars
758
Forks
48
Avg merge
17h 16m
Merged PRs (30d)
450

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/nvx

All issues in microsoft/nvx

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.