Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
HostWriter error checks and unit tests
  • Loading branch information
elinor-fung committed Jul 11, 2024
commit 41bac52a35db896cbb0448d0248a713e12da0b7d
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,32 @@ internal AppNameTooLongException(string name)
LongName = name;
}
}

/// <summary>
/// App-relative .NET path is an absolute path
/// </summary>
public sealed class AppRelativePathRootedException : AppHostUpdateException
{
public string Path { get; }

internal AppRelativePathRootedException(string path)
: base($"The app-relative .NET path should not be an absolute path. Path: {path}")
{
Path = path;
}
}

/// <summary>
/// App-relative .NET path is too long to be embedded in the apphost
/// </summary>
public sealed class AppRelativePathTooLongException : AppHostUpdateException
{
public string Path { get; }

internal AppRelativePathTooLongException(string path)
: base($"The app-relative .NET path is too long (must be less than 509 bytes). Path: {path}")
{
Path = path;
}
}
}
40 changes: 26 additions & 14 deletions src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,9 @@ public static void CreateAppHost(
throw new AppNameTooLongException(appBinaryFilePath);
}

byte[] searchOptionsBytes = null;
if (dotNetSearchOptions != null)
{
byte[] bytes = dotNetSearchOptions.AppRelativeDotNet != null
? Encoding.UTF8.GetBytes(dotNetSearchOptions.AppRelativeDotNet)
: [];

// <search_location> 0 <app_relative_dotnet_root>
searchOptionsBytes = new byte[bytes.Length + 2];
searchOptionsBytes[0] = (byte)dotNetSearchOptions.Location;
searchOptionsBytes[1] = 0;
if (bytes.Length > 0)
bytes.CopyTo(searchOptionsBytes, 2);
}
byte[] searchOptionsBytes = dotNetSearchOptions != null
? GetSearchOptionBytes(dotNetSearchOptions)
: null;

bool appHostIsPEImage = false;

Expand Down Expand Up @@ -284,6 +273,29 @@ void FindBundleHeader()
return headerOffset != 0;
}

private static byte[] GetSearchOptionBytes(DotNetSearchOptions searchOptions)
{
if (Path.IsPathRooted(searchOptions.AppRelativeDotNet))
throw new AppRelativePathRootedException(searchOptions.AppRelativeDotNet);

byte[] pathBytes = searchOptions.AppRelativeDotNet != null
? Encoding.UTF8.GetBytes(searchOptions.AppRelativeDotNet)
: [];

if (pathBytes.Length + 3 > 512)
throw new AppRelativePathTooLongException(searchOptions.AppRelativeDotNet);

// <search_location> 0 <app_relative_dotnet_root> 0
byte[] searchOptionsBytes = new byte[pathBytes.Length + 3];
searchOptionsBytes[0] = (byte)searchOptions.Location;
searchOptionsBytes[1] = 0;
searchOptionsBytes[searchOptionsBytes.Length - 1] = 0;
if (pathBytes.Length > 0)
pathBytes.CopyTo(searchOptionsBytes, 2);

return searchOptionsBytes;
}

[LibraryImport("libc", SetLastError = true)]
private static partial int chmod([MarshalAs(UnmanagedType.LPStr)] string pathname, int mode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public class CreateAppHost
private const string AppBinaryPathPlaceholder = "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2";
private readonly static byte[] AppBinaryPathPlaceholderSearchValue = Encoding.UTF8.GetBytes(AppBinaryPathPlaceholder);

/// <summary>
/// Value embedded in default apphost executable for configuration of how it will search for the .NET install
/// </summary>
private const string DotNetSearchPlaceholder = "\0\019ff3e9c3602ae8e841925bb461a0adb064a1f1903667a5e0d87e8f608f425ac";
private static readonly byte[] DotNetSearchPlaceholderValue = Encoding.UTF8.GetBytes(DotNetSearchPlaceholder);

[Fact]
public void EmbedAppBinaryPath()
{
Expand Down Expand Up @@ -96,6 +102,54 @@ public void AppBinaryPathTooLong_Fails()
}
}

[Fact]
public void AppRelativePathRooted_Fails()
{
using (TestArtifact artifact = CreateTestDirectory())
{
string sourceAppHostMock = PrepareAppHostMockFile(artifact.Location);
string destinationFilePath = Path.Combine(artifact.Location, "DestinationAppHost.exe.mock");
HostWriter.DotNetSearchOptions options = new()
{
Location = HostWriter.DotNetSearchOptions.SearchLocation.AppRelative,
AppRelativeDotNet = artifact.Location
};

Assert.Throws<AppRelativePathRootedException>(() =>
HostWriter.CreateAppHost(
sourceAppHostMock,
destinationFilePath,
"app.dll",
dotNetSearchOptions: options));

File.Exists(destinationFilePath).Should().BeFalse();
}
}

[Fact]
public void AppRelativePathTooLong_Fails()
{
using (TestArtifact artifact = CreateTestDirectory())
{
string sourceAppHostMock = PrepareAppHostMockFile(artifact.Location);
string destinationFilePath = Path.Combine(artifact.Location, "DestinationAppHost.exe.mock");
HostWriter.DotNetSearchOptions options = new()
{
Location = HostWriter.DotNetSearchOptions.SearchLocation.AppRelative,
AppRelativeDotNet = new string('p', 1024)
};

Assert.Throws<AppRelativePathTooLongException>(() =>
HostWriter.CreateAppHost(
sourceAppHostMock,
destinationFilePath,
"app.dll",
dotNetSearchOptions: options));

File.Exists(destinationFilePath).Should().BeFalse();
}
}

[Fact]
public void GUISubsystem_WindowsPEFile()
{
Expand Down Expand Up @@ -399,11 +453,11 @@ private string PrepareAppHostMockFile(string directory, Action<byte[]> customize
// The only customization which we do on non-Windows files is the embedding
// of the binary path, which works the same regardless of the file format.

int size = WindowsFileHeader.Length + AppBinaryPathPlaceholderSearchValue.Length;
int size = WindowsFileHeader.Length + AppBinaryPathPlaceholderSearchValue.Length + DotNetSearchPlaceholderValue.Length;
byte[] content = new byte[size];
Array.Copy(WindowsFileHeader, 0, content, 0, WindowsFileHeader.Length);
Array.Copy(AppBinaryPathPlaceholderSearchValue, 0, content, WindowsFileHeader.Length, AppBinaryPathPlaceholderSearchValue.Length);

Array.Copy(DotNetSearchPlaceholderValue, 0, content, WindowsFileHeader.Length + AppBinaryPathPlaceholderSearchValue.Length, DotNetSearchPlaceholderValue.Length);
customize?.Invoke(content);

string filePath = Path.Combine(directory, "SourceAppHost.exe.mock");
Expand Down