-
-
Notifications
You must be signed in to change notification settings - Fork 523
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
Safer auto-download handling, for maps but not code (#130) #274
base: main
Are you sure you want to change the base?
Conversation
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.
Why not check localName length before possible truncation in Com_sprintf()?
Also, you can do than once for all files in CL_InitDownloads() not waiting for a pak with long name in the tail
Because then I'd have to calculate how long it was going to end up (or equivalently, how long a buffer it would need to avoid truncation) and if I got that calculation wrong, we'd be back where we started. I'm aiming to make it as obvious as possible when security-sensitive things are correct.
Up to a point, but that requires knowing in one location in the code how large a buffer at another location is going to be. The further apart these checks are, the less obvious it will be whether they're correct. |
Q_strncpyz doesn't allow checking for truncation, hence using Com_sprintf(..., "%s", ...) as its equivalent. Signed-off-by: Simon McVittie <smcv@debian.org>
They are now only searched if a server uses them, and their expected checksums are included in the filename (the same as the fallback filename that was previously used if a collision was detected). Advanced users can copy them from downloads/ into their expected places. The filename ends with ".noexec.pk3" so that we can detect which files were auto-downloaded, even if they are moved into place. Adding "downloads/", the checksum and ".noexec" makes the lists of files somewhat larger, so expand the buffers they're written into to compensate. Signed-off-by: Simon McVittie <smcv@debian.org>
This prevents a server we connected to from continuing to influence engine behaviour after disconnection. Signed-off-by: Simon McVittie <smcv@debian.org>
This includes both files we auto-downloaded recently (in downloads/) and files that the user moved from the downloads/ directory to the appropriate mod directory. Signed-off-by: Simon McVittie <smcv@debian.org>
Branch updated to use the return value of |
There is a small issue with your implementation: pk3s in the download folder are only added in the search path if the server explicitly names them. If the client is the server (singleplayer) then those downloaded pk3 will never be loaded. This creates a strange situation where one can, say, connect to a server having a map X but can't play it locally with /map X This also has the side effect of restricting the (download) search path to only the pk3s referenced by the server (as opposed to those that are shared between client and server but not necessarily referenced, which would be the normal behavior). Now that could be considered a good thing (some mappers just love to override textures/sounds from other maps which can be quite annoying because a map can render differently from one server to another) , but IMHO this should be an option, not default behavior. |
This is deliberate, see the comments from @sago007 and @zturtleman on #130. It's a trade-off. If auto-downloaded pk3s are automatically made active for single-player (or a locally-hosted server) like they are now (and like you want), then a map or mod that you auto-downloaded from a server is immediately playable, which is good; but the same server can also (for instance) replace your
I believe the behaviour is: On a "pure server", which is the default, the search path is always restricted to the pk3s that the server told you to load, in the priority order that the server told you to load them. This hasn't changed. On an "impure" server, pk3s referenced by the server (in the order specified by the server) are highest priority. If a desired file isn't found in any of those, then the same pk3s that would be loaded in single player (and in the same order) are also searched, as a lower priority (because they were already in the search path before we prepended the auto-downloaded pk3s). In particular, if you are on an impure server and a player in the multiplayer game (you or someone else) has selected a custom model or skin that would have been available to you in single-player, you'll also see it in multiplayer. Is there a concrete situation where this implementation would load content that differs from what the current code would load, other than it not loading content from pk3s that were auto-downloaded from a previous server but are not referenced by the current server? |
I think it is relevant to point out that my filesystem project does achieve the behavior you are looking for without the downsides of letting downloaded pk3s override anything. Files in the download folder are always loaded and available to use (except for qvm and cfg files), but this check prioritizes them below everything else, and effectively stops them from breaking anything that otherwise works. It also works on a per-shader level, rather than per shader file, so you don't have to worry about special shader precedence issues.
This definitely has the potential to be disruptive. Referenced paks have historically only been used for downloads, so servers have a lot of flexibility in how it is used. If my understanding is correct, servers will now have problems with clients using paks downloaded from other servers if
None of these things would have mattered before, so it is a lot of potential headaches for both server admins and players. Pure servers may partially mitigate some of these issues, but only around half of servers are pure anyway, so you can't depend on that.
Probably the shader precedence; for example there will be cases where a pk3 in the download folder will now override the ID pak shaders when it wouldn't before. This would be considerably less common as a practical problem than the other reference-list related issues, however. |
@Chomenor: please do not jump into unrelated threads to announce your project. We know about it. |
@timedoctor Only my first paragraph was about my project, and it was about an aspect of my project I had neglected to document previously, so that is why I though it was worth mentioning. It wasn't my intention to spam, but I'll try to be more careful in the future. |
To be clear, I don't much care about any specific implementation: I just want something that the ioquake3 maintainers are willing to merge, and that has the result that a malicious server is unable to cause arbitrary code execution on its clients. If someone else's implementation meets those criteria, great.
The reference (ioquake3) server sends checksums and names in most-important-first order, so the current implementation in this PR is not correct even if the server is assumed to send the same order that ioquake3 would: it iterates that list forwards, and prepends each auto-downloaded pk3 to the client's search path, resulting in the least important auto-downloaded file coming first. Of course, this only matters if there is more than one auto-downloaded pk3, or if there is an auto-downloaded pk3 that is less important than a pk3 that is on the normal search path (available to single-player games). If auto-downloaded PK3s were inserted into the search path in sorted order, instead of always being prepended, I think that would resolve this: so for instance |
That doesn't quite work, because all PK3s from a higher-precedence directory beat all PK3s from a lower-precedence directory, regardless of alphabetical order (if we're playing Team Arena, |
Until you provide some reliable and automatic update system - all this stuff looks like shooting to the one remaining leg |
I agree with @Chomenor here, this is easily solved by putting the downloaded pk3s at a lower priority in the search list by default. Then the map is playable but won't override anything. Connecting to pure servers works as before. And unpure just as you described except that it would also look for other locally downloaded content (not on the server) instead of just the one referenced by the server. |
@timedoctor, @zturtleman, other ioquake3 maintainers: What search-path order would you prefer for auto-downloaded mods on impure servers? And would you prefer auto-downloads to be active after disconnecting from the server that used them (like vanilla Quake 3, so players can receive mods while joining a server and easily keep them afterwards), or not (like Unreal Tournament '99, so players can rely on joining a server not permanently changing textures or behaviour after disconnecting)? When I have answers to those two questions I'll update this PR to follow them. Non-maintainers can try to persuade the maintainers that a particular answer to one of those questions is best, but I'm not going to try to keep everyone happy by producing multiple variations of this branch, because there are multiple contradictory views; so when the maintainers make a decision, I'm going to treat it as final. I would be inclined to give more weight to the opinions of maintainers of widely used ioquake3 forks, like @sago007 (OpenArena) and @ensiform (OpenJK), who both commented on #130, because if widely used forks don't pick this up then I won't have achieved my goal of making the idtech3-based ecosystem more secure. For reference, the current search-path order for a mod (let's say Team Arena,
where PK3 files in I think the reasonable options for sort order are:
At the moment this branch promotes auto-downloads to be more important than non-auto-downloads, in the reverse of the order given by the remote server (least important remote file is most important on the client), but that's clearly wrong and needs fixing. I'll correct it when I know what I'm aiming for. |
As proposed on #130, this branch separates auto-downloaded and non-auto-downloaded PK3s, and does not allow loading executable code from auto-downloaded PK3s. This lets the auto-download mechanism be used for maps and textures without needing to have absolute trust in the server admin (and everyone on the network between you and them).
Auto-downloaded PK3s get a marker in the filename (
.noexec.
) which keeps them non-executable even if they are dragged into a directory that is on the search path, so that users can make an auto-downloaded map permanently available without privilege escalation.See #130 for background information, and further details of some of the choices made in designing this branch.