mirror of
https://github.com/SK-la/Ez2Lazer.git
synced 2026-03-13 11:20:28 +00:00
Apply more sanity checks when handling files from archives
This commit is contained in:
@@ -12,6 +12,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Utils;
|
||||
using Realms;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@@ -87,6 +88,10 @@ namespace osu.Game.Database
|
||||
public void AddFile(TModel item, Stream contents, string filename, Realm realm)
|
||||
{
|
||||
filename = filename.ToStandardisedPath();
|
||||
|
||||
if (FilesystemSanityCheckHelpers.IncursPathTraversalRisk(filename))
|
||||
throw new InvalidOperationException($@"Filename ""{filename}"" is not allowed.");
|
||||
|
||||
var existing = item.GetFile(filename);
|
||||
|
||||
if (existing != null)
|
||||
|
||||
@@ -17,6 +17,7 @@ using osu.Game.Extensions;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Utils;
|
||||
using Realms;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@@ -221,7 +222,15 @@ namespace osu.Game.Database
|
||||
foreach (string piece in realmFile.Filename.Split('/').Select(f => f.GetValidFilename()))
|
||||
destinationPath = Path.Combine(destinationPath, piece);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!);
|
||||
string destinationDirectory = Path.GetDirectoryName(destinationPath)!;
|
||||
|
||||
if (!FilesystemSanityCheckHelpers.IsSubDirectory(parent: mountedPath, child: destinationDirectory))
|
||||
{
|
||||
Logger.Log($@"Skipping attempt to mount {realmFile.Filename} due to detected escape out of mounted path.", LoggingTarget.Database);
|
||||
continue;
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
|
||||
// Consider using hard links here to make this instant.
|
||||
using (var inStream = Files.Storage.GetStream(sourcePath))
|
||||
@@ -361,6 +370,9 @@ namespace osu.Game.Database
|
||||
// We intentionally delay adding to realm to avoid blocking on a write during disk operations.
|
||||
foreach (var filenames in getShortenedFilenames(archive))
|
||||
{
|
||||
if (FilesystemSanityCheckHelpers.IncursPathTraversalRisk(filenames.shortened))
|
||||
throw new InvalidOperationException($@"Filename ""{filenames.original}"" is not allowed.");
|
||||
|
||||
using (Stream s = archive.GetStream(filenames.original))
|
||||
files.Add(new RealmNamedFileUsage(Files.Add(s, realm, false, parameters.PreferHardLinks), filenames.shortened));
|
||||
}
|
||||
|
||||
37
osu.Game/Utils/FilesystemSanityCheckHelpers.cs
Normal file
37
osu.Game/Utils/FilesystemSanityCheckHelpers.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace osu.Game.Utils
|
||||
{
|
||||
public static class FilesystemSanityCheckHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns whether <paramref name="path"/> is potentially susceptible to path traversal style attacks.
|
||||
/// </summary>
|
||||
public static bool IncursPathTraversalRisk(string path)
|
||||
=> path.Contains("../", StringComparison.Ordinal) || path.Contains("..\\", StringComparison.Ordinal) || Path.IsPathRooted(path);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether <paramref name="child"/> is a subdirectory (direct or nested) of <paramref name="parent"/>.
|
||||
/// </summary>
|
||||
public static bool IsSubDirectory(string parent, string child)
|
||||
{
|
||||
// `Path.GetFullPath()` invocations are required to fully resolve the paths to unambiguous downwards-traversal-only paths.
|
||||
var parentInfo = new DirectoryInfo(Path.GetFullPath(parent));
|
||||
var childInfo = new DirectoryInfo(Path.GetFullPath(child));
|
||||
|
||||
while (childInfo != null)
|
||||
{
|
||||
if (parentInfo.FullName == childInfo.FullName)
|
||||
return true;
|
||||
|
||||
childInfo = childInfo.Parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user