Friday, December 5, 2008

Thoughts on Cvar control, safety and protection

I wrote this over on Inside3D:

It's unlikely, but you never really know when a mod is going to use one of those cvars in an unexpected manner. I mean stuff like "my mod only works on GLQuake, I need a spare cvar to stuff a setting into, so - hey! - I'll use vid_mode". Party like it's 1996.
While I was at least half joking at the time, a bit later I got to thinking about it, and realised that yes, it is a fairly serious hole in the engine. User settings do belong to the user after all, and while I would certainly hope that most mods would be reasonably behaved and respect that, the lack of control that's currently present means that misbehaving code, or a rogue mod (or even a Hipnotic one ;) ), could wreak all manner of havoc.

At the same time, that perspective has to be balanced with mods that genuinely do modify user settings for honest and above-board purposes, that use that modification for something cool, and that go about it in a reasonable and well-behaved manner.

So I'm going to implement a solution that accomplishes the following purposes:
  • User settings are protected from modification by mods.
  • Users are warned when a mod attempts to modify a user setting.
  • Users have the option to allow this to happen or not.
  • The option can be toggled on and off.
  • Mods have no control over the toggling of this option - it's entirely at the user's discretion.
This is going to be achieved as follows:

Cvar Protection
Every cvar can have a "USAGE_PROTECTED" flag set at initialization. If a cvar doesn't have this flag, QC is free to party on it. If a cvar does have the flag set, we go over to the next stage, which is...

Cvar Value Shadowing
As well as their normal value, cvars will also have a "shadow" value. If a cvar is protected, all reads and writes by QC use the "shadow" value; the normal value is therefore sacrosanct and can only be read or written by the engine. Reads by the engine never use the shadow value, writes by the engine write to both the normal and shadow value; therefore a misbehaving mod can always be overruled by what the engine thinks is right (and what the user thinks is right), and what a mod writes to a cvar will never affect how the engine works (or how the user wants it to work). This should cover all cases where QC wants to use a cvar for it's own internal purposes, but what if QC wants to actually modify a user setting?

Protection Overriding
The user can choose to protect or unprotect cvars. Setting "cl_cvarprotect 1" (the default) will use the protected mode; setting "cl_cvarprotect 0" will revert to the default Q1 behaviour - all cvars are fair game. This is an "all or nothing" setting; I had thought about using commands to protect or unprotect individual cvars, but decided in the end that most people will just want either the new way or the old way. Nothing to stop misbehaving QC from issuing these commands and making the whole exercise meaningless, anyway. QC can never write to this cvar; it's doubly-protected, if you like. Behaviour is entirely at the choice of the user, and the user alone.

User Notification
If QC attempts to write to a protected cvar, the user will be notified, and will be informed of what to do. Something like "Allow always", "allow this time" or "allow never", with an appropriate warning that allowing it may cause consequences, some of which may be unpleasant. Yes, it's Vista's UAC in Quake, and yes, it's for the same reason - handing control over things that could damage their system back to the user.

0 comments: