The other day a customer of mine was having this issue on Windows 7: CreateProcessAsUser fails with error 5 (Access Denied) when using Jobs. So he had a Windows service running as System in Session 0, that service created a process running as System in Session 0 too, and this process tried to create a new process in logged-on user's session but failed with Access Denied. The process that the service created as System in Session 0 was member of a Job and that was the cause of the issue as my other post explains.
Now, my customer confirmed me that he wasn't explicitly adding the process to a Job. Actually, he wasn't using Jobs at all in his app. Why was the process a member of a Job then?
According to the Job Objects documentation, a process is associated to a Job either explicitly via AssignProcessToJobObject API or by default if your parent process is part of a Job already. In my customer's scenario, his Windows service was not part of a Job, and he wasn't calling any Job API in his code.
I did some kernel debugging to figure out who was assigning that process to a Job, and I found it. Our Program Compatibility Assistant Service (PcaSvc) was the process calling AssignProcessToJobObject to do the task.
Our Program Compatibility Assistant (PCA) service got the details of customer's app and the Job from an LRPC (Local Remote Procedure Call) call made from customer's Windows Service. But customer's code was not doing this directly. This was something that was happening behind the scenes when the service was creating the problematic process.
What is PCA?
Program Compatibility Assistant: frequently asked questions
What is the Program Compatibility Assistant?
The Program Compatibility Assistant detects known compatibility issues in older programs.
What changes does it make?
It depends on the problem, but any changes made are related to how Windows runs the program. No changes are made to the program itself. For example, the Program Compatibility Assistant can resolve conflicts with User Account Control, a new security feature in this version of Windows that can help make your computer safer. Or, it can run the program in a mode that simulates earlier versions of Windows. The changes that Program Compatibility Assistant makes are done automatically, so you don't need to make them.
How do I turn it off or turn it back on?
Adjustments to the Program Compatibility Wizard can be made by using Group Policy. For more information on how to use Group Policy, go to the Microsoft website for IT professionals.
The Program Compatibility Assistant is an automatic feature of Windows that runs when it detects an older program has a compatibility problem.
Doing some research I found out that, by design, PCA uses Job objects to perform its tasks. So PCA is clearly interfering with the problematic process. It detected some sort of compatibility problem with it, run it in compatibility mode and assigned it to a Job to handle it.
There are several ways to exclude programs from the PCA:
Program Compatibility Assistant (PCA) in Windows Vista
Excluding Programs from PCA
PCA is intended to detect issues with older programs and not intended to monitor programs developed for Windows Vista and Windows Server 2008. The best option to exclude a program from PCA is to include, with the program, an application manifest with run level (either Administrator or as limited users) marking for UAC. This marking means the program is tested to work under UAC (and Windows Vista and Windows Server 2008). PCA checks for this manifest and will exclude the program. This process applies for both installer and regular programs.
Another option to exclude applications from PCA is to add the list of executable files with full path under the following registry key: HKEY_LOCAL_MACHINE\ Software\Microsoft\Windows NT\CurrentVersion\Compatibility Assistant. The value name is ExecutablesToExclude, which is type REG_MULTI_SZ.
PCA automatically excludes programs running from network locations and programs containing fixes applied to them in the application compatibility databases.
A group policy setting is provided to disable PCA for all programs if desired. The name of the policy is Turn Off Program Compatibility Assistant. It can be found under Administrative Templates\Windows Components\Application Compatibility in the group policy editor (gpedit.msc).
There are also individual policies to turn off specific scenarios. These policies are available under Administrative Templates\System\Troubleshooting and Diagnostics\Application Compatibility Diagnostics in the group policy editor.
So just to test my findings were correct, I did a quick test: I added the path to the problematic EXE to the REG_MULTI_SZ value ExecutablesToExclude I created under HKEY_LOCAL_MACHINE\ Software\Microsoft\Windows NT\CurrentVersion\Compatibility Assistant, and it worked! The problematic process was not assigned to a Job anymore, and I didn't get the Access Denied error.
Summing up, there are several ways to solve this issue:
1) Problematic process creates its child processes with CREATE_BREAKAWAY_FROM_JOB, so we don’t care if it is within a Job or not.
2) We exclude the problematic process from PCA via registry or GPO.
3) We add a UAC manifest to problematic process. (For example: Step 6: Create and Embed an Application Manifest (UAC)).
My customer already had a manifest in his problematic process, but he had to add a Compatibility section (see Application Manifest for details) to make things work on Windows 7:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<!--The ID below indicates application support for Windows Vista -->
<!--The ID below indicates application support for Windows 7 -->
I hope this helps.
Alex (Alejandro Campos Magencio)