Microsoft does not publish an exact minimum job-object access mask for PROC_THREAD_ATTRIBUTE_JOB_LIST; use handles returned by CreateJobObjectW (which have JOB_OBJECT_ALL_ACCESS) and keep both those handles and their array valid through CreateProcessW and until the attribute list is deleted.
Access-right contract
The UpdateProcThreadAttribute documentation says only that PROC_THREAD_ATTRIBUTE_JOB_LIST takes an ordered list of job handles. Unlike PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, whose required PROCESS_CREATE_PROCESS right is stated explicitly, it specifies no required access mask for job-list handles.^1^
Consequently:
- There is no authoritative public basis for claiming that
JOB_OBJECT_ASSIGN_PROCESSis the documented minimum for this attribute. -
JOB_OBJECT_ASSIGN_PROCESSis explicitly required by the separateAssignProcessToJobObjectAPI, but that contract should not be transferred toPROC_THREAD_ATTRIBUTE_JOB_LISTas an undocumented equivalence.^2^ - The documentation does not divide access checking into one requirement for
UpdateProcThreadAttributeand another forCreateProcessW.UpdateProcThreadAttributereports only success/failure for adding the value to the opaque attribute list; no documented guarantee says that it validates each job handle or its access at that point.^1^
Therefore, treat successful UpdateProcThreadAttribute as successful attribute-list construction—not proof that CreateProcessW can perform every requested association.
Handles returned by CreateJobObjectW
A successful CreateJobObjectW(NULL, NULL) returns a handle with JOB_OBJECT_ALL_ACCESS.^3^ That mask combines all valid job-object rights, including JOB_OBJECT_ASSIGN_PROCESS.^4^
Thus, that handle is sufficient from an access-mask perspective. It does not guarantee that process creation will succeed: session, hierarchy, limits, job state, or other process-creation conditions can still prevent assignment.
If opening existing named jobs instead, the DACL is checked against the rights requested by OpenJobObject; requesting a guessed reduced mask cannot be described as supported for JOB_LIST because Microsoft has not documented its minimum mask.^4^
Version, session, and nesting constraints
-
PROC_THREAD_ATTRIBUTE_JOB_LISTis supported on Windows 10 and later and Windows Server 2016 and later.^1^ - Extended attributes require a
STARTUPINFOEXWandEXTENDED_STARTUPINFO_PRESENTinCreateProcessW.^5^ - All processes associated with a job must run in the same session.^3^
- Multiple job membership must form a valid nested-job hierarchy. A process may belong to multiple jobs only in such a hierarchy; nesting was introduced in Windows 8/Server 2012. A hierarchy cannot be formed when the relevant jobs set UI limits, and assignment order matters when constructing a hierarchy.^6^
- Existing job membership and breakaway rules can affect a child created by a process that is already in a job.^7^
No additional caller privilege is documented specifically for PROC_THREAD_ATTRIBUTE_JOB_LIST. That is not a guarantee that no security check occurs; it means the public contract does not identify a privilege beyond access to the relevant objects.
Failure and atomicity
There is no published guarantee that applying a multi-job list is transactional, all-or-nothing, or rolled back if a later association fails. The documentation states only that jobs are assigned in the supplied order.^1^
Accordingly, do not design around either possible implementation behavior:
- Do not assume partial association can be observed.
- Do not assume rollback is guaranteed.
- Treat a false return from
CreateProcessWas failure, immediately captureGetLastError, and do not expect usablePROCESS_INFORMATIONoutput.^5^
If all-or-nothing multi-job assignment is a hard correctness requirement, the public API contract is insufficient; this requires a Microsoft Support/engineering clarification for the exact supported Windows builds.
Lifetime and interruption
The documented lifetime rule is stronger than merely keeping the array alive for the call: the value supplied through lpValue must persist until DeleteProcThreadAttributeList is called.^1^
Use this ownership sequence:
- Store the
HANDLE[]in stable memory. - Keep every job handle open.
- Call
UpdateProcThreadAttribute. - Call
CreateProcessW. - Call
DeleteProcThreadAttributeList. - Release the array and close job handles when their required ownership lifetime ends.
Closing the last job handle can affect object lifetime; with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, it terminates associated processes.^3^
No public documentation guarantees rollback or cleanup if the creator is forcibly terminated while inside CreateProcessW. Forced termination immediately stops its threads without allowing cleanup code to run.^8^ Use an external supervisor and explicit job-handle ownership if crash/interruption behavior is part of the design.
References