Skip to content

Commit 9d48f9e

Browse files
committed
swisspol#57 Validate paths passed to GCDWebDAVServer and GCDWebUploader to ensure they are within the upload directory
1 parent 7c6e85c commit 9d48f9e

2 files changed

Lines changed: 35 additions & 16 deletions

File tree

GCDWebDAVServer/GCDWebDAVServer.m

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ @interface GCDWebDAVServer () {
6161

6262
@implementation GCDWebDAVServer (Methods)
6363

64+
// Must match implementation in GCDWebUploader
65+
- (BOOL)_checkSandboxedPath:(NSString*)path {
66+
return [[path stringByStandardizingPath] hasPrefix:_uploadDirectory];
67+
}
68+
6469
- (BOOL)_checkFileExtension:(NSString*)fileName {
6570
if (_allowedExtensions && ![_allowedExtensions containsObject:[[fileName pathExtension] lowercaseString]]) {
6671
return NO;
@@ -87,7 +92,7 @@ - (GCDWebServerResponse*)performGET:(GCDWebServerRequest*)request {
8792
NSString* relativePath = request.path;
8893
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
8994
BOOL isDirectory = NO;
90-
if (![absolutePath hasPrefix:_uploadDirectory] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
95+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
9196
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
9297
}
9398

@@ -116,7 +121,7 @@ - (GCDWebServerResponse*)performPUT:(GCDWebServerFileRequest*)request {
116121

117122
NSString* relativePath = request.path;
118123
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
119-
if (![absolutePath hasPrefix:_uploadDirectory]) {
124+
if (![self _checkSandboxedPath:absolutePath]) {
120125
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
121126
}
122127
BOOL isDirectory;
@@ -161,7 +166,7 @@ - (GCDWebServerResponse*)performDELETE:(GCDWebServerRequest*)request {
161166
NSString* relativePath = request.path;
162167
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
163168
BOOL isDirectory = NO;
164-
if (![absolutePath hasPrefix:_uploadDirectory] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
169+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
165170
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
166171
}
167172

@@ -194,7 +199,7 @@ - (GCDWebServerResponse*)performMKCOL:(GCDWebServerDataRequest*)request {
194199

195200
NSString* relativePath = request.path;
196201
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
197-
if (![absolutePath hasPrefix:_uploadDirectory]) {
202+
if (![self _checkSandboxedPath:absolutePath]) {
198203
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
199204
}
200205
BOOL isDirectory;
@@ -243,7 +248,7 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL)
243248

244249
NSString* srcRelativePath = request.path;
245250
NSString* srcAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:srcRelativePath];
246-
if (![srcAbsolutePath hasPrefix:_uploadDirectory]) {
251+
if (![self _checkSandboxedPath:srcAbsolutePath]) {
247252
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath];
248253
}
249254

@@ -254,7 +259,7 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL)
254259
}
255260
dstRelativePath = [[dstRelativePath substringFromIndex:(range.location + range.length)] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
256261
NSString* dstAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:dstRelativePath];
257-
if (![dstAbsolutePath hasPrefix:_uploadDirectory]) {
262+
if (![self _checkSandboxedPath:dstAbsolutePath]) {
258263
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath];
259264
}
260265

@@ -425,7 +430,7 @@ - (GCDWebServerResponse*)performPROPFIND:(GCDWebServerDataRequest*)request {
425430
NSString* relativePath = request.path;
426431
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
427432
BOOL isDirectory = NO;
428-
if (![absolutePath hasPrefix:_uploadDirectory] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
433+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
429434
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
430435
}
431436

@@ -475,7 +480,7 @@ - (GCDWebServerResponse*)performLOCK:(GCDWebServerDataRequest*)request {
475480
NSString* relativePath = request.path;
476481
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
477482
BOOL isDirectory = NO;
478-
if (![absolutePath hasPrefix:_uploadDirectory] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
483+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
479484
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
480485
}
481486

@@ -575,7 +580,7 @@ - (GCDWebServerResponse*)performUNLOCK:(GCDWebServerRequest*)request {
575580
NSString* relativePath = request.path;
576581
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
577582
BOOL isDirectory = NO;
578-
if (![absolutePath hasPrefix:_uploadDirectory] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
583+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
579584
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
580585
}
581586

GCDWebUploader/GCDWebUploader.m

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ @interface GCDWebUploader () {
5757

5858
@implementation GCDWebUploader (Methods)
5959

60+
// Must match implementation in GCDWebDAVServer
61+
- (BOOL)_checkSandboxedPath:(NSString*)path {
62+
return [[path stringByStandardizingPath] hasPrefix:_uploadDirectory];
63+
}
64+
6065
- (BOOL)_checkFileExtension:(NSString*)fileName {
6166
if (_allowedExtensions && ![_allowedExtensions containsObject:[[fileName pathExtension] lowercaseString]]) {
6267
return NO;
@@ -85,8 +90,8 @@ - (NSString*) _uniquePathForPath:(NSString*)path {
8590
- (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request {
8691
NSString* relativePath = [[request query] objectForKey:@"path"];
8792
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
88-
BOOL isDirectory;
89-
if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
93+
BOOL isDirectory = NO;
94+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
9095
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
9196
}
9297
if (!isDirectory) {
@@ -129,8 +134,8 @@ - (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request {
129134
- (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request {
130135
NSString* relativePath = [[request query] objectForKey:@"path"];
131136
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
132-
BOOL isDirectory;
133-
if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
137+
BOOL isDirectory = NO;
138+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
134139
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
135140
}
136141
if (isDirectory) {
@@ -160,6 +165,9 @@ - (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request {
160165
}
161166
NSString* relativePath = [[request firstArgumentForControlName:@"path"] string];
162167
NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]];
168+
if (![self _checkSandboxedPath:absolutePath]) {
169+
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
170+
}
163171

164172
if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {
165173
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file \"%@\" to \"%@\" is not permitted", file.fileName, relativePath];
@@ -181,13 +189,16 @@ - (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request {
181189
- (GCDWebServerResponse*)moveItem:(GCDWebServerURLEncodedFormRequest*)request {
182190
NSString* oldRelativePath = [request.arguments objectForKey:@"oldPath"];
183191
NSString* oldAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:oldRelativePath];
184-
BOOL isDirectory;
185-
if (![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) {
192+
BOOL isDirectory = NO;
193+
if (![self _checkSandboxedPath:oldAbsolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) {
186194
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", oldRelativePath];
187195
}
188196

189197
NSString* newRelativePath = [request.arguments objectForKey:@"newPath"];
190198
NSString* newAbsolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:newRelativePath]];
199+
if (![self _checkSandboxedPath:newAbsolutePath]) {
200+
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", newRelativePath];
201+
}
191202

192203
NSString* itemName = [newAbsolutePath lastPathComponent];
193204
if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) {
@@ -215,7 +226,7 @@ - (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request
215226
NSString* relativePath = [request.arguments objectForKey:@"path"];
216227
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
217228
BOOL isDirectory = NO;
218-
if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
229+
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
219230
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
220231
}
221232

@@ -244,6 +255,9 @@ - (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request
244255
- (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)request {
245256
NSString* relativePath = [request.arguments objectForKey:@"path"];
246257
NSString* absolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:relativePath]];
258+
if (![self _checkSandboxedPath:absolutePath]) {
259+
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
260+
}
247261

248262
NSString* directoryName = [absolutePath lastPathComponent];
249263
if (!_allowHidden && [directoryName hasPrefix:@"."]) {

0 commit comments

Comments
 (0)