Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent cartridges hijacking keyboard events #1787

Merged
merged 2 commits into from
Jan 8, 2022

Conversation

joshgoebel
Copy link
Collaborator

@joshgoebel joshgoebel commented Jan 7, 2022

Resolves #1785.

This fix captures the current (input.ram.keyboard) state in
tick_start and immediately restores it in tick_end. This
prevents cartridges from injecting corrupt "previous" states
into the keyboard state engine that could be used to hijack
keyboard input.

When we trust input.ram.keyboard after user code has run
we open ourselves up to a cartridge:

  • repeating keyboard events by fake "lifting" a key
    (which is still held by the user, then registering as
    separate repeating keypress/releases until the user
    finally releases the key)
  • preventing key up events by fake "holding" a key
    (this prevents the state engine from ever seeing the
    key release).

Originally this was a lot larger, but I figured it was going to be too hard to review and certify with just a glance. This takes your "don't let someone modify KEYBOARD" idea and simplifies it to preserving rather than protecting. We preserve the "now" state during a tick and then restore it immediately afterwards, vs trusting whatever (potentially incorrect) state could be present in the RAM.

Since the real problem is making sure the integrity of KEYBOARD state is guaranteed for "system" bits, this does so by making sure that immediate after pre-tick the "now" state is restored, guaranteeing that:

  • historic keyboard state is never corrupted in the first place (fixing the bug)
  • KEYBOARD state is guaranteed to be accurate immediately pre-tick because we haven't run any user code yet that could alter it

I hope this is clear. If you have any questions, ask.


I'm still open to doing a larger refactor here, but I thought this was pretty clean. The only gotcha is that code like handleShortcuts() must be run before the user code, and I've added a comment to that effect:

  • pretick
  • Studio handles keystrokes (KEYBOARD is guaranteed correct here)
  • tick (user code)
  • post tick

Resolves nesbox#1785.

This fix captures the current (`input.ram.keyboard`) state in
`tick_start` and immediately restores it in `tick_end`. This
prevents cartridges from injecting corrupt "previous" states
into the keyboard state engine that could be used to hijack
keyboard input.

When we trust `input.ram.keyboard` after user code has run
we open ourselves up to a cartridge:

- repeating keyboard events by fake "lifting" a key
  (which is still held by the user, then registering as
  separate repeating keypress/releases until the user
  finally releases the key)
- preventing key up events by fake "holding" a key
  (this prevents the state engine from ever seeing the
  key release).
@@ -108,6 +108,7 @@ typedef struct
struct
{
tic80_keyboard previous;
tic80_keyboard now;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized we should do the same for the tic80_gamepads previous; data

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think the gamepad could be used for studio control/input, so it's not a security risk, but it's easy enough to add to this PR if you like. I'll do it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gamepad used in Surf and Game Menu, so you also can hack them :)
Pls add the same for the gamepad too.
Thanks.

@joshgoebel
Copy link
Collaborator Author

You'll have to test, I don't have gamepads. But patch is simply enough.

Copy link
Owner

@nesbox nesbox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@nesbox nesbox merged commit eb27168 into nesbox:master Jan 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hacking KEYBOARD registers in "RAM" can affect input the IDE sees
2 participants