Fix an off-by-one error when parsing mount names

This commit is contained in:
Alex Barney 2022-05-17 02:26:26 -07:00
parent 2e04bcad94
commit dfd37d314f
2 changed files with 61 additions and 20 deletions

View file

@ -23,7 +23,7 @@ public static class MountUtility
/// </summary> /// </summary>
/// <param name="mountName">If the method returns successfully, contains the mount name of the provided path; /// <param name="mountName">If the method returns successfully, contains the mount name of the provided path;
/// otherwise the contents are undefined.</param> /// otherwise the contents are undefined.</param>
/// <param name="subPath">If the method returns successfully, contains the provided path without the /// <param name="outSubPath">If the method returns successfully, contains the provided path without the
/// mount name; otherwise the contents are undefined.</param> /// mount name; otherwise the contents are undefined.</param>
/// <param name="path">The <see cref="Path"/> to process.</param> /// <param name="path">The <see cref="Path"/> to process.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/> /// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
@ -31,52 +31,58 @@ public static class MountUtility
/// the mount name that begins with <c>/</c> or <c>\</c>.<br/> /// the mount name that begins with <c>/</c> or <c>\</c>.<br/>
/// <see cref="ResultFs.InvalidMountName"/>: <paramref name="path"/> contains an invalid mount name /// <see cref="ResultFs.InvalidMountName"/>: <paramref name="path"/> contains an invalid mount name
/// or does not have a mount name.</returns> /// or does not have a mount name.</returns>
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); UnsafeHelpers.SkipParamInit(out mountName);
subPath = default; outSubPath = default;
int mountLen = 0;
int maxMountLen = Math.Min(path.Length, PathTool.MountNameLengthMax);
if (WindowsPath.IsWindowsDrive(path) || WindowsPath.IsUncPath(path)) if (WindowsPath.IsWindowsDrive(path) || WindowsPath.IsUncPath(path))
{ {
StringUtils.Copy(mountName.Name, HostRootFileSystemMountName); StringUtils.Copy(mountName.Name, HostRootFileSystemMountName);
mountName.Name[PathTool.MountNameLengthMax] = NullTerminator; mountName.Name[PathTool.MountNameLengthMax] = NullTerminator;
subPath = path; outSubPath = path;
return Result.Success; return Result.Success;
} }
for (int i = 0; i <= maxMountLen; i++) int mountLen = FindMountNameDriveSeparator(path);
{
if (path[i] == DriveSeparator)
{
mountLen = i;
break;
}
}
if (mountLen == 0) if (mountLen == 0)
return ResultFs.InvalidMountName.Log(); return ResultFs.InvalidMountName.Log();
if (mountLen > maxMountLen) if (mountLen > PathTool.MountNameLengthMax)
return ResultFs.InvalidMountName.Log(); return ResultFs.InvalidMountName.Log();
if (mountLen <= 0) if (mountLen <= 0)
return ResultFs.InvalidMountName.Log(); return ResultFs.InvalidMountName.Log();
U8Span subPathTemp = path.Slice(mountLen + 1); U8Span subPath = path.Slice(mountLen + 1);
if (subPathTemp.Length == 0 || bool startsWithDir = subPath.Length > 0 &&
(subPathTemp[0] != DirectorySeparator && subPathTemp[0] != AltDirectorySeparator)) (subPath[0] == DirectorySeparator || subPath[0] == AltDirectorySeparator);
if (!startsWithDir)
return ResultFs.InvalidPathFormat.Log(); return ResultFs.InvalidPathFormat.Log();
path.Value.Slice(0, mountLen).CopyTo(mountName.Name); path.Value.Slice(0, mountLen).CopyTo(mountName.Name);
mountName.Name[mountLen] = NullTerminator; mountName.Name[mountLen] = NullTerminator;
subPath = subPathTemp;
outSubPath = subPath;
return Result.Success; 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) public static bool IsValidMountName(this FileSystemClientImpl fs, U8Span name)

View file

@ -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()));
}
}