From 4552a2d94f819cbc76b01354a692eda571cbd0c6 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 25 Aug 2020 23:03:48 -0700 Subject: [PATCH] Add permission checks to DeleteSaveDataFileSystem --- src/LibHac/FsSrv/FileSystemProxy.cs | 47 ++++++++++++++----- src/LibHac/FsSrv/FileSystemServer.cs | 7 --- .../FsSrv/Impl/ProgramRegistryManager.cs | 2 +- .../FileSystemServerFactory.cs | 2 +- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/LibHac/FsSrv/FileSystemProxy.cs b/src/LibHac/FsSrv/FileSystemProxy.cs index e31d7fe6..2c2adb1a 100644 --- a/src/LibHac/FsSrv/FileSystemProxy.cs +++ b/src/LibHac/FsSrv/FileSystemProxy.cs @@ -190,17 +190,27 @@ namespace LibHac.FsSrv private Result DeleteSaveDataFileSystemImpl(SaveDataSpaceId spaceId, ulong saveDataId) { - Result rc = OpenSaveDataIndexerAccessor(out SaveDataIndexerAccessor accessor, spaceId); + Result rc = GetProgramInfo(out ProgramInfo programInfo); if (rc.IsFailure()) return rc; - using (accessor) + SaveDataIndexerAccessor accessor = null; + + try { + SaveDataType saveType; + if (saveDataId == FileSystemServer.SaveIndexerId) { - // missing: This save can only be deleted by the FS process itself + if (!IsCurrentProcess(CurrentProcess)) + return ResultFs.PermissionDenied.Log(); + + saveType = SaveDataType.System; } else { + rc = OpenSaveDataIndexerAccessor(out accessor, spaceId); + if (rc.IsFailure()) return rc; + if (spaceId != SaveDataSpaceId.ProperSystem && spaceId != SaveDataSpaceId.SafeMode) { rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId); @@ -214,13 +224,17 @@ namespace LibHac.FsSrv if (key.Type == SaveDataType.System || key.Type == SaveDataType.SystemBcat) { - // Check if permissions allow deleting system save data + if (!programInfo.AccessControl.CanCall(OperationType.DeleteSystemSaveData)) + return ResultFs.PermissionDenied.Log(); } else { - // Check if permissions allow deleting save data + if (!programInfo.AccessControl.CanCall(OperationType.DeleteSaveData)) + return ResultFs.PermissionDenied.Log(); } + saveType = key.Type; + rc = accessor.Indexer.SetState(saveDataId, SaveDataState.Creating); if (rc.IsFailure()) return rc; @@ -228,11 +242,12 @@ namespace LibHac.FsSrv if (rc.IsFailure()) return rc; } - rc = DeleteSaveDataFileSystemImpl2(spaceId, saveDataId); + rc = DeleteSaveDataFileSystemImpl2(spaceId, saveDataId, saveType, false); if (rc.IsFailure()) return rc; if (saveDataId != FileSystemServer.SaveIndexerId) { + // ReSharper disable once PossibleNullReferenceException rc = accessor.Indexer.Delete(saveDataId); if (rc.IsFailure()) return rc; @@ -242,12 +257,14 @@ namespace LibHac.FsSrv return Result.Success; } + finally { accessor?.Dispose(); } } - private Result DeleteSaveDataFileSystemImpl2(SaveDataSpaceId spaceId, ulong saveDataId) + // ReSharper disable once UnusedParameter.Local + private Result DeleteSaveDataFileSystemImpl2(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataType type, bool shouldWipe) { // missing: Check extra data flags for this value. Bit 3 - bool doSecureDelete = false; + bool doSecureDelete = shouldWipe; Result rc = FsProxyCore.DeleteSaveDataMetaFiles(saveDataId, spaceId); if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc)) @@ -275,7 +292,6 @@ namespace LibHac.FsSrv using (accessor) { - rc = accessor.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId); if (rc.IsFailure()) return rc; @@ -326,6 +342,8 @@ namespace LibHac.FsSrv SaveDataIndexerAccessor accessor = null; + // Missing permission checks + try { if (attribute.StaticSaveDataId == FileSystemServer.SaveIndexerId) @@ -399,7 +417,7 @@ namespace LibHac.FsSrv { if (!ResultFs.PathAlreadyExists.Includes(rc)) return rc; - rc = DeleteSaveDataFileSystemImpl2(creationInfo.SpaceId, saveDataId); + rc = DeleteSaveDataFileSystemImpl2(creationInfo.SpaceId, saveDataId, attribute.Type, false); if (rc.IsFailure()) return rc; rc = FsProxyCore.CreateSaveDataFileSystem(saveDataId, ref attribute, ref creationInfo, SaveDataRootPath, @@ -455,7 +473,7 @@ namespace LibHac.FsSrv // Revert changes if an error happened in the middle of creation if (isDeleteNeeded) { - DeleteSaveDataFileSystemImpl2(creationInfo.SpaceId, saveDataId).IgnoreResult(); + DeleteSaveDataFileSystemImpl2(creationInfo.SpaceId, saveDataId, attribute.Type, false).IgnoreResult(); if (accessor != null && saveDataId != FileSystemServer.SaveIndexerId) { @@ -1253,6 +1271,13 @@ namespace LibHac.FsSrv return FsProxyCore.ProgramRegistry.GetProgramInfo(out programInfo, CurrentProcess); } + internal bool IsCurrentProcess(ulong processId) + { + ulong currentId = Hos.Os.GetCurrentProcessId().Value; + + return processId == currentId; + } + private static bool IsSystemSaveDataId(ulong id) { return (long)id < 0; diff --git a/src/LibHac/FsSrv/FileSystemServer.cs b/src/LibHac/FsSrv/FileSystemServer.cs index 3fd57fab..cebda0a8 100644 --- a/src/LibHac/FsSrv/FileSystemServer.cs +++ b/src/LibHac/FsSrv/FileSystemServer.cs @@ -96,13 +96,6 @@ namespace LibHac.FsSrv return new ProgramRegistryImpl(FsProxyCore.Config.ProgramRegistryServiceImpl); } - internal bool IsCurrentProcess(ulong processId) - { - ulong currentId = Hos.Os.GetCurrentProcessId().Value; - - return processId == currentId; - } - private class FileSystemProxyService : IServiceObject { private readonly FileSystemServer _server; diff --git a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs index 8105b824..bf6a7ec8 100644 --- a/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs +++ b/src/LibHac/FsSrv/Impl/ProgramRegistryManager.cs @@ -167,7 +167,7 @@ namespace LibHac.FsSrv.Impl ReadOnlySpan accessControlDescriptor) { ProcessId = 0; - AccessControl = new AccessControl(fsServer, accessControlData, accessControlDescriptor); + AccessControl = new AccessControl(fsServer, accessControlData, accessControlDescriptor, ulong.MaxValue); ProgramId = default; StorageId = 0; } diff --git a/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs b/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs index 7f4c8135..c5f80d91 100644 --- a/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs +++ b/tests/LibHac.Tests/Fs/FileSystemClientTests/FileSystemServerFactory.cs @@ -21,7 +21,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests var horizon = new Horizon(new StopWatchTimeSpanGenerator(), config); - HorizonClient horizonClient = horizon.CreateHorizonClient(); + HorizonClient horizonClient = horizon.CreatePrivilegedHorizonClient(); return horizonClient.Fs; }