Fixup program-registry-related classes

- IProgramRegistry
- ProgramRegistryImpl
- ProgramIndexRegistryService
- ProgramRegistryServiceImpl
This commit is contained in:
Alex Barney 2022-01-13 18:44:58 -07:00
parent 814ae34642
commit ecb85269eb
10 changed files with 245 additions and 210 deletions

View file

@ -20,7 +20,7 @@ public static class ProgramRegistry
if (rc.IsFailure()) return rc.Miss();
rc = programRegistry.Get.RegisterProgram(processId, programId, storageId, new InBuffer(accessControlData),
new InBuffer(accessControlDescriptor));
accessControlData.Length, new InBuffer(accessControlDescriptor), accessControlDescriptor.Length);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
@ -41,4 +41,4 @@ public static class ProgramRegistry
return Result.Success;
}
}
}

View file

@ -138,7 +138,7 @@ public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader
private ProgramIndexRegistryService GetProgramIndexRegistryService()
{
return new ProgramIndexRegistryService(Globals.ProgramRegistryServiceImpl, _currentProcess);
return new ProgramIndexRegistryService(_fsServer, Globals.ProgramRegistryServiceImpl, _currentProcess);
}
private AccessLogService GetAccessLogService()
@ -1151,4 +1151,4 @@ public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader
{
return GetBaseFileSystemService().OpenBisWiper(ref outBisWiper, transferMemoryHandle, transferMemorySize);
}
}
}

View file

@ -82,7 +82,7 @@ public static class FileSystemServerInitializer
var programRegistryService = new ProgramRegistryServiceImpl(in programRegistryConfig);
server.InitializeProgramRegistryImpl(programRegistryService);
ProgramRegistryImpl.Initialize(server, programRegistryService);
var baseStorageConfig = new BaseStorageServiceImpl.Configuration();
baseStorageConfig.BisStorageCreator = config.FsCreators.BuiltInStorageCreator;
@ -272,4 +272,4 @@ public class FileSystemServerConfig
/// If null, an empty set will be created.
/// </summary>
public ExternalKeySet ExternalKeySet { get; set; }
}
}

View file

@ -66,7 +66,8 @@ public static class FileSystemProxyServiceObject
public void Dispose() { }
public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId,
InBuffer accessControlData, InBuffer accessControlDescriptor)
InBuffer accessControlData, long accessControlDataSize, InBuffer accessControlDescriptor,
long accessControlDescriptorSize)
{
return ResultFs.PortAcceptableCountLimited.Log();
}
@ -81,4 +82,4 @@ public static class FileSystemProxyServiceObject
return ResultFs.PortAcceptableCountLimited.Log();
}
}
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs;

View file

@ -1,99 +0,0 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Impl;
using LibHac.Sf;
using LibHac.Util;
namespace LibHac.FsSrv;
/// <summary>
/// Used to perform operations on the program index registry.
/// </summary>
/// <remarks>Appropriate methods calls on IFileSystemProxy are forwarded to this class
/// which then checks the calling process' permissions and performs the requested operation.
/// <br/>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
internal readonly struct ProgramIndexRegistryService
{
private ProgramRegistryServiceImpl ServiceImpl { get; }
private ulong ProcessId { get; }
public ProgramIndexRegistryService(ProgramRegistryServiceImpl serviceImpl, ulong processId)
{
ServiceImpl = serviceImpl;
ProcessId = processId;
}
/// <summary>
/// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary>
/// <param name="programIndexMapInfo">A buffer containing the program map info to register.</param>
/// <param name="programCount">The number of programs to register. The provided buffer must be
/// large enough to hold this many <see cref="ProgramIndexMapInfo"/> entries.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.<br/>
/// <see cref="ResultFs.InvalidSize"/>: The buffer was too small to hold the specified
/// number of <see cref="ProgramIndexMapInfo"/> entries.</returns>
public Result RegisterProgramIndexMapInfo(InBuffer programIndexMapInfo, int programCount)
{
// Verify the caller's permissions
Result rc = GetProgramInfo(out ProgramInfo programInfo, ProcessId);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.RegisterProgramIndexMapInfo))
return ResultFs.PermissionDenied.Log();
// Return early if the program count is 0 so we leave any previously
// registered entries as they were
if (programCount == 0)
return Result.Success;
// Verify that the provided buffer is large enough to hold "programCount" entries
ReadOnlySpan<ProgramIndexMapInfo>
mapInfo = MemoryMarshal.Cast<byte, ProgramIndexMapInfo>(programIndexMapInfo.Buffer);
if (mapInfo.Length < programCount)
return ResultFs.InvalidSize.Log();
// Register the map info
return ServiceImpl.RegisterProgramIndexMapInfo(mapInfo.Slice(0, programCount));
}
/// <summary>
/// Gets the multi-program index of the calling process and the number of programs
/// in the current application.
/// </summary>
/// <param name="programIndex">When this method returns successfully, contains the
/// program index of the calling process.</param>
/// <param name="programCount">When this method returns successfully, contains the
/// number of programs in the current application.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.ProgramInfoNotFound"/>: The calling program was not found
/// in the program registry. Something's wrong with Loader if this happens.</returns>
public Result GetProgramIndex(out int programIndex, out int programCount)
{
UnsafeHelpers.SkipParamInit(out programIndex, out programCount);
// No permissions are needed to call this method
Result rc = GetProgramInfo(out ProgramInfo programInfo, ProcessId);
if (rc.IsFailure()) return rc;
// Try to get map info for this process
Optional<ProgramIndexMapInfo> mapInfo = ServiceImpl.GetProgramIndexMapInfo(programInfo.ProgramId);
// Set the output program index if map info was found
programIndex = mapInfo.HasValue ? mapInfo.ValueRo.ProgramIndex : 0;
// Set the number of programs in the current application
programCount = ServiceImpl.GetProgramIndexMapInfoCount();
return Result.Success;
}
/// <inheritdoc cref="ProgramRegistryServiceImpl.GetProgramInfo"/>
private Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
return ServiceImpl.GetProgramInfo(out programInfo, processId);
}
}

View file

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.FsSrv.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Ncm;
@ -6,15 +7,6 @@ using LibHac.Sf;
namespace LibHac.FsSrv;
public static class ProgramRegistryImplGlobalMethods
{
public static void InitializeProgramRegistryImpl(this FileSystemServer fsSrv,
ProgramRegistryServiceImpl serviceImpl)
{
fsSrv.Globals.ProgramRegistryImpl.ServiceImpl = serviceImpl;
}
}
internal struct ProgramRegistryImplGlobals
{
public ProgramRegistryServiceImpl ServiceImpl;
@ -27,12 +19,14 @@ internal struct ProgramRegistryImplGlobals
/// is stored in a <see cref="ProgramInfo"/> and includes the process' process ID, program ID,
/// storage location and file system permissions. This allows FS to resolve the program ID and
/// verify the permissions of any process calling it.
/// <br/>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
/// <para>Based on FS 13.1.0 (nnSdk 13.4.0)</para></remarks>
public class ProgramRegistryImpl : IProgramRegistry
{
private FileSystemServer _fsServer;
private ulong _processId;
// LibHac addition
private FileSystemServer _fsServer;
private ref ProgramRegistryImplGlobals Globals => ref _fsServer.Globals.ProgramRegistryImpl;
public ProgramRegistryImpl(FileSystemServer server)
@ -47,12 +41,20 @@ public class ProgramRegistryImpl : IProgramRegistry
/// <see cref="ResultFs.InvalidArgument"/>: The process ID is already registered.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
/// <inheritdoc cref="ProgramRegistryManager.RegisterProgram"/>
public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId,
InBuffer accessControlData, InBuffer accessControlDescriptor)
public Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, InBuffer accessControlData,
long accessControlDataSize, InBuffer accessControlDescriptor, long accessControlDescriptorSize)
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
if (!_fsServer.IsInitialProgram(_processId))
return ResultFs.PermissionDenied.Log();
if (accessControlDataSize > accessControlData.Size)
return ResultFs.InvalidSize.Log();
if (accessControlDescriptorSize > accessControlDescriptor.Size)
return ResultFs.InvalidSize.Log();
return Globals.ServiceImpl.RegisterProgramInfo(processId, programId, storageId, accessControlData.Buffer,
accessControlDescriptor.Buffer);
}
@ -63,6 +65,8 @@ public class ProgramRegistryImpl : IProgramRegistry
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgram(ulong processId)
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
if (!_fsServer.IsInitialProgram(_processId))
return ResultFs.PermissionDenied.Log();
@ -72,12 +76,16 @@ public class ProgramRegistryImpl : IProgramRegistry
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfo(out programInfo, processId);
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId)
{
Assert.SdkRequiresNotNull(Globals.ServiceImpl);
return Globals.ServiceImpl.GetProgramInfoByProgramId(out programInfo, programId);
}
@ -91,4 +99,22 @@ public class ProgramRegistryImpl : IProgramRegistry
_processId = processId;
return Result.Success;
}
/// <summary>
/// Sets the <see cref="ProgramRegistryServiceImpl"/> used by the provided <see cref="FileSystemServer"/>.
/// This function must be called before calling functions on a <see cref="ProgramRegistryImpl"/>.
/// This function must not be called more than once.
/// </summary>
/// <param name="fsServer">The <see cref="FileSystemServer"/> to initialize.</param>
/// <param name="serviceImpl">The <see cref="ProgramRegistryServiceImpl"/>
/// that <paramref name="fsServer"/> will use.</param>
public static void Initialize(FileSystemServer fsServer, ProgramRegistryServiceImpl serviceImpl)
{
ref ProgramRegistryImplGlobals globals = ref fsServer.Globals.ProgramRegistryImpl;
Assert.SdkRequiresNotNull(serviceImpl);
Assert.SdkRequiresNull(globals.ServiceImpl);
globals.ServiceImpl = serviceImpl;
}
}

View file

@ -0,0 +1,193 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.Impl;
using LibHac.Ncm;
using LibHac.Sf;
using LibHac.Util;
namespace LibHac.FsSrv;
/// <summary>
/// Used to perform operations on the program index registry.
/// </summary>
/// <remarks>Appropriate methods calls on IFileSystemProxy are forwarded to this class
/// which then checks the calling process' permissions and performs the requested operation.
/// <para>Based on FS 13.1.0 (nnSdk 13.4.0)</para></remarks>
internal readonly struct ProgramIndexRegistryService
{
private readonly ProgramRegistryServiceImpl _serviceImpl;
private readonly ulong _processId;
// LibHac addition
private readonly FileSystemServer _fsServer;
public ProgramIndexRegistryService(FileSystemServer fsServer, ProgramRegistryServiceImpl serviceImpl,
ulong processId)
{
_serviceImpl = serviceImpl;
_processId = processId;
_fsServer = fsServer;
}
/// <summary>
/// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary>
/// <param name="programIndexMapInfo">A buffer containing the program map info to register.</param>
/// <param name="programCount">The number of programs to register. The provided buffer must be
/// large enough to hold this many <see cref="ProgramIndexMapInfo"/> entries.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.<br/>
/// <see cref="ResultFs.InvalidSize"/>: The buffer was too small to hold the specified
/// number of <see cref="ProgramIndexMapInfo"/> entries.</returns>
public Result RegisterProgramIndexMapInfo(InBuffer programIndexMapInfo, int programCount)
{
// Verify the caller's permissions
using (var programRegistry = new ProgramRegistryImpl(_fsServer))
{
Result rc = programRegistry.GetProgramInfo(out ProgramInfo programInfo, _processId);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.RegisterProgramIndexMapInfo))
return ResultFs.PermissionDenied.Log();
}
// Return early if the program count is 0 so we leave any previously
// registered entries as they were
if (programCount == 0)
return Result.Success;
// Verify that the provided buffer is large enough to hold "programCount" entries
ReadOnlySpan<ProgramIndexMapInfo>
mapInfo = MemoryMarshal.Cast<byte, ProgramIndexMapInfo>(programIndexMapInfo.Buffer);
if (mapInfo.Length < programCount)
return ResultFs.InvalidSize.Log();
// Register the map info
return _serviceImpl.ResetProgramIndexMapInfo(mapInfo.Slice(0, programCount));
}
/// <summary>
/// Gets the multi-program index of the calling process and the number of programs
/// in the current application.
/// </summary>
/// <param name="programIndex">When this method returns successfully, contains the
/// program index of the calling process.</param>
/// <param name="programCount">When this method returns successfully, contains the
/// number of programs in the current application.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.ProgramInfoNotFound"/>: The calling program was not found
/// in the program registry. Something's wrong with Loader if this happens.</returns>
public Result GetProgramIndex(out int programIndex, out int programCount)
{
UnsafeHelpers.SkipParamInit(out programIndex, out programCount);
// No permissions are needed to call this method
Result rc = GetProgramInfo(out ProgramInfo programInfo, _processId);
if (rc.IsFailure()) return rc;
// Try to get map info for this process
Optional<ProgramIndexMapInfo> mapInfo = _serviceImpl.GetProgramIndexMapInfo(programInfo.ProgramId);
// Set the output program index if map info was found
programIndex = mapInfo.HasValue ? mapInfo.ValueRo.ProgramIndex : 0;
// Set the number of programs in the current application
programCount = _serviceImpl.GetProgramIndexMapInfoCount();
return Result.Success;
}
/// <inheritdoc cref="ProgramRegistryServiceImpl.GetProgramInfo"/>
private Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
using var programRegistry = new ProgramRegistryImpl(_fsServer);
return programRegistry.GetProgramInfo(out programInfo, processId);
}
}
/// <summary>
/// Manages the main program registry and the multi-program registry.
/// </summary>
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
public class ProgramRegistryServiceImpl : IDisposable
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private Configuration _config;
private ProgramRegistryManager _registryManager;
private ProgramIndexMapInfoManager _programIndexManager;
public struct Configuration
{
// LibHac addition
public FileSystemServer FsServer;
}
public ProgramRegistryServiceImpl(in Configuration config)
{
_config = config;
_registryManager = new ProgramRegistryManager(_config.FsServer);
_programIndexManager = new ProgramIndexMapInfoManager();
}
public void Dispose()
{
_registryManager?.Dispose();
_programIndexManager?.Dispose();
}
/// <inheritdoc cref="ProgramRegistryManager.RegisterProgram"/>
public Result RegisterProgramInfo(ulong processId, ProgramId programId, StorageId storageId,
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{
return _registryManager.RegisterProgram(processId, programId, storageId, accessControlData,
accessControlDescriptor);
}
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgramInfo(ulong processId)
{
return _registryManager.UnregisterProgram(processId);
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
return _registryManager.GetProgramInfo(out programInfo, processId);
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId)
{
return _registryManager.GetProgramInfoByProgramId(out programInfo, programId);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Reset"/>
public Result ResetProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
return _programIndexManager.Reset(programIndexMapInfo);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/>
public Optional<ProgramIndexMapInfo> GetProgramIndexMapInfo(ProgramId programId)
{
return _programIndexManager.Get(programId);
}
/// <summary>
/// Gets the number of programs in the currently registered application.
/// </summary>
/// <returns>The number of programs.</returns>
public int GetProgramIndexMapInfoCount()
{
return _programIndexManager.GetProgramCount();
}
}

View file

@ -1,85 +0,0 @@
using System;
using LibHac.Fs;
using LibHac.FsSrv.Impl;
using LibHac.Ncm;
using LibHac.Util;
namespace LibHac.FsSrv;
/// <summary>
/// Manages the main program registry and the multi-program registry.
/// </summary>
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
public class ProgramRegistryServiceImpl
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private Configuration _config;
private ProgramRegistryManager _registryManager;
private ProgramIndexMapInfoManager _programIndexManager;
public ProgramRegistryServiceImpl(in Configuration config)
{
_config = config;
_registryManager = new ProgramRegistryManager(_config.FsServer);
_programIndexManager = new ProgramIndexMapInfoManager();
}
public struct Configuration
{
// LibHac addition
public FileSystemServer FsServer;
}
/// <inheritdoc cref="ProgramRegistryManager.RegisterProgram"/>
public Result RegisterProgramInfo(ulong processId, ProgramId programId, StorageId storageId,
ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{
return _registryManager.RegisterProgram(processId, programId, storageId, accessControlData,
accessControlDescriptor);
}
/// <inheritdoc cref="ProgramRegistryManager.UnregisterProgram" />
public Result UnregisterProgramInfo(ulong processId)
{
return _registryManager.UnregisterProgram(processId);
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfo"/>
public Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
return _registryManager.GetProgramInfo(out programInfo, processId);
}
/// <inheritdoc cref="ProgramRegistryManager.GetProgramInfoByProgramId"/>
public Result GetProgramInfoByProgramId(out ProgramInfo programInfo, ulong programId)
{
return _registryManager.GetProgramInfoByProgramId(out programInfo, programId);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.GetProgramId"/>
public ProgramId GetProgramIdByIndex(ProgramId programId, byte programIndex)
{
return _programIndexManager.GetProgramId(programId, programIndex);
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Get"/>
public Optional<ProgramIndexMapInfo> GetProgramIndexMapInfo(ProgramId programId)
{
return _programIndexManager.Get(programId);
}
/// <summary>
/// Gets the number of programs in the currently registered application.
/// </summary>
/// <returns>The number of programs.</returns>
public int GetProgramIndexMapInfoCount()
{
return _programIndexManager.GetProgramCount();
}
/// <inheritdoc cref="ProgramIndexMapInfoManager.Reset"/>
public Result RegisterProgramIndexMapInfo(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
return _programIndexManager.Reset(programIndexMapInfo);
}
}

View file

@ -6,9 +6,9 @@ namespace LibHac.FsSrv.Sf;
public interface IProgramRegistry : IDisposable
{
Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId,
InBuffer accessControlData, InBuffer accessControlDescriptor);
Result RegisterProgram(ulong processId, ProgramId programId, StorageId storageId, InBuffer accessControlData,
long accessControlDataSize, InBuffer accessControlDescriptor, long accessControlDescriptorSize);
Result UnregisterProgram(ulong processId);
Result SetCurrentProcess(ulong processId);
}
}