Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions _security/CVE-2021-41556.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: CVE-2021-41556
description: Out-of-bounds read in Squirrel interpreter allows sandbox escape and remote code execution
first_vulnerable: 0.7.0
first_fixed: 13.2
related_bugs: []
related_commits:
- 89259af
patches:
- name: For version 0.7.0 up to including 13.1
file: 0.7.0 - 13.1.patch
---

A vulnerability in the Squirrel engine meant that a suitably crafted script could be used to escape the default "sandbox" and execute arbitrary code.
This has been published separately as CVE-2021-41556, to which OpenTTD is vulnerable as well as it uses a modified copy of the Squirrel engine for running AIs and Gamescripts.
Due to further restrictions in how OpenTTD uses Squirrel - notably that `rawset` was never implemented and the default memory limits are smaller than what is required - means that the vulnerability is much harder to exploit.

This issue was first fixed in nightlies prior to 14.0, backported and first released in 13.2.
The fix is a direct backport from the upstream Squirrel repository.
33 changes: 33 additions & 0 deletions _security/CVE-2021-41556/0.7.0 - 13.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
layout: security_patch
cve: CVE-2021-41556
first_version: 0.7.0
last_version: 13.1
---

diff --git a/src/3rdparty/squirrel/squirrel/sqclass.cpp b/src/3rdparty/squirrel/squirrel/sqclass.cpp
index 643685c9e6..eacb0a8c5a 100644
--- a/src/3rdparty/squirrel/squirrel/sqclass.cpp
+++ b/src/3rdparty/squirrel/squirrel/sqclass.cpp
@@ -65,6 +65,9 @@ bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr
_defaultvalues[_member_idx(temp)].val = val;
return true;
}
+ if (_members->CountUsed() >= MEMBER_MAX_COUNT) {
+ return false;
+ }
if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) {
SQInteger mmidx;
if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) &&
diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h
index 4fb6ecbd97..4da20e524f 100644
--- a/src/3rdparty/squirrel/squirrel/sqclass.h
+++ b/src/3rdparty/squirrel/squirrel/sqclass.h
@@ -18,6 +18,7 @@ typedef sqvector<SQClassMember> SQClassMemberVec;

#define MEMBER_TYPE_METHOD 0x01000000
#define MEMBER_TYPE_FIELD 0x02000000
+#define MEMBER_MAX_COUNT 0x00FFFFFF

#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD)
#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD)