Add some validation to StorageBase

This commit is contained in:
Alex Barney 2019-10-11 12:53:29 -05:00
parent 54950c9b68
commit bfc343e801
9 changed files with 89 additions and 40 deletions

View file

@ -55,7 +55,7 @@ namespace LibHac.Fs
public Result GetSize(out long size) public Result GetSize(out long size)
{ {
size = 0; size = default;
if (IsDisposed) return ResultFs.PreconditionViolation.Log(); if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return GetSizeImpl(out size); return GetSizeImpl(out size);

View file

@ -21,7 +21,7 @@ namespace LibHac.Fs
FsClient = Handle.File.Parent.FsClient; FsClient = Handle.File.Parent.FsClient;
} }
public override Result Read(long offset, Span<byte> destination) public override Result ReadImpl(long offset, Span<byte> destination)
{ {
lock (_locker) lock (_locker)
{ {
@ -30,14 +30,13 @@ namespace LibHac.Fs
Result rc = UpdateSize(); Result rc = UpdateSize();
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
if (destination.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.ValueOutOfRange.Log();
return FsClient.ReadFile(Handle, offset, destination); return FsClient.ReadFile(Handle, offset, destination);
} }
} }
public override Result Write(long offset, ReadOnlySpan<byte> source) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
{ {
lock (_locker) lock (_locker)
{ {
@ -46,26 +45,25 @@ namespace LibHac.Fs
Result rc = UpdateSize(); Result rc = UpdateSize();
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
if (source.Length < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.ValueOutOfRange.Log();
return FsClient.WriteFile(Handle, offset, source); return FsClient.WriteFile(Handle, offset, source);
} }
} }
public override Result Flush() public override Result FlushImpl()
{ {
return FsClient.FlushFile(Handle); return FsClient.FlushFile(Handle);
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
FileSize = InvalidSize; FileSize = InvalidSize;
return FsClient.SetFileSize(Handle, size); return FsClient.SetFileSize(Handle, size);
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = default; size = default;
@ -87,7 +85,7 @@ namespace LibHac.Fs
return Result.Success; return Result.Success;
} }
public override void Dispose() protected override void Dispose(bool disposing)
{ {
if (CloseHandle) if (CloseHandle)
{ {

View file

@ -205,8 +205,8 @@ namespace LibHac.Fs
{ {
None = 0, None = 0,
Application = 1 << 0, Application = 1 << 0,
Internal = 1 << 1, System = 1 << 1,
All = Application | Internal All = Application | System
} }
[Flags] [Flags]

View file

@ -135,7 +135,7 @@
public static Result RemapStorageMapFull => new Result(ModuleFs, 6811); public static Result RemapStorageMapFull => new Result(ModuleFs, 6811);
public static Result Result6902 => new Result(ModuleFs, 6902); public static Result SubStorageNotInitialized => new Result(ModuleFs, 6902);
public static Result MountNameNotFound => new Result(ModuleFs, 6905); public static Result MountNameNotFound => new Result(ModuleFs, 6905);
} }
} }

View file

@ -31,7 +31,7 @@ namespace LibHac.Fs
public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId,
ulong saveDataId, UserId userId, ulong ownerId, long size, long journalSize, uint flags) ulong saveDataId, UserId userId, ulong ownerId, long size, long journalSize, uint flags)
{ {
return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, return fs.RunOperationWithAccessLog(LocalAccessLogMode.System,
() => () =>
{ {
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
@ -89,7 +89,7 @@ namespace LibHac.Fs
public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId) public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId)
{ {
return fs.RunOperationWithAccessLog(LocalAccessLogMode.Internal, return fs.RunOperationWithAccessLog(LocalAccessLogMode.System,
() => () =>
{ {
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();

View file

@ -1,20 +1,71 @@
using System; using System;
using System.Threading;
namespace LibHac.Fs namespace LibHac.Fs
{ {
public abstract class StorageBase : IStorage public abstract class StorageBase : IStorage
{ {
public abstract Result Read(long offset, Span<byte> destination); // 0 = not disposed; 1 = disposed
public abstract Result Write(long offset, ReadOnlySpan<byte> source); private int _disposedState;
public abstract Result Flush(); private bool IsDisposed => _disposedState != 0;
public abstract Result SetSize(long size);
public abstract Result GetSize(out long size);
public virtual void Dispose() { } public abstract Result ReadImpl(long offset, Span<byte> destination);
public abstract Result WriteImpl(long offset, ReadOnlySpan<byte> source);
public abstract Result FlushImpl();
public abstract Result GetSizeImpl(out long size);
public abstract Result SetSizeImpl(long size);
public Result Read(long offset, Span<byte> destination)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return ReadImpl(offset, destination);
}
public Result Write(long offset, ReadOnlySpan<byte> source)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return WriteImpl(offset, source);
}
public Result Flush()
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return FlushImpl();
}
public Result SetSize(long size)
{
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return SetSizeImpl(size);
}
public Result GetSize(out long size)
{
size = default;
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
return GetSizeImpl(out size);
}
public void Dispose()
{
// Make sure Dispose is only called once
if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
protected virtual void Dispose(bool disposing) { }
public static bool IsRangeValid(long offset, long size, long totalSize) public static bool IsRangeValid(long offset, long size, long totalSize)
{ {
return size <= totalSize && offset <= totalSize - size; return offset >= 0 && size >= 0 && size <= totalSize && offset <= totalSize - size;
} }
} }
} }

View file

@ -23,38 +23,38 @@ namespace LibHac.Fs
Size = size; Size = size;
} }
public override Result Read(long offset, Span<byte> destination) public override Result ReadImpl(long offset, Span<byte> destination)
{ {
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
if (destination.Length == 0) return Result.Success; if (destination.Length == 0) return Result.Success;
if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.ValueOutOfRange.Log();
return BaseStorage.Read(Offset + offset, destination); return BaseStorage.Read(Offset + offset, destination);
} }
public override Result Write(long offset, ReadOnlySpan<byte> source) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
{ {
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
if (source.Length == 0) return Result.Success; if (source.Length == 0) return Result.Success;
if (Size < 0 || offset < 0) return ResultFs.ValueOutOfRange.Log();
if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.ValueOutOfRange.Log(); if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.ValueOutOfRange.Log();
return BaseStorage.Write(Offset + offset, source); return BaseStorage.Write(Offset + offset, source);
} }
public override Result Flush() public override Result FlushImpl()
{ {
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
return BaseStorage.Flush(); return BaseStorage.Flush();
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); if (!IsResizable) return ResultFs.SubStorageNotResizable.Log();
if (size < 0 || Offset < 0) return ResultFs.ValueOutOfRange.Log(); if (size < 0 || Offset < 0) return ResultFs.InvalidSize.Log();
Result rc = BaseStorage.GetSize(out long baseSize); Result rc = BaseStorage.GetSize(out long baseSize);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
@ -72,11 +72,11 @@ namespace LibHac.Fs
return Result.Success; return Result.Success;
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = default; size = default;
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
size = Size; size = Size;
return Result.Success; return Result.Success;

View file

@ -87,7 +87,7 @@ namespace LibHac.FsService.Creators
imageHash.CopyTo(ImageHash); imageHash.CopyTo(ImageHash);
} }
public override Result Read(long offset, Span<byte> destination) public override Result ReadImpl(long offset, Span<byte> destination)
{ {
// In secure mode, if Handle is old and the card's device ID and // In secure mode, if Handle is old and the card's device ID and
// header hash are still the same, Handle is updated to the new handle // header hash are still the same, Handle is updated to the new handle
@ -95,22 +95,22 @@ namespace LibHac.FsService.Creators
return GameCard.Read(Handle, offset, destination); return GameCard.Read(Handle, offset, destination);
} }
public override Result Write(long offset, ReadOnlySpan<byte> source) public override Result WriteImpl(long offset, ReadOnlySpan<byte> source)
{ {
return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log(); return ResultFs.UnsupportedOperationInRoGameCardStorageWrite.Log();
} }
public override Result Flush() public override Result FlushImpl()
{ {
return Result.Success; return Result.Success;
} }
public override Result SetSize(long size) public override Result SetSizeImpl(long size)
{ {
return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log(); return ResultFs.UnsupportedOperationInRoGameCardStorageSetSize.Log();
} }
public override Result GetSize(out long size) public override Result GetSizeImpl(out long size)
{ {
size = 0; size = 0;

View file

@ -62,7 +62,7 @@ namespace LibHac.FsSystem
public override Result SetSize(long size) public override Result SetSize(long size)
{ {
if (BaseStorage == null) return ResultFs.Result6902.Log(); if (BaseStorage == null) return ResultFs.SubStorageNotInitialized.Log();
// todo: Add IsResizable member // todo: Add IsResizable member
// if (!IsResizable) return ResultFs.SubStorageNotResizable.Log(); // if (!IsResizable) return ResultFs.SubStorageNotResizable.Log();