-
-
Notifications
You must be signed in to change notification settings - Fork 489
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
Conversation
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
You'll have to test, I don't have gamepads. But patch is simply enough. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you
Resolves #1785.
This fix captures the current (
input.ram.keyboard
) state intick_start
and immediately restores it intick_end
. Thisprevents 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 runwe open ourselves up to a cartridge:
(which is still held by the user, then registering as
separate repeating keypress/releases until the user
finally releases the 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: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: