1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
From 64613bc8b6b4adf1e32231f9844d99cd512b8973 Mon Sep 17 00:00:00 2001
From: Alexey Sokolov <alexey+znc@asokolov.org>
Date: Fri, 15 Mar 2019 20:34:10 +0000
Subject: [PATCH] Don't crash if user specified invalid encoding.
This is CVE-2019-9917
---
modules/controlpanel.cpp | 2 +-
src/IRCNetwork.cpp | 4 ++--
src/User.cpp | 4 ++--
src/znc.cpp | 26 ++++++++++++++++++++++----
test/integration/tests/scripting.cpp | 7 +++++++
5 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/modules/controlpanel.cpp b/modules/controlpanel.cpp
index 139c2aefa..109f8c6b0 100644
--- a/modules/controlpanel.cpp
+++ b/modules/controlpanel.cpp
@@ -495,7 +495,7 @@ class CAdminMod : public CModule {
#ifdef HAVE_ICU
else if (sVar == "clientencoding") {
pUser->SetClientEncoding(sValue);
- PutModule("ClientEncoding = " + sValue);
+ PutModule("ClientEncoding = " + pUser->GetClientEncoding());
}
#endif
else
diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp
index 0284dc53e..0e1d6e2a3 100644
--- a/src/IRCNetwork.cpp
+++ b/src/IRCNetwork.cpp
@@ -1482,9 +1482,9 @@ void CIRCNetwork::SetBindHost(const CString& s) {
}
void CIRCNetwork::SetEncoding(const CString& s) {
- m_sEncoding = s;
+ m_sEncoding = CZNC::Get().FixupEncoding(s);
if (GetIRCSock()) {
- GetIRCSock()->SetEncoding(s);
+ GetIRCSock()->SetEncoding(m_sEncoding);
}
}
diff --git a/src/User.cpp b/src/User.cpp
index 3fd532a7c..c44cf6070 100644
--- a/src/User.cpp
+++ b/src/User.cpp
@@ -1253,9 +1253,9 @@ void CUser::SetAdmin(bool b) { m_bAdmin = b; }
void CUser::SetDenySetBindHost(bool b) { m_bDenySetBindHost = b; }
void CUser::SetDefaultChanModes(const CString& s) { m_sDefaultChanModes = s; }
void CUser::SetClientEncoding(const CString& s) {
- m_sClientEncoding = s;
+ m_sClientEncoding = CZNC::Get().FixupEncoding(s);
for (CClient* pClient : GetAllClients()) {
- pClient->SetEncoding(s);
+ pClient->SetEncoding(m_sClientEncoding);
}
}
void CUser::SetQuitMsg(const CString& s) { m_sQuitMsg = s; }
diff --git a/src/znc.cpp b/src/znc.cpp
index 4e7216ee1..3f4dd2e07 100644
--- a/src/znc.cpp
+++ b/src/znc.cpp
@@ -2092,18 +2092,36 @@ void CZNC::ForceEncoding() {
m_uiForceEncoding++;
#ifdef HAVE_ICU
for (Csock* pSock : GetManager()) {
- if (pSock->GetEncoding().empty()) {
- pSock->SetEncoding("UTF-8");
- }
+ pSock->SetEncoding(FixupEncoding(pSock->GetEncoding()));
}
#endif
}
void CZNC::UnforceEncoding() { m_uiForceEncoding--; }
bool CZNC::IsForcingEncoding() const { return m_uiForceEncoding; }
CString CZNC::FixupEncoding(const CString& sEncoding) const {
- if (sEncoding.empty() && m_uiForceEncoding) {
+ if (!m_uiForceEncoding) {
+ return sEncoding;
+ }
+ if (sEncoding.empty()) {
+ return "UTF-8";
+ }
+ const char* sRealEncoding = sEncoding.c_str();
+ if (sEncoding[0] == '*' || sEncoding[0] == '^') {
+ sRealEncoding++;
+ }
+ if (!*sRealEncoding) {
return "UTF-8";
}
+#ifdef HAVE_ICU
+ UErrorCode e = U_ZERO_ERROR;
+ UConverter* cnv = ucnv_open(sRealEncoding, &e);
+ if (cnv) {
+ ucnv_close(cnv);
+ }
+ if (U_FAILURE(e)) {
+ return "UTF-8";
+ }
+#endif
return sEncoding;
}
diff --git a/test/integration/tests/scripting.cpp b/test/integration/tests/scripting.cpp
index 9dd68d8fa..8f809f50c 100644
--- a/test/integration/tests/scripting.cpp
+++ b/test/integration/tests/scripting.cpp
@@ -55,6 +55,13 @@ TEST_F(ZNCTest, Modpython) {
ircd.Write(":n!u@h PRIVMSG nick :Hi\xF0, github issue #1229");
// "replacement character"
client.ReadUntil("Hi\xEF\xBF\xBD, github issue");
+
+ // Non-existing encoding
+ client.Write("PRIVMSG *controlpanel :Set ClientEncoding $me Western");
+ client.Write("JOIN #a\342");
+ client.ReadUntil(
+ ":*controlpanel!znc@znc.in PRIVMSG nick :ClientEncoding = UTF-8");
+ ircd.ReadUntil("JOIN #a\xEF\xBF\xBD");
}
TEST_F(ZNCTest, ModpythonSocket) {
|