NTSetInformationProcess (ProcessAccessToken) fails with STATUS_NOT_SUPPORTED
- I had just created a new method to implement setuid() on Cygwin, which doesn't
just call ImpersonateLoggedOnUser, but instead tries to replace the process token
using NTSetInformationProcess (ProcessAccessToken).
The problem with using ImpersonateLoggedOnUser is that the effect of calling
setuid() can be reverted by a call to RevertToSelf(). This is contrary to how
setuid() is supposed to work. For security reasons, a setuid() call must not be
revertable when called from a privileged user account.
So, to accomplish this, I re-implemented setuid() by replacing the process token.
This works fine on all systems until Windows 2003.
Guess what happens on Vista. The NTSetInformationProcess call returns with
STATUS_NOT_SUPPORTED. I'm rather disappointed. I was going to make
a system call more secure and Vista doesn't allow it. This contradicts security
rather than helping it.
So, here's the question: How is a POSIX layer supposed to implement setuid
correctly if that feature has been removed from the OS? How is Interix going to
do that?
Corinna
Answers
Hello.
I am a developer on the Windows Kernel Team. Before continuing, I want to stress as a disclaimer that NtSetInformationProcess, class ProcessAccessToken, is an undocumented and unsupported infterface. It is reserved for system component use and is subject to change between operating system releases. That being said, I would like to address your particular concern.
The NT kernel was never intended to allow token switching once a process started running. This is because handles, etc. may have been opened in an old security context, inflight operations may use inconsistent security contexts, etc. As such, it typically does not make sense to switch a process' token once it has begun execution. However, this was not enforced until Vista.
Unfortunately, it is difficult to properly implement setuid() semantics on NT as you have noted, though it too could be susceptible to the issues outlined above. After exploring alternative implementations for Interix we settled on leaving the lazy swap behavior intact for EXEs launched from POSIX binaries (image type = POSIX in the PE image). This was a reasonable compromise since the change was not security-based in nature, and allowed the legacy behavior to persist in conjunction with binaries that had (or should have) better control of their environment.
Arun Kishan
Windows Kernel Team
All Replies
- Ping? Any help here?
Corinna Hello.
I am a developer on the Windows Kernel Team. Before continuing, I want to stress as a disclaimer that NtSetInformationProcess, class ProcessAccessToken, is an undocumented and unsupported infterface. It is reserved for system component use and is subject to change between operating system releases. That being said, I would like to address your particular concern.
The NT kernel was never intended to allow token switching once a process started running. This is because handles, etc. may have been opened in an old security context, inflight operations may use inconsistent security contexts, etc. As such, it typically does not make sense to switch a process' token once it has begun execution. However, this was not enforced until Vista.
Unfortunately, it is difficult to properly implement setuid() semantics on NT as you have noted, though it too could be susceptible to the issues outlined above. After exploring alternative implementations for Interix we settled on leaving the lazy swap behavior intact for EXEs launched from POSIX binaries (image type = POSIX in the PE image). This was a reasonable compromise since the change was not security-based in nature, and allowed the legacy behavior to persist in conjunction with binaries that had (or should have) better control of their environment.
Arun Kishan
Windows Kernel Team
- Hi,
> [...] NtSetInformationProcess, class ProcessAccessToken, is an undocumented and
> unsupported infterface.
I understand perfectly. It's just that some undocumented APIs look pretty useful to implement
a certain behaviour...
> The NT kernel was never intended to allow token switching once a process started running.
Uh, ok. So the NtSetInformationProcess(ProcessAccessToken) API was only ever meant to
set the process token at process creation time?
> This is because handles, etc. may have been opened in an old security context, inflight
> operations may use inconsistent security contexts, etc. As such, it typically does not make
> sense to switch a process' token once it has begun execution.
I'm wondering that this matters. I assumed that the security context only matters at creation
time of the handle to the object. When I give a handle to a child process running under another
user account, the handle is still valid in the context of the child process. So, without knowing
how that's implemented, it sounds strange that this should be different when changing the
user context in the running process.
> After exploring alternative implementations for Interix we settled on leaving the lazy swap
> behavior intact [...]. This was a reasonable compromise since the change was not
> security-based in nature, and allowed the legacy behavior to persist in conjunction with
> binaries that had (or should have) better control of their environment.
Do I understand you correctly, with "lazy" you mean that Interix is using an equivalent
approach(*) to Cygwin, which is, changing the user context using ImpersonateLoggedOnUser
in the calling process and only switching to the final user context when starting child
processes on exec(3) using CreateProcessAsUser? Or is there yet another way to do this
which I just don't realize?
What always bugged me with this technique is the fact that it's easily possible to switch back
to the original user context in the calling process. OpenSSH, for instance, has a function
permanently_set_uid(), which tests explicitly if it's possible to revert the user context after
calling setuid(). If so, it treats that as a fatal error and exits. Since Cygwin's setuid is "broken"
in this regard, it was necessary to add a bit of Cygwin-specific code to OpenSSH. Sure, I could
implement setuid so that it doesn't allow a reversion to the original user context. But it would not
reflect the reality, it would just fake security.
Thanks for your informative and helpful reply,
Corinna
(*) I'm aware that you don't use the Win32 interfaces in Interix ;) Yes, it was initially only intended for our own use to enable CreateProcessAsUser. What was meant above about odd behavior is the inconsistencies that result since objects that perhaps a process could access previously may no longer be accessible (handle accesses remain fine). It's not a real security problem but is also of limited use unless you have total control of the target process to know its state at the time of the swap. Since for most NT processes there could be any number of threads doing various tasks (including injected threads), the effect of a swap during runtime is not deterministic.
Our guidance around this to Interix was to use NT impersonation support for revertable setuid and for the permanent id change case (dropping privileges), we decided to support the primary token swap as noted above. We allow this if the primary exe is a POSIX exe since the environment is assumed to be more constrained.
Arun
So short of implementing the actual swap myself in a driver, which I am loathe to do, or tricking the API into thinking I'm POSIX, is there any other way to achieve it?
We have an application that worked fine on XP but is broken on Vista due to this change.


