Skip to content

Commit

Permalink
[Net] Fix Marshalls infinite recursion crash.
Browse files Browse the repository at this point in the history
Variants like dictionaries and arrays can have cyclic references, which
caused `encode_variant` to run an infinite recursion.
Instead of keeping a stack and looking for cyclic references which would
make serialization slower, this commit adds a `MAX_RECURSION_DEPTH`
constant to Variant, and have `encode_variant` keep track of the current
recursion depth, bailing when it's too high since this likely means a
cyclic reference has been encountered.
  • Loading branch information
Faless committed Jul 30, 2021
1 parent e95e33f commit 3246364
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 9 deletions.
18 changes: 10 additions & 8 deletions core/io/marshalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,8 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
}
}

Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects) {
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects, int p_depth) {
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ERR_OUT_OF_MEMORY, "Potential inifite recursion detected. Bailing.");
uint8_t *buf = r_buffer;

r_len = 0;
Expand Down Expand Up @@ -1380,10 +1381,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
_encode_string(E.name, buf, r_len);

int len;
Error err = encode_variant(obj->get(E.name), buf, len, p_full_objects);
if (err) {
return err;
}
Error err = encode_variant(obj->get(E.name), buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
Expand Down Expand Up @@ -1433,15 +1432,17 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len++; //pad
*/
int len;
encode_variant(E, buf, len, p_full_objects);
Error err = encode_variant(E, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
buf += len;
}
Variant *v = d.getptr(E);
ERR_FAIL_COND_V(!v, ERR_BUG);
encode_variant(*v, buf, len, p_full_objects);
err = encode_variant(*v, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
Expand All @@ -1462,7 +1463,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo

for (int i = 0; i < v.size(); i++) {
int len;
encode_variant(v.get(i), buf, len, p_full_objects);
Error err = encode_variant(v.get(i), buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
Expand Down
2 changes: 1 addition & 1 deletion core/io/marshalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,6 @@ class EncodedObjectAsID : public RefCounted {
};

Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = nullptr, bool p_allow_objects = false);
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false);
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false, int p_depth = 0);

#endif // MARSHALLS_H
5 changes: 5 additions & 0 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ class Variant {
VARIANT_MAX
};

enum {
// Maximum recursion depth allowed when serializing variants.
MAX_RECURSION_DEPTH = 1024,
};

private:
friend struct _VariantCall;
friend class VariantInternal;
Expand Down

0 comments on commit 3246364

Please sign in to comment.