mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Honor permissions in OpenFileSystemWithId. Add basic AC test
This commit is contained in:
parent
3184e6ca7e
commit
6496a2c1bc
13 changed files with 304 additions and 11 deletions
|
@ -1,4 +1,5 @@
|
|||
Name,Index
|
||||
Svc,1
|
||||
Fs,2
|
||||
Loader,9
|
||||
Sf,10
|
||||
|
|
|
|
@ -1,4 +1,5 @@
|
|||
Name,Namespace,Path
|
||||
Svc,LibHac.Svc,LibHac/Svc/ResultSvc.cs
|
||||
Fs,LibHac.Fs,LibHac/Fs/ResultFs.cs
|
||||
Loader,LibHac.Loader,LibHac/Loader/ResultLoader.cs
|
||||
Sf,LibHac.Sf,LibHac/Sf/ResultSf.cs
|
||||
|
|
|
|
@ -1,4 +1,53 @@
|
|||
Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||
|
||||
1,7,,OutOfSessions,
|
||||
1,14,,InvalidArgument,
|
||||
1,33,,NotImplemented,
|
||||
1,54,,StopProcessingException,
|
||||
1,57,,NoSynchronizationObject,
|
||||
1,59,,TerminationRequested,
|
||||
1,70,,NoEvent,
|
||||
|
||||
1,101,,InvalidSize,
|
||||
1,102,,InvalidAddress,
|
||||
1,103,,OutOfResource,
|
||||
1,104,,OutOfMemory,
|
||||
1,105,,OutOfHandles,
|
||||
1,106,,InvalidCurrentMemory,
|
||||
1,108,,InvalidNewMemoryPermission,
|
||||
1,110,,InvalidMemoryRegion,
|
||||
1,112,,InvalidPriority,
|
||||
1,113,,InvalidCoreId,
|
||||
1,114,,InvalidHandle,
|
||||
1,115,,InvalidPointer,
|
||||
1,116,,InvalidCombination,
|
||||
1,117,,TimedOut,
|
||||
1,118,,Cancelled,
|
||||
1,119,,OutOfRange,
|
||||
1,120,,InvalidEnumValue,
|
||||
1,121,,NotFound,
|
||||
1,122,,Busy,
|
||||
1,123,,SessionClosed,
|
||||
1,124,,NotHandled,
|
||||
1,125,,InvalidState,
|
||||
1,126,,ReservedUsed,
|
||||
1,127,,NotSupported,
|
||||
1,128,,Debug,
|
||||
1,129,,NoThread,
|
||||
1,130,,UnknownThread,
|
||||
1,131,,PortClosed,
|
||||
1,132,,LimitReached,
|
||||
1,133,,InvalidMemoryPool,
|
||||
|
||||
1,258,,ReceiveListBroken,
|
||||
1,259,,OutOfAddressSpace,
|
||||
1,260,,MessageTooLarge,
|
||||
|
||||
1,517,,InvalidProcessId,
|
||||
1,518,,InvalidThreadId,
|
||||
1,519,,InvalidId,
|
||||
1,520,,ProcessTerminated,
|
||||
|
||||
2,0,999,HandledByAllProcess,
|
||||
2,1,,PathNotFound,Specified path does not exist
|
||||
2,2,,PathAlreadyExists,Specified path already exists
|
||||
|
|
|
|
@ -64,7 +64,7 @@ namespace LibHac.Fs
|
|||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
throw new HorizonResultException(rc, "Failed to create file system proxy service object.");
|
||||
throw new HorizonResultException(rc, "Failed to get file system proxy service object.");
|
||||
}
|
||||
|
||||
fsProxy.SetCurrentProcess(Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
|
||||
|
@ -91,7 +91,7 @@ namespace LibHac.Fs
|
|||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
throw new HorizonResultException(rc, "Failed to create file system proxy service object.");
|
||||
throw new HorizonResultException(rc, "Failed to get file system proxy service object.");
|
||||
}
|
||||
|
||||
fsProxy.SetCurrentProcess(Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
|
||||
|
@ -118,7 +118,7 @@ namespace LibHac.Fs
|
|||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
throw new HorizonResultException(rc, "Failed to create registry service object.");
|
||||
throw new HorizonResultException(rc, "Failed to get registry service object.");
|
||||
}
|
||||
|
||||
ProgramRegistry = registry;
|
||||
|
|
|
@ -45,15 +45,58 @@ namespace LibHac.FsSrv
|
|||
{
|
||||
fileSystem = default;
|
||||
|
||||
// Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter
|
||||
Result rc = GetProgramInfo(out ProgramInfo programInfo);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
bool canMountSystemDataPrivate = false;
|
||||
AccessControl ac = programInfo.AccessControl;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FileSystemProxyType.Logo:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountLogo).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
case FileSystemProxyType.Control:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountContentControl).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
case FileSystemProxyType.Manual:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountContentManual).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
case FileSystemProxyType.Meta:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountContentMeta).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
case FileSystemProxyType.Data:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountContentData).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
case FileSystemProxyType.Package:
|
||||
if (!ac.GetAccessibilityFor(AccessibilityType.MountApplicationPackage).CanRead)
|
||||
return ResultFs.PermissionDenied.Log();
|
||||
break;
|
||||
default:
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
|
||||
if (type == FileSystemProxyType.Meta)
|
||||
{
|
||||
id = ulong.MaxValue;
|
||||
}
|
||||
else if (id == ulong.MaxValue)
|
||||
{
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
|
||||
bool canMountSystemDataPrivate = ac.GetAccessibilityFor(AccessibilityType.MountSystemDataPrivate).CanRead;
|
||||
|
||||
var normalizer = new PathNormalizer(path, GetPathNormalizerOptions(path));
|
||||
if (normalizer.Result.IsFailure()) return normalizer.Result;
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
return FsProxyCore.OpenFileSystem(out fileSystem, normalizer.Path, type, canMountSystemDataPrivate, id);
|
||||
|
||||
// Missing speed emulation storage type wrapper, async wrapper, and FileSystemInterfaceAdapter
|
||||
}
|
||||
|
||||
private PathNormalizer.Option GetPathNormalizerOptions(U8Span path)
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace LibHac.FsSrv.Impl
|
|||
const int initialProcessIdLowerBound = 1;
|
||||
const int initialProcessIdUpperBound = 0x50;
|
||||
|
||||
return initialProcessIdLowerBound >= processId && processId <= initialProcessIdUpperBound;
|
||||
return initialProcessIdLowerBound <= processId && processId <= initialProcessIdUpperBound;
|
||||
}
|
||||
|
||||
internal static ProgramInfo CreateProgramInfoForInitialProcess(FileSystemServer fsServer)
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace LibHac.FsSrv.Sf
|
|||
Span<byte> str = SpanHelpers.AsByteSpan(ref fspPath);
|
||||
|
||||
// Ensure null terminator even if the creation fails for safety
|
||||
str[0x301] = 0;
|
||||
str[MaxLength] = 0;
|
||||
|
||||
var sb = new U8StringBuilder(str);
|
||||
bool overflowed = sb.Append(path).Overflowed;
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace LibHac.FsSystem
|
|||
Unsafe.SkipInit(out fsPath);
|
||||
|
||||
// Ensure null terminator even if the creation fails for safety
|
||||
fsPath.Str[0x301] = 0;
|
||||
fsPath.Str[MaxLength] = 0;
|
||||
|
||||
var sb = new U8StringBuilder(fsPath.Str);
|
||||
bool overflowed = sb.Append(path).Overflowed;
|
||||
|
|
3
src/LibHac/InternalsVisibleToTests.cs
Normal file
3
src/LibHac/InternalsVisibleToTests.cs
Normal file
|
@ -0,0 +1,3 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("LibHac.Tests")]
|
|
@ -2,7 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Sf;
|
||||
using LibHac.Svc;
|
||||
|
||||
namespace LibHac.Sm
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace LibHac.Sm
|
|||
|
||||
if (!Services.TryGetValue(serviceName, out IServiceObject service))
|
||||
{
|
||||
return ResultSf.RequestDeferredByUser.Log();
|
||||
return ResultSvc.NotFound.Log();
|
||||
}
|
||||
|
||||
return service.GetServiceObject(out serviceObject);
|
||||
|
|
107
src/LibHac/Svc/ResultSvc.cs
Normal file
107
src/LibHac/Svc/ResultSvc.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This file was automatically generated.
|
||||
// Changes to this file will be lost when the file is regenerated.
|
||||
//
|
||||
// To change this file, modify /build/CodeGen/results.csv at the root of this
|
||||
// repo and run the build script.
|
||||
//
|
||||
// The script can be run with the "codegen" option to run only the
|
||||
// code generation portion of the build.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace LibHac.Svc
|
||||
{
|
||||
public static class ResultSvc
|
||||
{
|
||||
public const int ModuleSvc = 1;
|
||||
|
||||
/// <summary>Error code: 2001-0007; Inner value: 0xe01</summary>
|
||||
public static Result.Base OutOfSessions => new Result.Base(ModuleSvc, 7);
|
||||
/// <summary>Error code: 2001-0014; Inner value: 0x1c01</summary>
|
||||
public static Result.Base InvalidArgument => new Result.Base(ModuleSvc, 14);
|
||||
/// <summary>Error code: 2001-0033; Inner value: 0x4201</summary>
|
||||
public static Result.Base NotImplemented => new Result.Base(ModuleSvc, 33);
|
||||
/// <summary>Error code: 2001-0054; Inner value: 0x6c01</summary>
|
||||
public static Result.Base StopProcessingException => new Result.Base(ModuleSvc, 54);
|
||||
/// <summary>Error code: 2001-0057; Inner value: 0x7201</summary>
|
||||
public static Result.Base NoSynchronizationObject => new Result.Base(ModuleSvc, 57);
|
||||
/// <summary>Error code: 2001-0059; Inner value: 0x7601</summary>
|
||||
public static Result.Base TerminationRequested => new Result.Base(ModuleSvc, 59);
|
||||
/// <summary>Error code: 2001-0070; Inner value: 0x8c01</summary>
|
||||
public static Result.Base NoEvent => new Result.Base(ModuleSvc, 70);
|
||||
/// <summary>Error code: 2001-0101; Inner value: 0xca01</summary>
|
||||
public static Result.Base InvalidSize => new Result.Base(ModuleSvc, 101);
|
||||
/// <summary>Error code: 2001-0102; Inner value: 0xcc01</summary>
|
||||
public static Result.Base InvalidAddress => new Result.Base(ModuleSvc, 102);
|
||||
/// <summary>Error code: 2001-0103; Inner value: 0xce01</summary>
|
||||
public static Result.Base OutOfResource => new Result.Base(ModuleSvc, 103);
|
||||
/// <summary>Error code: 2001-0104; Inner value: 0xd001</summary>
|
||||
public static Result.Base OutOfMemory => new Result.Base(ModuleSvc, 104);
|
||||
/// <summary>Error code: 2001-0105; Inner value: 0xd201</summary>
|
||||
public static Result.Base OutOfHandles => new Result.Base(ModuleSvc, 105);
|
||||
/// <summary>Error code: 2001-0106; Inner value: 0xd401</summary>
|
||||
public static Result.Base InvalidCurrentMemory => new Result.Base(ModuleSvc, 106);
|
||||
/// <summary>Error code: 2001-0108; Inner value: 0xd801</summary>
|
||||
public static Result.Base InvalidNewMemoryPermission => new Result.Base(ModuleSvc, 108);
|
||||
/// <summary>Error code: 2001-0110; Inner value: 0xdc01</summary>
|
||||
public static Result.Base InvalidMemoryRegion => new Result.Base(ModuleSvc, 110);
|
||||
/// <summary>Error code: 2001-0112; Inner value: 0xe001</summary>
|
||||
public static Result.Base InvalidPriority => new Result.Base(ModuleSvc, 112);
|
||||
/// <summary>Error code: 2001-0113; Inner value: 0xe201</summary>
|
||||
public static Result.Base InvalidCoreId => new Result.Base(ModuleSvc, 113);
|
||||
/// <summary>Error code: 2001-0114; Inner value: 0xe401</summary>
|
||||
public static Result.Base InvalidHandle => new Result.Base(ModuleSvc, 114);
|
||||
/// <summary>Error code: 2001-0115; Inner value: 0xe601</summary>
|
||||
public static Result.Base InvalidPointer => new Result.Base(ModuleSvc, 115);
|
||||
/// <summary>Error code: 2001-0116; Inner value: 0xe801</summary>
|
||||
public static Result.Base InvalidCombination => new Result.Base(ModuleSvc, 116);
|
||||
/// <summary>Error code: 2001-0117; Inner value: 0xea01</summary>
|
||||
public static Result.Base TimedOut => new Result.Base(ModuleSvc, 117);
|
||||
/// <summary>Error code: 2001-0118; Inner value: 0xec01</summary>
|
||||
public static Result.Base Cancelled => new Result.Base(ModuleSvc, 118);
|
||||
/// <summary>Error code: 2001-0119; Inner value: 0xee01</summary>
|
||||
public static Result.Base OutOfRange => new Result.Base(ModuleSvc, 119);
|
||||
/// <summary>Error code: 2001-0120; Inner value: 0xf001</summary>
|
||||
public static Result.Base InvalidEnumValue => new Result.Base(ModuleSvc, 120);
|
||||
/// <summary>Error code: 2001-0121; Inner value: 0xf201</summary>
|
||||
public static Result.Base NotFound => new Result.Base(ModuleSvc, 121);
|
||||
/// <summary>Error code: 2001-0122; Inner value: 0xf401</summary>
|
||||
public static Result.Base Busy => new Result.Base(ModuleSvc, 122);
|
||||
/// <summary>Error code: 2001-0123; Inner value: 0xf601</summary>
|
||||
public static Result.Base SessionClosed => new Result.Base(ModuleSvc, 123);
|
||||
/// <summary>Error code: 2001-0124; Inner value: 0xf801</summary>
|
||||
public static Result.Base NotHandled => new Result.Base(ModuleSvc, 124);
|
||||
/// <summary>Error code: 2001-0125; Inner value: 0xfa01</summary>
|
||||
public static Result.Base InvalidState => new Result.Base(ModuleSvc, 125);
|
||||
/// <summary>Error code: 2001-0126; Inner value: 0xfc01</summary>
|
||||
public static Result.Base ReservedUsed => new Result.Base(ModuleSvc, 126);
|
||||
/// <summary>Error code: 2001-0127; Inner value: 0xfe01</summary>
|
||||
public static Result.Base NotSupported => new Result.Base(ModuleSvc, 127);
|
||||
/// <summary>Error code: 2001-0128; Inner value: 0x10001</summary>
|
||||
public static Result.Base Debug => new Result.Base(ModuleSvc, 128);
|
||||
/// <summary>Error code: 2001-0129; Inner value: 0x10201</summary>
|
||||
public static Result.Base NoThread => new Result.Base(ModuleSvc, 129);
|
||||
/// <summary>Error code: 2001-0130; Inner value: 0x10401</summary>
|
||||
public static Result.Base UnknownThread => new Result.Base(ModuleSvc, 130);
|
||||
/// <summary>Error code: 2001-0131; Inner value: 0x10601</summary>
|
||||
public static Result.Base PortClosed => new Result.Base(ModuleSvc, 131);
|
||||
/// <summary>Error code: 2001-0132; Inner value: 0x10801</summary>
|
||||
public static Result.Base LimitReached => new Result.Base(ModuleSvc, 132);
|
||||
/// <summary>Error code: 2001-0133; Inner value: 0x10a01</summary>
|
||||
public static Result.Base InvalidMemoryPool => new Result.Base(ModuleSvc, 133);
|
||||
/// <summary>Error code: 2001-0258; Inner value: 0x20401</summary>
|
||||
public static Result.Base ReceiveListBroken => new Result.Base(ModuleSvc, 258);
|
||||
/// <summary>Error code: 2001-0259; Inner value: 0x20601</summary>
|
||||
public static Result.Base OutOfAddressSpace => new Result.Base(ModuleSvc, 259);
|
||||
/// <summary>Error code: 2001-0260; Inner value: 0x20801</summary>
|
||||
public static Result.Base MessageTooLarge => new Result.Base(ModuleSvc, 260);
|
||||
/// <summary>Error code: 2001-0517; Inner value: 0x40a01</summary>
|
||||
public static Result.Base InvalidProcessId => new Result.Base(ModuleSvc, 517);
|
||||
/// <summary>Error code: 2001-0518; Inner value: 0x40c01</summary>
|
||||
public static Result.Base InvalidThreadId => new Result.Base(ModuleSvc, 518);
|
||||
/// <summary>Error code: 2001-0519; Inner value: 0x40e01</summary>
|
||||
public static Result.Base InvalidId => new Result.Base(ModuleSvc, 519);
|
||||
/// <summary>Error code: 2001-0520; Inner value: 0x41001</summary>
|
||||
public static Result.Base ProcessTerminated => new Result.Base(ModuleSvc, 520);
|
||||
}
|
||||
}
|
64
tests/LibHac.Tests/FsSrv/AccessControlTests.cs
Normal file
64
tests/LibHac.Tests/FsSrv/AccessControlTests.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.Ncm;
|
||||
using Xunit;
|
||||
using ContentType = LibHac.Fs.ContentType;
|
||||
|
||||
namespace LibHac.Tests.FsSrv
|
||||
{
|
||||
public class AccessControlTests
|
||||
{
|
||||
[Fact]
|
||||
public void OpenFileSystemWithNoPermissions_ReturnsPermissionDenied()
|
||||
{
|
||||
Horizon hos = HorizonFactory.CreateBasicHorizon();
|
||||
|
||||
HorizonClient regClient = hos.CreatePrivilegedHorizonClient();
|
||||
HorizonClient client = hos.CreateHorizonClient();
|
||||
|
||||
var dataHeader = new AccessControlDataHeader();
|
||||
var descriptor = new AccessControlDescriptor();
|
||||
|
||||
descriptor.Version = 123;
|
||||
dataHeader.Version = 123;
|
||||
|
||||
descriptor.AccessFlags = (ulong)AccessControlBits.Bits.None;
|
||||
dataHeader.AccessFlags = (ulong)AccessControlBits.Bits.None;
|
||||
|
||||
Assert.Success(regClient.Fs.RegisterProgram(client.ProcessId.Value, new ProgramId(123),
|
||||
StorageId.BuiltInUser, SpanHelpers.AsReadOnlyByteSpan(in dataHeader),
|
||||
SpanHelpers.AsReadOnlyByteSpan(in descriptor)));
|
||||
|
||||
Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Control);
|
||||
Assert.Result(ResultFs.PermissionDenied, rc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenFileSystemWithPermissions_ReturnsInvalidNcaMountPoint()
|
||||
{
|
||||
Horizon hos = HorizonFactory.CreateBasicHorizon();
|
||||
|
||||
HorizonClient regClient = hos.CreatePrivilegedHorizonClient();
|
||||
HorizonClient client = hos.CreateHorizonClient();
|
||||
|
||||
var dataHeader = new AccessControlDataHeader();
|
||||
var descriptor = new AccessControlDescriptor();
|
||||
|
||||
descriptor.Version = 123;
|
||||
dataHeader.Version = 123;
|
||||
|
||||
descriptor.AccessFlags = (ulong)AccessControlBits.Bits.ApplicationInfo;
|
||||
dataHeader.AccessFlags = (ulong)AccessControlBits.Bits.ApplicationInfo;
|
||||
|
||||
Assert.Success(regClient.Fs.RegisterProgram(client.ProcessId.Value, new ProgramId(123),
|
||||
StorageId.BuiltInUser, SpanHelpers.AsReadOnlyByteSpan(in dataHeader),
|
||||
SpanHelpers.AsReadOnlyByteSpan(in descriptor)));
|
||||
|
||||
// We should get InvalidNcaMountPoint because mounting NCAs from @System isn't allowed
|
||||
Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Control);
|
||||
Assert.Result(ResultFs.InvalidNcaMountPoint, rc);
|
||||
}
|
||||
}
|
||||
}
|
25
tests/LibHac.Tests/HorizonFactory.cs
Normal file
25
tests/LibHac.Tests/HorizonFactory.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSrv;
|
||||
|
||||
namespace LibHac.Tests
|
||||
{
|
||||
public static class HorizonFactory
|
||||
{
|
||||
public static Horizon CreateBasicHorizon()
|
||||
{
|
||||
IFileSystem rootFs = new InMemoryFileSystem();
|
||||
|
||||
var defaultObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(rootFs, new Keyset());
|
||||
|
||||
var config = new FileSystemServerConfig();
|
||||
config.FsCreators = defaultObjects.FsCreators;
|
||||
config.DeviceOperator = defaultObjects.DeviceOperator;
|
||||
config.ExternalKeySet = new ExternalKeySet();
|
||||
|
||||
var horizon = new Horizon(new StopWatchTimeSpanGenerator(), config);
|
||||
|
||||
return horizon;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue