Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
kgsws

Code Execution in source ports.

Recommended Posts

Cheers for sharing.

 

My understanding is that GZDoom has something resembling a responsible disclosure policy - which is to say that Zombie found some stuff and reported it privately, and it was disclosed after an official release fixing it was put out - but I'm not sure what the exact protocol for reporting such things is is beyond figuring out the correct person to DM and the right platform to DM them on (Discord? Github? ZDF? Fuckin' smoke signals?!?)

Share this post


Link to post

I'm gonna sneak in and say "don't change signed to unsigned integers". All the data has been cooked with signed, so all you'll be doing is allocating huge chunks of data for stuff that is either broken or malicious and then get random out of memory errors. Capture them with <0 checks and error message appropriately (especially when it comes to allocations).

Share this post


Link to post
Posted (edited)

Interesting, thanks for compiling the list. I particularly like the one with P_SpawnMapThing as it only requires the player playing the map (if I understood correctly).

 

Not too long ago when I was mapping in vanilla, using action 37 (W1 floor lower to lowest floor (change texture)), I noticed it had a problem if the lowering sector had too many linedefs. This is known, yes, but my question is just whether it has been investigated as a possible way to cause code execution?

Share this post


Link to post
15 hours ago, Kinsie said:

Cheers for sharing.

 

My understanding is that GZDoom has something resembling a responsible disclosure policy - which is to say that Zombie found some stuff and reported it privately, and it was disclosed after an official release fixing it was put out - but I'm not sure what the exact protocol for reporting such things is is beyond figuring out the correct person to DM and the right platform to DM them on (Discord? Github? ZDF? Fuckin' smoke signals?!?)

You can PM the entire developer group on ZDF, and that's what has been used a few times.

Share this post


Link to post
11 hours ago, GooberMan said:

I'm gonna sneak in and say "don't change signed to unsigned integers". All the data has been cooked with signed, so all you'll be doing is allocating huge chunks of data for stuff that is either broken or malicious and then get random out of memory errors. Capture them with <0 checks and error message appropriately (especially when it comes to allocations).

Well, places i have mentioned should be safe to change into unsigned. No existing and valid data should contain negative values on places i have mentioned.

Plus, some overflow bugs are true even for too high signed values.

 

2 hours ago, slowfade said:

Interesting, thanks for compiling the list. I particularly like the one with P_SpawnMapThing as it only requires the player playing the map (if I understood correctly).

Well, Z_Malloc combined with signed values with various negative values in texture data leads to code execution when you load the WAD. Even before graphics mode starts.

That's what ACE Engine uses.

 

2 hours ago, slowfade said:

Not too long ago when I was mapping in vanilla, using action 37 (W1 floor lower to lowest floor (change texture)), I noticed it had a problem if the lowering sector had too many linedefs. This is known, yes, but my question is just whether it has been investigated as a possible way to cause code execution?

Actually there are overflow bugs like that, yeah. I should add those.

Share this post


Link to post

I kind of shudder to think what could've happened if these exploits had been found at the time when people just downloaded wads and ran them natively in the original Doom exes.

Share this post


Link to post
43 minutes ago, slowfade said:

I kind of shudder to think what could've happened if these exploits had been found at the time when people just downloaded wads and ran them natively in the original Doom exes.

I think it'd have forced id software to release a patch that fixed known exploits (perhaps repeatedly, as more exploits got discovered) and it probably would have resulted in a few more complevels to handle for demo playback.

Share this post


Link to post
Posted (edited)
1 hour ago, kgsws said:

Well, places i have mentioned should be safe to change into unsigned. No existing and valid data should contain negative values on places i have mentioned.

 

So let's take a texture with width and height of -1 each. Cast to unsigned, that's 65535x65535 texels if it's a compositable texture. Which is 4294836225. Which is just shy of 4 gigabytes. Best you can do with signed values is 1 gigabyte.

 

Being able to fill memory with a valid range is an entirely different thing. Don't reinterpret data to however you see fit just because it can break another way.

 

(I'm pretty strict on these points, since these kinds of assumptions are basically game security 101 - and especially since there's three decades worth of tools in this community that work with signed values.)

Share this post


Link to post
1 minute ago, GooberMan said:

So let's take a texture with width and height of -1 each. Cast to unsigned, that's 65535x65535 texels if it's a compositable texture. Which is 4294836225. Which is just shy of 4 gigabytes. Best you can do with signed values is 1 gigabyte.

With fixed Z_Malloc, allocating this much memory would simply fail.

 

3 minutes ago, GooberMan said:

Don't reinterpret data to however you see fit just because it can break another way.

My point is that when doom was coded, they clearly did not care about signed vs unsigned values. There are no assumptions about negative vs positive values. Therefore, keeping signed values vs using unsigned values does not really matter if you don't also add other checks. Both cases are broken in some way.

(except in a few places where they use negative values to convey special meaning)

 

Anyway, if you want to fix width / height / patch range properly, you should also check for some kind of top limit. You could also check, as you have mentioned, for negative values.

I'm gonna mention "negative check" in my original post.

Share this post


Link to post

Most level values are already extended to unsigned in advanced ports anyways because this is how we support larger levels. You can't have a negative sector or sidedef offset in Eternity in a binary map because those values are treated as unsigned anyways. So the debate over whether to extend or not is moot in those points for most implementations at this point. Otherwise, I'd also argue that you can always also add a sanity check for excessive size, whether or not the values are signed or unsigned. What valid use case do community tools have for negatively sized images for example? Either you're going to do if(w <= 0 || h <= 0) invalid; or you're going to do if(w * h > SANITY_THRESHOLD) invalid; - I see no difference except the latter lets you support reasonably larger images and the former does not.

Share this post


Link to post
1 hour ago, kgsws said:

With fixed Z_Malloc, allocating this much memory would simply fail

 

No it wouldn't. Rum and Raisin's Z_Malloc wraps in to malloc/dlmalloc. It would keep allocating 4 gigabytes and slow the system down as you hit physical RAM limit and start swapping virtual memory.

Share this post


Link to post
Posted (edited)
23 minutes ago, Quasar said:

Most level values are already extended to unsigned in advanced ports anyways because this is how we support larger levels.

Yes, and you need to special case things with heuristics to handle it.

Finding security holes is one thing. Taking an approach that creates more problems is another.

Share this post


Link to post
51 minutes ago, GooberMan said:

No it wouldn't. Rum and Raisin's Z_Malloc wraps in to malloc/dlmalloc. It would keep allocating 4 gigabytes and slow the system down as you hit physical RAM limit and start swapping virtual memory.

OK, for custom implementations it would not. Either way, code execution path is gone.

 

47 minutes ago, GooberMan said:

Yes, and you need to special case things with heuristics to handle it.

That's one way to do this. I would use one structure with unsigned values and do something like this for old maps when parsing:

if(vanilla_format && loadsubsec->firstseg >= numsegs)
	I_Error("Invalid subsector!")

Because, technically, this check should be done anyway at some point. You would have to count segs first, of course.

 

52 minutes ago, GooberMan said:

Finding security holes is one thing. Taking an approach that creates more problems is another.

Of course range checking everywhere is better.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×