Skip to content

Commit aa38e77

Browse files
authored
Merge pull request #31250 from nextcloud/backport/30114/stable20
[stable20] Prevent writing invalid mtime
2 parents 2877973 + 235e1ff commit aa38e77

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

apps/dav/lib/Connector/Sabre/Node.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ protected function sanitizeMtime($mtimeFromRequest) {
414414
throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
415415
}
416416

417+
// Prevent writing invalid mtime (timezone-proof)
418+
if ((int)$mtimeFromRequest <= 24 * 60 * 60) {
419+
throw new \InvalidArgumentException('X-OC-MTime header must be a valid positive integer');
420+
}
421+
417422
return (int)$mtimeFromRequest;
418423
}
419424
}

apps/dav/tests/unit/Connector/Sabre/FileTest.php

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -354,28 +354,28 @@ public function legalMtimeProvider() {
354354
'expected result' => null
355355
],
356356
"castable string (int)" => [
357-
'HTTP_X_OC_MTIME' => "34",
358-
'expected result' => 34
357+
'HTTP_X_OC_MTIME' => "987654321",
358+
'expected result' => 987654321
359359
],
360360
"castable string (float)" => [
361-
'HTTP_X_OC_MTIME' => "34.56",
362-
'expected result' => 34
361+
'HTTP_X_OC_MTIME' => "123456789.56",
362+
'expected result' => 123456789
363363
],
364364
"float" => [
365-
'HTTP_X_OC_MTIME' => 34.56,
366-
'expected result' => 34
365+
'HTTP_X_OC_MTIME' => 123456789.56,
366+
'expected result' => 123456789
367367
],
368368
"zero" => [
369369
'HTTP_X_OC_MTIME' => 0,
370-
'expected result' => 0
370+
'expected result' => null
371371
],
372372
"zero string" => [
373373
'HTTP_X_OC_MTIME' => "0",
374-
'expected result' => 0
374+
'expected result' => null
375375
],
376376
"negative zero string" => [
377377
'HTTP_X_OC_MTIME' => "-0",
378-
'expected result' => 0
378+
'expected result' => null
379379
],
380380
"string starting with number following by char" => [
381381
'HTTP_X_OC_MTIME' => "2345asdf",
@@ -391,11 +391,11 @@ public function legalMtimeProvider() {
391391
],
392392
"negative int" => [
393393
'HTTP_X_OC_MTIME' => -34,
394-
'expected result' => -34
394+
'expected result' => null
395395
],
396396
"negative float" => [
397397
'HTTP_X_OC_MTIME' => -34.43,
398-
'expected result' => -34
398+
'expected result' => null
399399
],
400400
];
401401
}
@@ -414,7 +414,6 @@ public function testPutSingleFileLegalMtime($requestMtime, $resultMtime) {
414414

415415
if ($resultMtime === null) {
416416
$this->expectException(\InvalidArgumentException::class);
417-
$this->expectExceptionMessage("X-OC-MTime header must be an integer (unix timestamp).");
418417
}
419418

420419
$this->doPut($file, null, $request);
@@ -440,7 +439,6 @@ public function testChunkedPutLegalMtime($requestMtime, $resultMtime) {
440439

441440
if ($resultMtime === null) {
442441
$this->expectException(\Sabre\DAV\Exception::class);
443-
$this->expectExceptionMessage("X-OC-MTime header must be an integer (unix timestamp).");
444442
}
445443

446444
$this->doPut($file.'-chunking-12345-2-0', null, $request);

apps/dav/tests/unit/Connector/Sabre/NodeTest.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,54 @@ public function testSharePermissions($type, $user, $permissions, $expected) {
165165
->disableOriginalConstructor()
166166
->getMock();
167167

168-
$node = new \OCA\DAV\Connector\Sabre\File($view, $info);
168+
$node = new \OCA\DAV\Connector\Sabre\File($view, $info);
169169
$this->invokePrivate($node, 'shareManager', [$shareManager]);
170170
$this->assertEquals($expected, $node->getSharePermissions($user));
171171
}
172+
173+
public function sanitizeMtimeProvider() {
174+
return [
175+
[123456789, 123456789],
176+
['987654321', 987654321],
177+
];
178+
}
179+
180+
/**
181+
* @dataProvider sanitizeMtimeProvider
182+
*/
183+
public function testSanitizeMtime($mtime, $expected) {
184+
$view = $this->getMockBuilder(View::class)
185+
->disableOriginalConstructor()
186+
->getMock();
187+
$info = $this->getMockBuilder(FileInfo::class)
188+
->disableOriginalConstructor()
189+
->getMock();
190+
191+
$node = new \OCA\DAV\Connector\Sabre\File($view, $info);
192+
$result = $this->invokePrivate($node, 'sanitizeMtime', [$mtime]);
193+
$this->assertEquals($expected, $result);
194+
}
195+
196+
public function invalidSanitizeMtimeProvider() {
197+
return [
198+
[-1337], [0], ['abcdef'], ['-1337'], ['0'], [12321], [24 * 60 * 60 - 1]
199+
];
200+
}
201+
202+
/**
203+
* @dataProvider invalidSanitizeMtimeProvider
204+
*/
205+
public function testInvalidSanitizeMtime($mtime) {
206+
$this->expectException(\InvalidArgumentException::class);
207+
208+
$view = $this->getMockBuilder(View::class)
209+
->disableOriginalConstructor()
210+
->getMock();
211+
$info = $this->getMockBuilder(FileInfo::class)
212+
->disableOriginalConstructor()
213+
->getMock();
214+
215+
$node = new \OCA\DAV\Connector\Sabre\File($view, $info);
216+
$result = $this->invokePrivate($node, 'sanitizeMtime', [$mtime]);
217+
}
172218
}

0 commit comments

Comments
 (0)