Skip to content

Commit e855dfe

Browse files
committed
Merged PR 741487: Make execute permission configurable and disable it for BXL internal repo
Introduced a flag to enable/disable explicit setting of the execute permissions bit for the root process in linux builds. Added a condition to explicitly set this bit for node and dotnet in the extractor. This is done to obtain more information about the linux permissions bug. Related work items: #2104538
1 parent fc6f339 commit e855dfe

File tree

17 files changed

+92
-62
lines changed

17 files changed

+92
-62
lines changed

.azdo/linux/job-ptrace.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
# This step currently only builds selfhost with the --minimal flag, but will be extended in the future to run more unit tests with ptrace
9797
- bash: |
9898
set -eu
99-
bash bxl.sh /ado /cacheMiss:"[Bxl.Selfhost.Linux.PTrace]" /logObservedFileAccesses /cacheConfigFilePath:Out/CacheConfig.json /logoutput:FullOutputOnError /logsToRetain:10 /exp:lazysodeletion- /logsDirectory:"Out/Logs/Build" --minimal --internal --use-dev "/p:BUILDXL_FINGERPRINT_SALT='Bxl.Selfhost.Linux.PTrace.CasingPR'" /forceEnableLinuxPTraceSandbox+ /injectCacheMisses:0.3
99+
bash bxl.sh /ado /cacheMiss:"[Bxl.Selfhost.Linux.PTrace]" /logObservedFileAccesses /cacheConfigFilePath:Out/CacheConfig.json /logoutput:FullOutputOnError /logsToRetain:10 /exp:lazysodeletion- /logsDirectory:"Out/Logs/Build" --minimal --internal --use-dev /forceEnableLinuxPTraceSandbox+ /injectCacheMisses:0.3
100100
displayName: Build BXL with LKG and PTrace
101101
workingDirectory: /home/subst
102102
env:

.azdo/linux/job-selfhost.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ jobs:
149149
# - the disks on Azure Pipeline VMs are too small to build everything, so let's instead run tests
150150
# - we also disable early worker release to avoid releasing a worker before attachment, which tends to happen
151151
# when the build is highly cached: the intention is to have as much of a distributed build as possible for validation purposes
152-
./bxl.sh --use-dev --use-adobuildrunner ${{ parameters.BxlCommonArgs }} /logsDirectory:"Out/Logs/${{ parameters.validationName }}" ${{ parameters.bxlExtraArgs }} "/f:tag='test' /p:BUILDXL_FINGERPRINT_SALT='PrPipelineSalt_20230825'" /earlyWorkerRelease- /p:BuildXLWorkerAttachTimeoutMin=10 /logToKusto /logToKustoBlobUri:https://adomessages.blob.core.windows.net/adomessages /logToKustoIdentityId:6e0959cf-a9ba-4988-bbf1-7facd9deda51 /logToKustoTenantId:975f013f-7f24-47e8-a7d3-abc4752bf346 /historicMetadataCache-
152+
./bxl.sh --use-dev --use-adobuildrunner ${{ parameters.BxlCommonArgs }} /logsDirectory:"Out/Logs/${{ parameters.validationName }}" ${{ parameters.bxlExtraArgs }} "/f:tag='test'" /earlyWorkerRelease- /p:BuildXLWorkerAttachTimeoutMin=10 /logToKusto /logToKustoBlobUri:https://adomessages.blob.core.windows.net/adomessages /logToKustoIdentityId:6e0959cf-a9ba-4988-bbf1-7facd9deda51 /logToKustoTenantId:975f013f-7f24-47e8-a7d3-abc4752bf346 /historicMetadataCache-
153153
displayName: Test (${{ parameters.validationName }})
154154
workingDirectory: /home/subst
155155
env:

Public/Src/App/Bxl/Args.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ public bool TryParse(string[] args, PathTable pathTable, out ICommandLineConfigu
381381
OptionHandlerFactory.CreateBoolOption(
382382
"disableIsObsoleteCheckDuringConversion",
383383
sign => frontEndConfiguration.DisableIsObsoleteCheckDuringConversion = sign),
384+
OptionHandlerFactory.CreateBoolOption(
385+
"forceAddExecutionPermission",
386+
sign => sandboxConfiguration.ForceAddExecutionPermission = sign),
384387
OptionHandlerFactory.CreateOption2(
385388
"distributedBuildRole",
386389
"dbr",

Public/Src/App/Bxl/HelpText.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,12 @@ public static void DisplayHelp(HelpLevel helpLevel)
922922
HelpLevel.Verbose
923923
);
924924

925+
hw.WriteOption(
926+
"/forceAddExecutionPermission[+|-]",
927+
Strings.HelpText_DisplayHelp_ForceAddExecutionPermission,
928+
HelpLevel.Verbose
929+
);
930+
925931
#endregion
926932

927933
hw.WriteBanner(

Public/Src/App/Bxl/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,4 +1168,7 @@ Example: ad2d42d2ec5d2ca0c0b7ad65402d07c7ef40b91e</value>
11681168
<data name="HelpText_DisplayHelp_EnableVerboseProcessLogging" xml:space="preserve">
11691169
<value>Enables verbose sandbox logging for specific pips based on their formatted semistable hashes. This is tantamount to switching /logObservedFileAccesses and /logProcesses for these pips, and also enabling verbose debug logging in the sandbox. A list of semistable hashes might be specified, separated by semicolons. If the special value "*" is given, sandbox logging will be enabled for every pip. Example: /debug_enableVerboseProcessLogging:Pip3855A4C7E1E820D0;PipE9638AD7DDD6AF67</value>
11701170
</data>
1171+
<data name="HelpText_DisplayHelp_ForceAddExecutionPermission" xml:space="preserve">
1172+
<value>When set to true, it enables the execution permission for the root process of process pips in Linux builds. Defaults to true.</value>
1173+
</data>
11711174
</root>

Public/Src/Engine/ProcessPipExecutor/SandboxedProcessPipExecutor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,8 @@ public async Task<SandboxedProcessPipExecutionResult> RunAsync(
837837
sandboxConnection: sandboxConnection,
838838
sidebandWriter: sidebandWriter,
839839
detoursEventListener: m_detoursListener,
840-
fileSystemView: fileSystemView)
840+
fileSystemView: fileSystemView,
841+
forceAddExecutionPermission: m_sandboxConfig.ForceAddExecutionPermission)
841842
{
842843
Arguments = arguments,
843844
WorkingDirectory = m_workingDirectory,

Public/Src/Engine/Processes/SandboxedProcessInfo.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ public SandboxedProcessInfo(
132132
IDetoursEventListener? detoursEventListener = null,
133133
ISandboxConnection? sandboxConnection = null,
134134
bool createJobObjectForCurrentProcess = true,
135-
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null)
135+
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null,
136+
bool forceAddExecutionPermission = true)
136137
: this(
137138
new PathTable(),
138139
fileStorage,
@@ -143,7 +144,8 @@ public SandboxedProcessInfo(
143144
detoursEventListener,
144145
sandboxConnection,
145146
createJobObjectForCurrentProcess: createJobObjectForCurrentProcess,
146-
monitoringConfig: monitoringConfig)
147+
monitoringConfig: monitoringConfig,
148+
forceAddExecutionPermission: forceAddExecutionPermission)
147149
{
148150
}
149151

@@ -163,7 +165,8 @@ public SandboxedProcessInfo(
163165
SidebandWriter? sidebandWriter = null,
164166
bool createJobObjectForCurrentProcess = true,
165167
ISandboxFileSystemView? fileSystemView = null,
166-
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null)
168+
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null,
169+
bool forceAddExecutionPermission = true)
167170
{
168171
PathTable = pathTable;
169172
FileAccessManifest = fileAccessManifest ?? new FileAccessManifest(pathTable);
@@ -182,6 +185,7 @@ public SandboxedProcessInfo(
182185
CreateJobObjectForCurrentProcess = createJobObjectForCurrentProcess;
183186
FileSystemView = fileSystemView;
184187
MonitoringConfig = monitoringConfig;
188+
ForceAddExecutionPermission = forceAddExecutionPermission;
185189
}
186190

187191
/// <summary>
@@ -198,7 +202,8 @@ public SandboxedProcessInfo(
198202
ISandboxConnection? sandboxConnection = null,
199203
FileAccessManifest? fileAccessManifest = null,
200204
bool createJobObjectForCurrentProcess = true,
201-
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null
205+
SandboxedProcessResourceMonitoringConfig? monitoringConfig = null,
206+
bool forceAddExecutionPermission = true
202207
)
203208
: this(
204209
pathTable,
@@ -211,7 +216,8 @@ public SandboxedProcessInfo(
211216
detoursEventListener,
212217
sandboxConnection,
213218
createJobObjectForCurrentProcess: createJobObjectForCurrentProcess,
214-
monitoringConfig: monitoringConfig)
219+
monitoringConfig: monitoringConfig,
220+
forceAddExecutionPermission: forceAddExecutionPermission)
215221
{
216222
}
217223

@@ -291,6 +297,11 @@ public SandboxedProcessInfo(
291297
/// </remarks>
292298
public int NumRetriesPipeReadOnCancel { get; set; } = DefaultPipeReadRetryOnCancellationCount;
293299

300+
/// <summary>
301+
/// Force set the execute permission bit for the root process of process pips in Linux builds.
302+
/// </summary>
303+
public bool ForceAddExecutionPermission { get; }
304+
294305
/// <summary>
295306
/// Encoded command line arguments
296307
/// </summary>
@@ -595,6 +606,7 @@ public void Serialize(Stream stream)
595606
writer.WriteNullableString(DetoursFailureFile);
596607
writer.WriteNullableReadOnlyList(ExternalVmSandboxStaleFilesToClean, (w, s) => w.Write(s));
597608
writer.Write(CreateSandboxTraceFile);
609+
writer.Write(ForceAddExecutionPermission);
598610

599611
// File access manifest should be serialized the last.
600612
writer.Write(FileAccessManifest, (w, v) => FileAccessManifest.Serialize(stream));
@@ -643,9 +655,9 @@ public static SandboxedProcessInfo Deserialize(Stream stream, LoggingContext log
643655
var detoursFailureFile = reader.ReadNullableString();
644656
var externalVmSandboxStaleFilesToClean = reader.ReadNullableReadOnlyList(r => r.ReadString());
645657
var createSandboxTraceFile = reader.ReadBoolean();
658+
bool forceAddExecutionPermission = reader.ReadBoolean();
646659

647660
var fam = reader.ReadNullable(r => FileAccessManifest.Deserialize(stream));
648-
649661
return new SandboxedProcessInfo(
650662
new PathTable(),
651663
sandboxedProcessStandardFiles != null ? new StandardFileStorage(sandboxedProcessStandardFiles) : null,
@@ -655,7 +667,8 @@ public static SandboxedProcessInfo Deserialize(Stream stream, LoggingContext log
655667
loggingContext: loggingContext,
656668
sidebandWriter: sidebandWritter,
657669
detoursEventListener: detoursEventListener,
658-
createJobObjectForCurrentProcess: createJobObjectForCurrentProcess)
670+
createJobObjectForCurrentProcess: createJobObjectForCurrentProcess,
671+
forceAddExecutionPermission: forceAddExecutionPermission)
659672
{
660673
m_arguments = arguments,
661674
m_commandLine = commandLine,

Public/Src/Engine/Processes/SandboxedProcessUnix.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,11 @@ public SandboxedProcessUnix(SandboxedProcessInfo info, bool ignoreReportedAccess
213213
DegreeOfParallelism: 1, // Must be one, otherwise SandboxedPipExecutor will fail asserting valid reports
214214
SingleProducerConstrained: useSingleProducer);
215215

216-
m_pendingReports = ActionBlockSlim.Create<AccessReport>(configuration: executionOptions, HandleAccessReport);
217-
216+
m_pendingReports = ActionBlockSlim.Create<AccessReport>(configuration: executionOptions,
217+
(accessReport) =>
218+
{
219+
HandleAccessReport(accessReport, info.ForceAddExecutionPermission);
220+
});
218221
// install 'ProcessReady' and 'ProcessStarted' handlers to inform the sandbox
219222
ProcessReady += () => SandboxConnection.NotifyPipReady(info.LoggingContext, info.FileAccessManifest, this, m_pendingReports.Completion);
220223
ProcessStarted += (pid) => OnProcessStartedAsync(info).GetAwaiter().GetResult();
@@ -280,7 +283,10 @@ protected override System.Diagnostics.Process CreateProcess(SandboxedProcessInfo
280283
{
281284
// This is a workaround for an issue that appears on Linux where some executables in the BuildXL
282285
// nuget/npm package may not have the execute bit set causing a permission denied error
283-
_ = FileUtilities.TrySetExecutePermissionIfNeeded(process.StartInfo.FileName);
286+
if (info.ForceAddExecutionPermission)
287+
{
288+
_ = FileUtilities.TrySetExecutePermissionIfNeeded(process.StartInfo.FileName);
289+
}
284290

285291
process.StartInfo.Arguments = $"{process.StartInfo.FileName} {process.StartInfo.Arguments}";
286292
process.StartInfo.FileName = EnvExecutable;
@@ -602,7 +608,7 @@ internal void PostAccessReport(AccessReport report)
602608
#endif
603609
}
604610

605-
private async Task FeedStdInAsync(SandboxedProcessInfo info, string? processStdinFileName)
611+
private async Task FeedStdInAsync(SandboxedProcessInfo info, string? processStdinFileName, bool forceAddExecutionPermission = true)
606612
{
607613
Contract.Requires(info.RootJailInfo == null || !NeedsShellWrapping(), "Cannot run root jail on this OS");
608614

@@ -651,7 +657,10 @@ private async Task FeedStdInAsync(SandboxedProcessInfo info, string? processStdi
651657

652658
lines.Add($"exec {cmdLine}");
653659

654-
SetExecutePermissionIfNeeded(info.FileName, throwIfNotFound: false);
660+
if (info.ForceAddExecutionPermission)
661+
{
662+
SetExecutePermissionIfNeeded(info.FileName, throwIfNotFound: false);
663+
}
655664
foreach (string line in lines)
656665
{
657666
await Process.StandardInput.WriteLineAsync(line);
@@ -836,7 +845,7 @@ private void UpdateAverageTimeSpentInReportQueue(AccessReportStatistics stats)
836845
m_sumOfReportQueueTimesUs += (stats.DequeueTime - stats.EnqueueTime) / 1000;
837846
}
838847

839-
private void HandleAccessReport(AccessReport report)
848+
private void HandleAccessReport(AccessReport report, bool forceAddExecutionPermission)
840849
{
841850
if (ShouldReportFileAccesses && report.Operation != FileOperation.OpDebugMessage)
842851
{
@@ -869,7 +878,7 @@ private void HandleAccessReport(AccessReport report)
869878
// The process is statically linked, a ptrace runner needs to be started up
870879
if (report.Operation == FileOperation.OpStaticallyLinkedProcess)
871880
{
872-
StartPTraceRunner(report.Pid, reportPath);
881+
StartPTraceRunner(report.Pid, reportPath, forceAddExecutionPermission);
873882
}
874883

875884
var pathExists = true;
@@ -1067,7 +1076,7 @@ internal static string AccessReportToString(AccessReport report)
10671076
I($"{operation}:{pid}|{requestedAccess}|{status}|{explicitLogging}|{error}|{path}|{isDirectory}|e:{report.Statistics.EnqueueTime}|h:{processTime}us|q:{queueTime}us");
10681077
}
10691078

1070-
private void StartPTraceRunner(int pid, string path)
1079+
private void StartPTraceRunner(int pid, string path, bool forceAddExecutionPermission)
10711080
{
10721081
var paths = SandboxConnectionLinuxDetours.GetPaths(RootJailInfo, UniqueName);
10731082
var args = $"-c {pid} -x {path}";
@@ -1094,8 +1103,9 @@ private void StartPTraceRunner(int pid, string path)
10941103
// We will kill these manually if the pip is exiting
10951104
Timeout.InfiniteTimeSpan,
10961105
// The runner will only log to stderr if there's a problem, other logs go to the main log using the fifo
1097-
errorBuilder: line => { if (line != null) { Logger.Log.PTraceRunnerError(m_loggingContext, line); } }
1098-
);
1106+
errorBuilder: line => { if (line != null) { Logger.Log.PTraceRunnerError(m_loggingContext, line); } },
1107+
forceAddExecutionPermission: forceAddExecutionPermission
1108+
);
10991109

11001110
ptraceRunner.Start();
11011111
m_ptraceRunners.Add(runnerTask(ptraceRunner));

Public/Src/Engine/Processes/UnSandboxedProcess.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ public UnsandboxedProcess(SandboxedProcessInfo info)
182182
{
183183
LogProcessState($"Unable to generate core dump: {m_dumpCreationException.GetLogEventMessage()}");
184184
}
185-
});
185+
},
186+
forceAddExecutionPermission: info.ForceAddExecutionPermission);
186187
}
187188

188189
/// <summary>

Public/Src/FrontEnd/UnitTests/Lage/IntegrationTests/LageIntegrationTestBase.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,6 @@ protected LageIntegrationTestBase(ITestOutputHelper output) : base(output, true)
7575

7676
SourceRoot = Path.Combine(TestRoot, RelativeSourceRoot);
7777
OutDir = "target";
78-
79-
// TODO Bug 2073919- this is a temporary workaround to tests that are flakey due to the execute permission
80-
// not correctly transiting through cache
81-
AssertTrue(FileUtilities.TrySetExecutePermissionIfNeeded(PathToYarn).Succeeded);
82-
AssertTrue(FileUtilities.TrySetExecutePermissionIfNeeded(PathToLage).Succeeded);
83-
AssertTrue(FileUtilities.TrySetExecutePermissionIfNeeded(PathToNode).Succeeded);
8478
}
8579

8680
/// <nodoc/>

0 commit comments

Comments
 (0)