Skip to content

Commit

Permalink
Make host tests enable test-only behaviour for nethost before first u…
Browse files Browse the repository at this point in the history
…se (#107170)

On macOS with system integrity protection enabled, if a code-signed binary is loaded in a process, modified, and loaded again in another process, the second run will crash with Code Signature Invalid).

Enabling test-only behaviour modifies the binary (re-writes a placeholder value). The nethost tests were enabling/disabling test-only behaviour for the same nethost binary used by all the tests. This change updates the tests to just always enable it before any use of the binary.
  • Loading branch information
elinor-fung authored Aug 30, 2024
1 parent 2297f60 commit 48ab86a
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 23 deletions.
37 changes: 17 additions & 20 deletions src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ public void GetHostFxrPath_DotNetRootParameter(bool explicitLoad, bool useAssemb
}

[Theory]
[ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[InlineData(true, false, true, false)]
[InlineData(true, false, true, true)]
[InlineData(true, false, false, false)]
Expand Down Expand Up @@ -183,7 +182,6 @@ public void GetHostFxrPath_HostFxrAlreadyLoaded()
}

[Theory]
[ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
[InlineData("{0}", false, true)]
[InlineData("{0}\n", false, true)]
Expand Down Expand Up @@ -249,7 +247,6 @@ public void GetHostFxrPath_InstallLocationFile(string value, bool shouldUseArchS
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
public void GetHostFxrPath_GlobalInstallation_HasNoDefaultInstallationPath()
{
Expand Down Expand Up @@ -280,7 +277,6 @@ public void GetHostFxrPath_GlobalInstallation_HasNoDefaultInstallationPath()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/61131", TestPlatforms.OSX)]
[SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
public void GetHostFxrPath_GlobalInstallation_ArchitectureSpecificPathIsPickedOverDefaultPath()
{
Expand Down Expand Up @@ -342,22 +338,23 @@ public void TracingNotBufferedByDefault()
[Fact]
public void TestOnlyDisabledByDefault()
{
// Intentionally not enabling test-only behavior. This test validates that even if the test-only env. variable is set
// it will not take effect on its own by default.
// To make sure the test is reliable, copy the product binary again into the test folder where we run it from.
// This is to make sure that we're using the unmodified product binary. If some previous test
// enabled test-only product behavior on the binary and didn't correctly cleanup, this test would fail.
File.Copy(
Binaries.NetHost.FilePath,
sharedState.NethostPath,
overwrite: true);

Command.Create(sharedState.NativeHostPath, GetHostFxrPath)
.EnableTracingAndCaptureOutputs()
.EnvironmentVariable(Constants.TestOnlyEnvironmentVariables.GloballyRegisteredPath, sharedState.ValidInstallRoot)
.DotNetRoot(null)
.Execute()
.Should().NotHaveStdErrContaining($"Using global install location [{sharedState.ValidInstallRoot}] as runtime location.");
using (TestArtifact artifact = TestArtifact.Create(nameof(TestOnlyDisabledByDefault)))
{
// Copy the native host and unmodified nethost product binary into a new test folder
string nativeHostPath = Path.Combine(artifact.Location, Path.GetFileName(sharedState.NativeHostPath));
File.Copy(sharedState.NativeHostPath, nativeHostPath);

// Intentionally not enabling test-only behavior. This test validates that even if the test-only env. variable is set
// it will not take effect on its own by default.
File.Copy(Binaries.NetHost.FilePath, Path.Combine(artifact.Location, Binaries.NetHost.FileName));

Command.Create(nativeHostPath, GetHostFxrPath)
.EnableTracingAndCaptureOutputs()
.EnvironmentVariable(Constants.TestOnlyEnvironmentVariables.GloballyRegisteredPath, sharedState.ValidInstallRoot)
.DotNetRoot(null)
.Execute()
.Should().NotHaveStdErrContaining($"Using global install location [{sharedState.ValidInstallRoot}] as runtime location.");
}
}

public class SharedTestState : SharedTestStateBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ public SharedTestStateBase()
// user-friendly way of linking against nethost (instead of dlopen/LoadLibrary and dlsym/GetProcAddress).
// On Windows, we can delay load through a linker option, but on other platforms load is required on start.
NethostPath = Path.Combine(Path.GetDirectoryName(NativeHostPath), Binaries.NetHost.FileName);
File.Copy(
Binaries.NetHost.FilePath,
NethostPath);
File.Copy(Binaries.NetHost.FilePath, NethostPath);

// Enable test-only behaviour for nethost. We always do this - even for tests that don't need the behaviour.
// On macOS with system integrity protection enabled, if a code-signed binary is loaded, modified (test-only
// behaviour rewrites part of the binary), and loaded again, the process will crash (Code Signature Invalid).
// We don't bother disabling it later, as we just delete the containing folder after tests run.
_ = TestOnlyProductBehavior.Enable(NethostPath);
}

public Command CreateNativeHostCommand(IEnumerable<string> args, string dotNetRoot)
Expand Down

0 comments on commit 48ab86a

Please sign in to comment.