Audacity  3.0.3
XMLTagHandler.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  XMLTagHandler.cpp
6 
7  Dominic Mazzoni
8  Vaughan Johnson
9 
10 
11 *//****************************************************************//*******************************************************************/
23 
24 #include "XMLTagHandler.h"
25 
26 #ifdef _WIN32
27  #include <windows.h>
28  #include <wx/msw/winundef.h>
29 #endif
30 
31 #include <wx/defs.h>
32 #include <wx/arrstr.h>
33 #include <wx/filename.h>
34 
35 #include "FileNames.h"
36 
37 // Length check. Is in part about not supplying malicious strings to file functions.
38 bool XMLValueChecker::IsGoodString(const wxString & str)
39 {
40  // Originally based on MAX_PATH, which is way too limiting and just wrong since
41  // the length check is for a plain string and not a filename
42  if (IsGoodLongString(str) && str.length() <= 4096) // Shouldn't be any reason for longer strings, except intentional file corruption.
43  {
44  return true;
45  }
46 
47  return false;
48 }
49 
50 // No length check, as e.g. labels could be very long.
51 bool XMLValueChecker::IsGoodLongString(const wxString & str)
52 {
53  return str.Find('\0', false) == wxNOT_FOUND; // No null characters except terminator.
54 }
55 
56 
57 // "Good" means the name is well-formed and names an existing file or folder.
58 bool XMLValueChecker::IsGoodFileName(const FilePath & strFileName, const FilePath & strDirName /* = "{} */)
59 {
60  // Test strFileName.
61  if (!IsGoodFileString(strFileName) ||
62  (strDirName.length() + 1 + strFileName.length() > PLATFORM_MAX_PATH))
63  return false;
64 
65  // Test the corresponding wxFileName.
66  wxFileName fileName(strDirName, strFileName);
67  return (fileName.IsOk() && fileName.FileExists());
68 }
69 
71 {
72  return (IsGoodString(str) &&
73  !str.empty() &&
74 
75  // FILENAME_MAX is 260 in MSVC, but inconsistent across platforms,
76  // sometimes huge, but we use 260 for all platforms.
77  (str.length() <= 260) &&
78 
79  (str.Find(wxFileName::GetPathSeparator()) == -1)); // No path separator characters.
80 }
81 
82 bool XMLValueChecker::IsGoodSubdirName(const FilePath & strSubdirName, const FilePath & strDirName /* = {} */)
83 {
84  // Test strSubdirName.
85  // Note this prevents path separators, and relative path to parents (strDirName),
86  // so fixes vulnerability #3 in the NGS report for UmixIt,
87  // where an attacker could craft an AUP file with relative pathnames to get to system files, for example.
88  if (!IsGoodFileString(strSubdirName) ||
89  (strSubdirName == wxT(".")) || (strSubdirName == wxT("..")) ||
90  (strDirName.length() + 1 + strSubdirName.length() > PLATFORM_MAX_PATH))
91  return false;
92 
93  // Test the corresponding wxFileName.
94  wxFileName fileName(strDirName, strSubdirName);
95  return (fileName.IsOk() && fileName.DirExists());
96 }
97 
98 bool XMLValueChecker::IsGoodPathName(const FilePath & strPathName)
99 {
100  // Test the corresponding wxFileName.
101  wxFileName fileName(strPathName);
102  return XMLValueChecker::IsGoodFileName(fileName.GetFullName(), fileName.GetPath(wxPATH_GET_VOLUME));
103 }
104 
106 {
107  return (IsGoodString(str) &&
108  !str.empty() &&
109  (str.length() <= PLATFORM_MAX_PATH));
110 }
111 
112 
113 bool XMLValueChecker::IsGoodIntForRange(const wxString & strInt, const wxString & strMAXABS)
114 {
115  if (!IsGoodString(strInt))
116  return false;
117 
118  // Check that the value won't overflow.
119  // Must lie between -Range and +Range-1
120  // We're strict about disallowing spaces and commas, and requiring minus sign to be first
121  // char for negative. No + sign for positive numbers. It's disallowed, not optional.
122 
123  const size_t lenMAXABS = strMAXABS.length();
124  const size_t lenStrInt = strInt.length();
125 
126  if( lenStrInt < 1 )
127  return false;
128  size_t offset = (strInt[0] == '-') ?1:0;
129  if( lenStrInt <= offset )
130  return false;// string too short, no digits in it.
131 
132  if (lenStrInt > (lenMAXABS + offset))
133  return false;
134 
135  unsigned int i;
136  for (i = offset; i < lenStrInt; i++)
137  if (strInt[i] < '0' || strInt[i] > '9' )
138  return false; // not a digit
139 
140  // All chars were digits.
141  if( lenStrInt < (lenMAXABS + offset) )
142  return true; // too few digits to overflow.
143 
144  // Numerical part is same length as strMAXABS
145  for (i = 0; i < lenMAXABS; i++)
146  if (strInt[i+offset] < strMAXABS[i])
147  return true; // number is small enough
148  else if (strInt[i+offset] > strMAXABS[i])
149  return false; // number is too big.
150 
151  // Digits were textually equal to strMAXABS
152  // That's OK if negative, but not OK if positive.
153  return (strInt[0] == '-');
154 }
155 
156 
157 bool XMLValueChecker::IsGoodInt(const wxString & strInt)
158 {
159  // Signed long: -2,147,483,648 to +2,147,483,647, i.e., -2^31 to 2^31-1
160  return IsGoodIntForRange( strInt, "2147483648" );
161 }
162 
163 bool XMLValueChecker::IsGoodInt64(const wxString & strInt)
164 {
165  // Signed 64-bit: -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807, i.e., -2^63 to 2^63-1
166  return IsGoodIntForRange( strInt, "9223372036854775808" );
167 }
168 
169 bool XMLTagHandler::ReadXMLTag(const char *tag, const char **attrs)
170 {
171  wxArrayString tmp_attrs;
172 
173  while (*attrs) {
174  const char *s = *attrs++;
175  tmp_attrs.push_back(UTF8CTOWX(s));
176  }
177 
178 // JKC: Previously the next line was:
179 // const char **out_attrs = NEW char (const char *)[tmp_attrs.size()+1];
180 // however MSVC doesn't like the constness in this position, so this is now
181 // added by a cast after creating the array of pointers-to-non-const chars.
182  auto out_attrs = std::make_unique<const wxChar *[]>(tmp_attrs.size() + 1);
183  for (size_t i=0; i<tmp_attrs.size(); i++) {
184  out_attrs[i] = tmp_attrs[i];
185  }
186  out_attrs[tmp_attrs.size()] = 0;
187 
188  bool result = HandleXMLTag(UTF8CTOWX(tag), out_attrs.get());
189 
190  return result;
191 }
192 
193 void XMLTagHandler::ReadXMLEndTag(const char *tag)
194 {
196 }
197 
198 void XMLTagHandler::ReadXMLContent(const char *s, int len)
199 {
200  HandleXMLContent(wxString(s, wxConvUTF8, len));
201 }
202 
204 {
205  return HandleXMLChild(UTF8CTOWX(tag));
206 }
XMLValueChecker::IsGoodInt
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
Definition: XMLTagHandler.cpp:157
XMLValueChecker::IsGoodPathName
static bool IsGoodPathName(const FilePath &strPathName)
Definition: XMLTagHandler.cpp:98
XMLTagHandler::HandleXMLEndTag
virtual void HandleXMLEndTag(const wxChar *WXUNUSED(tag))
Definition: XMLTagHandler.h:79
XMLValueChecker::IsGoodInt64
static bool IsGoodInt64(const wxString &strInt)
Check that the supplied string can be converted to a 64bit integer.
Definition: XMLTagHandler.cpp:163
XMLTagHandler::ReadXMLChild
XMLTagHandler * ReadXMLChild(const char *tag)
Definition: XMLTagHandler.cpp:203
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:38
XMLTagHandler.h
FilePath
wxString FilePath
Definition: Project.h:20
XMLTagHandler::HandleXMLContent
virtual void HandleXMLContent(const wxString &WXUNUSED(content))
Definition: XMLTagHandler.h:84
XMLTagHandler::ReadXMLTag
bool ReadXMLTag(const char *tag, const char **attrs)
Definition: XMLTagHandler.cpp:169
UTF8CTOWX
#define UTF8CTOWX(X)
Definition: Internat.h:159
XMLValueChecker::IsGoodFileName
static bool IsGoodFileName(const FilePath &strFileName, const FilePath &strDirName={})
Definition: XMLTagHandler.cpp:58
XMLValueChecker::IsGoodFileString
static bool IsGoodFileString(const FilePath &str)
Definition: XMLTagHandler.cpp:70
XMLTagHandler
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:62
XMLValueChecker::IsGoodSubdirName
static bool IsGoodSubdirName(const FilePath &strSubdirName, const FilePath &strDirName={})
Definition: XMLTagHandler.cpp:82
XMLValueChecker::IsGoodLongString
static bool IsGoodLongString(const wxString &str)
Definition: XMLTagHandler.cpp:51
FileNames.h
PLATFORM_MAX_PATH
#define PLATFORM_MAX_PATH
Definition: FileNames.h:22
XMLTagHandler::HandleXMLTag
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs)=0
XMLTagHandler::HandleXMLChild
virtual XMLTagHandler * HandleXMLChild(const wxChar *tag)=0
XMLTagHandler::ReadXMLEndTag
void ReadXMLEndTag(const char *tag)
Definition: XMLTagHandler.cpp:193
XMLValueChecker::IsGoodPathString
static bool IsGoodPathString(const FilePath &str)
Definition: XMLTagHandler.cpp:105
XMLValueChecker::IsGoodIntForRange
static bool IsGoodIntForRange(const wxString &strInt, const wxString &strMAXABS)
Definition: XMLTagHandler.cpp:113
XMLTagHandler::ReadXMLContent
void ReadXMLContent(const char *s, int len)
Definition: XMLTagHandler.cpp:198