/// <summary><see cref="ProcessUtilities.AttachContainerToJobObject(IntPtr, IReadOnlyDictionary{ExpandedAbsolutePath, IReadOnlyList{ExpandedAbsolutePath}}, out IEnumerable{string})"/></summary> public void AttachContainerToJobObject(IntPtr hJob, IReadOnlyDictionary <ExpandedAbsolutePath, IReadOnlyList <ExpandedAbsolutePath> > redirectedDirectories, out IEnumerable <string> warnings) { try { if (NativeContainerUtilities.WcCreateDescriptionFromXml(s_containerDescription, out var description) != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to create a description for a container for job object {hJob}.")); } if (NativeContainerUtilities.WcCreateContainer(hJob, description, isServerSilo: false) != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to create a container for job object {hJob}.")); } NativeContainerUtilities.WcDestroyDescription(description); var wciRetries = new List <string>(); ConfigureContainer(hJob, redirectedDirectories, wciRetries); warnings = wciRetries; } catch (NativeWin32Exception ex) { throw new BuildXLException("Unable to create container.", ex); } }
/// <summary><see cref="ProcessUtilities.TryCleanUpContainer"/></summary> public bool TryCleanUpContainer(IntPtr hJob, out IEnumerable <string> errors) { var cleanUpErrors = new List <string>(); var result = NativeContainerUtilities.WcCleanupContainer(hJob, null); if (result != 0) { cleanUpErrors.Add(I($"Cannot clean up container for job object {hJob}. Details: {NativeWin32Exception.GetFormattedMessageForNativeErrorCode(result)}")); } errors = cleanUpErrors; return(cleanUpErrors.Count == 0); }
private static int LoadFilterWithPrivilege(string filterName) { try { NativeContainerUtilities.RtlImpersonateSelf(NativeContainerUtilities.SecurityImpersonationLevel.SecurityImpersonation, 0, out _); NativeContainerUtilities.RtlAdjustPrivilege(NativeContainerUtilities.Priviledge.SE_LOAD_DRIVER_PRIVILEGE, true, true, out _); var result = NativeContainerUtilities.FilterLoad(filterName); return(result); } finally { NativeContainerUtilities.RevertToSelf(); } }
private static void ConfigureBindFilter(IntPtr hJob, IReadOnlyCollection <ExpandedAbsolutePath> sourcePaths, string targetPath) { foreach (ExpandedAbsolutePath sourcePath in sourcePaths) { var hresult = NativeContainerUtilities.BfSetupFilter( hJob, // This flag has to be passed when WCI and Bind are configured for the same silo NativeContainerUtilities.BfSetupFilterFlags.BINDFLT_FLAG_USE_CURRENT_SILO_MAPPING, sourcePath.ExpandedPath, targetPath, CollectionUtilities.EmptyArray <string>(), 0); if (hresult != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to setup the Bind filter from '{sourcePath}' to '{targetPath}'.")); } } }
private static void ConfigureWciFilter(IntPtr hJob, IReadOnlyCollection <ExpandedAbsolutePath> sourcePaths, string destinationPath, List <string> wciRetries) { var layerDescriptors = new NativeContainerUtilities.WC_LAYER_DESCRIPTOR[sourcePaths.Count]; int i = 0; foreach (ExpandedAbsolutePath sourcePath in sourcePaths) { var layerDescriptor = new NativeContainerUtilities.WC_LAYER_DESCRIPTOR { // By default we always set the layer so it inherits the descriptor. This // makes hardlinks (ACLed for deny-write) and exposed via copy-on-write writable // The sparse flag is not set explicitly since we use the general sparse isolation mode // which implies that each layer will be sparse Flags = NativeContainerUtilities.LayerDescriptorFlags.InheritSecurity, LayerId = NativeContainerUtilities.ToGuid(Guid.NewGuid()), Path = sourcePath.ExpandedPath, }; layerDescriptors[i] = layerDescriptor; i++; } var reparsePointData = new NativeContainerUtilities.WC_REPARSE_POINT_DATA { Flags = 0, LayerId = layerDescriptors[0].LayerId, NameLength = 0, Name = string.Empty }; var hresult = -1; hresult = NativeContainerUtilities.WciSetReparsePointData( destinationPath, ref reparsePointData, (UInt16)Marshal.OffsetOf(typeof(NativeContainerUtilities.WC_REPARSE_POINT_DATA), "Name")); if (hresult != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to setup the reparse point data for '{destinationPath}'.")); } hresult = -1; // We try to setup the WCI filter on a retry loop to workaround an existing issue // in the driver behavior, where the setup sometimes fails. var retries = s_wciRetries; while (hresult != 0 && retries > 0) { // Isolation is set to hard because we want the virtualized source path to be // completely isolated (e.g. with 'hard' we will get copy-on-write behavior and // tombstones when any deletion happens inside the container). // It is also set as sparse so all layers recursively merge without needing an explicit reparse point // for each of them hresult = NativeContainerUtilities.WciSetupFilter( hJob, NativeContainerUtilities.WC_ISOLATION_MODE.IsolationModeSparseHard, destinationPath, layerDescriptors, (uint)layerDescriptors.Length, NativeContainerUtilities.WC_NESTING_MODE.WcNestingModeInner); retries--; if (hresult != 0) { wciRetries.Add(I($"Error setting WCI filter for {hJob} from '{string.Join(Environment.NewLine, sourcePaths)}' to '{destinationPath}'. Retries left: {retries}. Details: {NativeWin32Exception.GetFormattedMessageForNativeErrorCode(hresult)}")); } } if (hresult != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to setup the WCI filter for source paths '{string.Join(Environment.NewLine, sourcePaths)}' to destination path '{destinationPath}'.")); } }