@@ -124,24 +124,29 @@ static int validate_utf8_char(const uint8_t *untrusted_c) {
124
124
// is set to zero, and the number of non-".." components is incremented.
125
125
//
126
126
// The return value is the number of non-".." components on
127
- // success, or 0 on failure.
128
- static size_t validate_path (const uint8_t * const untrusted_name , size_t allowed_leading_dotdot )
127
+ // success, or -1 on failure.
128
+ static ssize_t validate_path (const uint8_t * const untrusted_name , size_t allowed_leading_dotdot )
129
129
{
130
- size_t non_dotdot_components = 0 , i = 0 ;
130
+ // We assume that there are not SSIZE_MAX path components.
131
+ // This cannot happen on hardware using a flat address space,
132
+ // as this would require SIZE_MAX bytes in the path and leave
133
+ // no space for the executable code.
134
+ ssize_t non_dotdot_components = 0 ;
135
+ size_t i = 0 ;
131
136
do {
132
137
if (i == 0 || untrusted_name [i - 1 ] == '/' ) {
133
138
switch (untrusted_name [i ]) {
134
139
case '/' : // repeated or initial slash
135
140
case '\0' : // trailing slash or empty string
136
- return 0 ;
141
+ return -1 ;
137
142
case '.' :
138
143
if (untrusted_name [i + 1 ] == '\0' || untrusted_name [i + 1 ] == '/' )
139
- return 0 ;
144
+ return -1 ;
140
145
if ((untrusted_name [i + 1 ] == '.' ) &&
141
146
(untrusted_name [i + 2 ] == '\0' || untrusted_name [i + 2 ] == '/' )) {
142
147
/* Check if the limit on leading ".." components has been exceeded */
143
148
if (allowed_leading_dotdot < 1 )
144
- return 0 ;
149
+ return -1 ;
145
150
allowed_leading_dotdot -- ;
146
151
i += 2 ; // advance past ".."
147
152
continue ;
@@ -160,7 +165,7 @@ static size_t validate_path(const uint8_t *const untrusted_name, size_t allowed_
160
165
if (utf8_ret > 0 ) {
161
166
i += utf8_ret ;
162
167
} else {
163
- return 0 ;
168
+ return -1 ;
164
169
}
165
170
}
166
171
} while (untrusted_name [i ]);
@@ -177,7 +182,7 @@ QUBES_PURE_PUBLIC bool
177
182
qubes_pure_validate_symbolic_link (const uint8_t * untrusted_name ,
178
183
const uint8_t * untrusted_target )
179
184
{
180
- size_t depth = validate_path (untrusted_name , 0 );
185
+ ssize_t depth = validate_path (untrusted_name , 0 );
181
186
// Symlink paths must have at least 2 components: "a/b" is okay
182
187
// but "a" is not. This ensures that the toplevel "a" entry
183
188
// is not a symbolic link.
@@ -190,7 +195,7 @@ qubes_pure_validate_symbolic_link(const uint8_t *untrusted_name,
190
195
// (which resolves to "a/d") but not "../../d" (which resolves to "d").
191
196
// This ensures that ~/QubesIncoming/QUBENAME/a/b cannot point outside
192
197
// of ~/QubesIncoming/QUBENAME/a.
193
- return validate_path (untrusted_target , depth - 2 ) > 0 ;
198
+ return validate_path (untrusted_target , ( size_t )( depth - 2 )) >= 0 ;
194
199
}
195
200
196
201
QUBES_PURE_PUBLIC bool
0 commit comments