From dfd37d314f35547bd41904a4f0b40f2f6c8b76b3 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 17 May 2022 02:26:26 -0700 Subject: [PATCH] Fix an off-by-one error when parsing mount names --- src/LibHac/Fs/Fsa/MountUtility.cs | 46 +++++++++++-------- .../Fs/FsaTests/MountUtilityTests.cs | 35 ++++++++++++++ 2 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 tests/LibHac.Tests/Fs/FsaTests/MountUtilityTests.cs diff --git a/src/LibHac/Fs/Fsa/MountUtility.cs b/src/LibHac/Fs/Fsa/MountUtility.cs index f7fb917f..b7a144ea 100644 --- a/src/LibHac/Fs/Fsa/MountUtility.cs +++ b/src/LibHac/Fs/Fsa/MountUtility.cs @@ -23,7 +23,7 @@ public static class MountUtility /// /// If the method returns successfully, contains the mount name of the provided path; /// otherwise the contents are undefined. - /// If the method returns successfully, contains the provided path without the + /// If the method returns successfully, contains the provided path without the /// mount name; otherwise the contents are undefined. /// The to process. /// : The operation was successful.
@@ -31,52 +31,58 @@ public static class MountUtility /// the mount name that begins with / or \.
/// : contains an invalid mount name /// or does not have a mount name.
- private static Result GetMountNameAndSubPath(out MountName mountName, out U8Span subPath, U8Span path) + private static Result GetMountNameAndSubPath(out MountName mountName, out U8Span outSubPath, U8Span path) { UnsafeHelpers.SkipParamInit(out mountName); - subPath = default; - - int mountLen = 0; - int maxMountLen = Math.Min(path.Length, PathTool.MountNameLengthMax); + outSubPath = default; if (WindowsPath.IsWindowsDrive(path) || WindowsPath.IsUncPath(path)) { StringUtils.Copy(mountName.Name, HostRootFileSystemMountName); mountName.Name[PathTool.MountNameLengthMax] = NullTerminator; - subPath = path; + outSubPath = path; return Result.Success; } - for (int i = 0; i <= maxMountLen; i++) - { - if (path[i] == DriveSeparator) - { - mountLen = i; - break; - } - } + int mountLen = FindMountNameDriveSeparator(path); if (mountLen == 0) return ResultFs.InvalidMountName.Log(); - if (mountLen > maxMountLen) + if (mountLen > PathTool.MountNameLengthMax) return ResultFs.InvalidMountName.Log(); if (mountLen <= 0) return ResultFs.InvalidMountName.Log(); - U8Span subPathTemp = path.Slice(mountLen + 1); + U8Span subPath = path.Slice(mountLen + 1); - if (subPathTemp.Length == 0 || - (subPathTemp[0] != DirectorySeparator && subPathTemp[0] != AltDirectorySeparator)) + bool startsWithDir = subPath.Length > 0 && + (subPath[0] == DirectorySeparator || subPath[0] == AltDirectorySeparator); + + if (!startsWithDir) return ResultFs.InvalidPathFormat.Log(); path.Value.Slice(0, mountLen).CopyTo(mountName.Name); mountName.Name[mountLen] = NullTerminator; - subPath = subPathTemp; + outSubPath = subPath; return Result.Success; + + static int FindMountNameDriveSeparator(U8Span path) + { + for (int i = 0; i < path.Length && i < PathTool.MountNameLengthMax + 1; i++) + { + if (path[i] == NullTerminator) + return 0; + + if (path[i] == DriveSeparator) + return i; + } + + return 0; + } } public static bool IsValidMountName(this FileSystemClientImpl fs, U8Span name) diff --git a/tests/LibHac.Tests/Fs/FsaTests/MountUtilityTests.cs b/tests/LibHac.Tests/Fs/FsaTests/MountUtilityTests.cs new file mode 100644 index 00000000..371e3236 --- /dev/null +++ b/tests/LibHac.Tests/Fs/FsaTests/MountUtilityTests.cs @@ -0,0 +1,35 @@ +using LibHac.Common; +using LibHac.Fs; +using LibHac.Fs.Fsa; +using LibHac.Fs.Shim; +using LibHac.Tests.Fs.FileSystemClientTests; +using Xunit; + +namespace LibHac.Tests.Fs.FsaTests; + +public class MountUtilityTests +{ + [Theory] + [InlineData("0123456789ABCDE", "0123456789ABCDE:/")] + [InlineData("01234", "01234:/")] + public void GetMountName_ValidName_ReturnsSuccess(string mountName, string path) + { + FileSystemClient fs = FileSystemServerFactory.CreateClient(true); + + Assert.Success(fs.MountSdCard(mountName.ToU8Span())); + Assert.Success(fs.GetEntryType(out _, path.ToU8Span())); + } + + [Theory] + [InlineData("01234", "01234")] + [InlineData("0123456789ABCDE", "0123456789ABCDE")] + [InlineData("01234", "0123456789ABCDEF")] + [InlineData("01234", "0123456789ABCDEF:/")] + public void GetMountName_InvalidName_ReturnsInvalidMountName(string mountName, string path) + { + FileSystemClient fs = FileSystemServerFactory.CreateClient(true); + + Assert.Success(fs.MountSdCard(mountName.ToU8Span())); + Assert.Result(ResultFs.InvalidMountName, fs.GetEntryType(out _, path.ToU8Span())); + } +} \ No newline at end of file