diff --git a/src/Runner.Sdk/ProcessInvoker.cs b/src/Runner.Sdk/ProcessInvoker.cs index 7270faf5dc9..1b4dbd7dcae 100644 --- a/src/Runner.Sdk/ProcessInvoker.cs +++ b/src/Runner.Sdk/ProcessInvoker.cs @@ -871,6 +871,14 @@ private void NixKillProcessTree() #if OS_LINUX private void WriteProcessOomScoreAdj(int processId, int oomScoreAdj) { + var disableOomScoreAdj = Environment.GetEnvironmentVariable("ACTIONS_RUNNER_DISABLE_OOM_SCORE_ADJ"); + if (string.Equals(disableOomScoreAdj, "true", StringComparison.OrdinalIgnoreCase) || + string.Equals(disableOomScoreAdj, "1", StringComparison.OrdinalIgnoreCase)) + { + Trace.Verbose("Skipping oom_score_adj write: ACTIONS_RUNNER_DISABLE_OOM_SCORE_ADJ is set (unprivileged container)."); + return; + } + try { string procFilePath = $"/proc/{processId}/oom_score_adj"; diff --git a/src/Test/L0/ProcessInvokerL0.cs b/src/Test/L0/ProcessInvokerL0.cs index dc3629e67aa..011a57ae31d 100644 --- a/src/Test/L0/ProcessInvokerL0.cs +++ b/src/Test/L0/ProcessInvokerL0.cs @@ -510,6 +510,53 @@ public async Task OomScoreAdjIsInherited() } } } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public async Task OomScoreAdjIsSkipped_WhenDisableEnvVarSet() + { + // Unprivileged containers (e.g. ARC runners) cannot write to /proc//oom_score_adj. + // ACTIONS_RUNNER_DISABLE_OOM_SCORE_ADJ suppresses the write entirely so no exception is raised. + string testProcPath = $"/proc/{Process.GetCurrentProcess().Id}/oom_score_adj"; + if (File.Exists(testProcPath)) + { + Environment.SetEnvironmentVariable("ACTIONS_RUNNER_DISABLE_OOM_SCORE_ADJ", "true"); + try + { + using (TestHostContext hc = new(this)) + using (var tokenSource = new CancellationTokenSource()) + { + Tracing trace = hc.GetTrace(); + var processInvoker = new ProcessInvokerWrapper(); + processInvoker.Initialize(hc); + int oomScoreAdj = -9999; + processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => + { + oomScoreAdj = int.Parse(e.Data); + tokenSource.Cancel(); + }; + try + { + // The child process should inherit the parent's oom_score_adj unchanged (not 500). + int parentOomScore = int.Parse(File.ReadAllText(testProcPath).Trim()); + var proc = await processInvoker.ExecuteAsync("", "bash", "-c \"cat /proc/$$/oom_score_adj\"", null, false, null, false, null, false, false, + highPriorityProcess: false, + cancellationToken: tokenSource.Token); + Assert.Equal(parentOomScore, oomScoreAdj); + } + catch (OperationCanceledException) + { + trace.Info("Caught expected OperationCanceledException"); + } + } + } + finally + { + Environment.SetEnvironmentVariable("ACTIONS_RUNNER_DISABLE_OOM_SCORE_ADJ", null); + } + } + } #endif } }