Skip to content

Commit b8ddca8

Browse files
authored
Merge pull request #31013 from nextcloud/backport/30114/stable22
[stable22] Prevent writing invalid mtime
2 parents bcbd42d + 41fe871 commit b8ddca8

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
@@ -412,6 +412,11 @@ protected function sanitizeMtime($mtimeFromRequest) {
412412
throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
413413
}
414414

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

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -361,28 +361,28 @@ public function legalMtimeProvider() {
361361
'expected result' => null
362362
],
363363
"castable string (int)" => [
364-
'HTTP_X_OC_MTIME' => "34",
365-
'expected result' => 34
364+
'HTTP_X_OC_MTIME' => "987654321",
365+
'expected result' => 987654321
366366
],
367367
"castable string (float)" => [
368-
'HTTP_X_OC_MTIME' => "34.56",
369-
'expected result' => 34
368+
'HTTP_X_OC_MTIME' => "123456789.56",
369+
'expected result' => 123456789
370370
],
371371
"float" => [
372-
'HTTP_X_OC_MTIME' => 34.56,
373-
'expected result' => 34
372+
'HTTP_X_OC_MTIME' => 123456789.56,
373+
'expected result' => 123456789
374374
],
375375
"zero" => [
376376
'HTTP_X_OC_MTIME' => 0,
377-
'expected result' => 0
377+
'expected result' => null
378378
],
379379
"zero string" => [
380380
'HTTP_X_OC_MTIME' => "0",
381-
'expected result' => 0
381+
'expected result' => null
382382
],
383383
"negative zero string" => [
384384
'HTTP_X_OC_MTIME' => "-0",
385-
'expected result' => 0
385+
'expected result' => null
386386
],
387387
"string starting with number following by char" => [
388388
'HTTP_X_OC_MTIME' => "2345asdf",
@@ -398,11 +398,11 @@ public function legalMtimeProvider() {
398398
],
399399
"negative int" => [
400400
'HTTP_X_OC_MTIME' => -34,
401-
'expected result' => -34
401+
'expected result' => null
402402
],
403403
"negative float" => [
404404
'HTTP_X_OC_MTIME' => -34.43,
405-
'expected result' => -34
405+
'expected result' => null
406406
],
407407
];
408408
}
@@ -421,7 +421,6 @@ public function testPutSingleFileLegalMtime($requestMtime, $resultMtime) {
421421

422422
if ($resultMtime === null) {
423423
$this->expectException(\InvalidArgumentException::class);
424-
$this->expectExceptionMessage("X-OC-MTime header must be an integer (unix timestamp).");
425424
}
426425

427426
$this->doPut($file, null, $request);
@@ -447,7 +446,6 @@ public function testChunkedPutLegalMtime($requestMtime, $resultMtime) {
447446

448447
if ($resultMtime === null) {
449448
$this->expectException(\Sabre\DAV\Exception::class);
450-
$this->expectExceptionMessage("X-OC-MTime header must be an integer (unix timestamp).");
451449
}
452450

453451
$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
@@ -164,8 +164,54 @@ public function testSharePermissions($type, $user, $permissions, $expected) {
164164
->disableOriginalConstructor()
165165
->getMock();
166166

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

0 commit comments

Comments
 (0)