Based on my earlier posts, I've recently written a whitepaper for Microsoft France on how to build a machine that is capable of dual booting either Linux or Windows Vista when the latter is protected by BitLocker leveraging a TPM chip.
If you understand French, you' ll find the whitepaper, a webcast where I describe the steps and a video showing all the process and test of the final result on Microsoft's France interoperability website (http://www.microsoft.com/france/interop). To directly access the file please go to http://www.microsoft.com/france/interop/themes/infrastructure/20080430-dualboot-linux-bitlocker/default.mspx.
The video ("Partie2") is annotated with French callouts but it should be easy to understand even to non French speaking people. Here are the different sequences you can watch (the file embeds markers to jump directly to the different sections) :
0’00”: Linux OpenSuse install

4’28”: GRUB install out of MBR, on the Linux partition; get a copy of Linux boot sector


6’22”: Windows Vista install



10’54”: add an entry for Linux/GRUB in Windows Vista Boot Manager, using bcdedit tool

13’11”: boot test with Linux BEFORE enabling BitLocker; NTFS partitions mount

15’09”: enable TPM in BIOS

15’32”: BitLocker enablement with TPM from Windows Vista





22’38”: boot test with Linux AFTER Bitlocker was enabled using a TPM; NTFS partitions mount fails

24’18”: boot test with Windows VistaAFTER BitLocker was enabled using a TPM; visualize partition with DiskScape tool


25’23”: add entry for Boot Manager in GRUB
26’32”: secure startup test launching machine through Boot Manager then GRUB then Boot Manager



27’20”: secure startup test using a bootable DVD in startup chain
(This is part 5 of our series of posts on service hardening.)
Last but not least a service can be (and should be) configured to have network restrictions with what is called the "Windows Service Hardening" rules in the Windows SDK (we'll call those WSH rules for short). As a service developer, it is your responsibility to setup those rules during the installation and configuration of your service. Why? Because you know what network access (if any) your service needs, and by setting up WSH rules you can make sure your service will only get access to network ports and protocols it needs, thus contributing to the overall defense of the system and the environment.
What is different with those WSH network rules and, let's say, the Windows Firewall with Advanced Firewall Security rules? Well, technically, it is reasonable to think that the WSH are evaluated and enforced by Windows Vista integrated firewall. However, from a functional standpoint, they are totally independent and separate:
· Once defined, WSH rules for your service are en forced no matter what the firewall configuration may be. The administrator may have turned off all firewalls, yet this won’t affect the WSH rules that you have setup.
· WSH network restrictions rules can only be used to restrict access, they cannot in any way grant access to a network resource that would not already be allowed by the firewall. WSH rules are evaluated first, before those of the firewall.
· WSH rules cannot be configured with the Windows Firewall with Advanced Security administration tools such as the WF.msc MMC snap-in or netsh. They can only be defined with the API. So once your service has been installed and the WSH rules put in place, there is no way (short of programming or scripting) an administrator may change them while administering the firewall.
As a service developer for Windows Vista and Longhorn server, it is a best practice to take advantage of the service network restriction mechanism and setup the WSH rules for your service. In addition, the network resources that your service needs should be documented so that the IT folks in charge of a deployment can configure the firewall accordingly.
To define WSH rules, one uses the INetFwServiceRestriction interface which can be used from C++ code or VB scripts. Calling the RestrictService method with the restrictService parameter set to TRUE creates two rules that will block all inbound and outbound network communication for your service. This is what the following script would do:
' Create the FwPolicy2 object.
Dim fwPolicy2
Set fwPolicy2 = CreateObject("HNetCfg.FwPolicy2")
' Get the Service Restriction object for the local firewall policy.
Dim ServiceRestriction
Set ServiceRestriction = fwPolicy2.ServiceRestriction
' Restrict a service
ServiceRestriction.RestrictService ServiceName, ProgramName, TRUE, FALSE
Those two rules can be seen in the WSH rules section of the registry (HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Configurable\System):
v2.0|Action=Block|Active=TRUE|Dir=Out|App=c:\mysvc\mysvc.exe|Svc=mysvc|Name=Outbound service restriction rule for mysvc|Desc=Block all outbound traffic from service mysvc|Edge=FALSE|
v2.0|Action=Block|Active=TRUE|Dir=In|App=c:\mysvc\mysvc.exe|Svc=mysvc|Name=Inbound service restriction rule for mysvc|Desc=Block all inbound traffic to service mysvc|Edge=FALSE|
Notice that those rules refer to the service specifically (by its short name) and affect only the service (and not other software components). Per-service SID (see our previous posts on service hardening) and WSH network restriction rules go hand in hand. If your service does not already have a per-service SID, the RestrictService API will configure it to have one. In addition, if your service is to be run write-restricted, you can set the serviceSidRestricted parameter to TRUE. This is convenient as it saves you from having to call ChangeServiceConfig2.
Imagine now that your service needs outbound network access on TCP port 8080, you can define the appropriate rules with the INetFwRule interface. The following script (in addition to the previous one would) would restrict the service for outbound communication on that port and protocol only:
Dim CurrentRule
set CurrentRule = CreateObject("HNetCfg.FwRule")
CurrentRule.Name = "MySvc network restriction"
CurrentRule.ApplicationName = ProgramName
CurrentRule.ServiceName = ServiceName
CurrentRule.Protocol = 6
CurrentRule.RemotePorts = 8080
CurrentRule.Direction = NET_FW_RULE_DIR_OUT
CurrentRule.Enabled = TRUE
ServiceRestriction.Rules.Add CurrentRule
The corresponding WSH service network restriction rules in the registry would be:
v2.0|Action=Allow|Active=TRUE|Dir=Out|Protocol=6|RPort=8080|App=c:\mysvc\mysvc.exe|Svc=mysvc|Name=Allow mysvc (c:\mysvc\mysvc.exe) outbound on port 8080|Edge=FALSE|
v2.0|Action=Block|Active=TRUE|Dir=Out|App=c:\mysvc\mysvc.exe|Svc=mysvc|Name=Outbound service restriction rule for mysvc|Desc=Block all outbound traffic from service mysvc|Edge=FALSE|
v2.0|Action=Block|Active=TRUE|Dir=In|App=c:\mysvc\mysvc.exe|Svc=mysvc|Name=Inbound service restriction rule for mysvc|Desc=Block all inbound traffic to service mysvc|Edge=FALSE|
What about Windows Vista native services? Well most of them have their own network restriction rules. Actually, the INetFwServiceRestriction and INetFwRule APIs cannot be used to configure restrictions for the OS native services. So network restrictions for native services are something fully static. It is configured once for all at the OS install (development?) time and cannot be changed. You may notice that while WSH rules are stored in the RestrictedServices\Configurable subkey, Windows Vista native services network restriction rules are stored separately in RestrictedServices\Static subkey.
(This is part 4 of our series of posts on service hardening.)
A service can be configured to be write-restricted, in addition to having a per-service SID. To do so, you specify a SID type of "Restricted" when configuring your service (see our previous post “Per-service SID”). In that case the process hosting your service will run with a (new to Windows Vista) "write-restricted" token.
Hmmm, what is this animal, and what does it mean?
You may have heard of (or maybe be familiar with) restricted tokens. There are several definitions for those, one of which is a token issued from the CreateRestrictedToken API. We like to think of restricted tokens as tokens that have Restricting SIDs. When the system evaluates access to a resource, if there are restricting SIDs, the evaluation is made with two independent passes. The first pass uses the User SID and the Group SIDs, and the second pass uses the Restricting SIDs. For access to be granted, both passes must succeed. What that means is that Restricting SIDs can only be used to restrain access that a user account would have to start with but not broaden it in any event. Another case of the recurring "always restrain, never broaden" scheme.
We see restricted tokens along with the S-1-5-12 Restricted Code SID as early attempts to run applications with lower privilege and were used by "Run As…" with the "Protect my computer and data from unauthorized program activity” checkbox (no longer in Vista). In addition to Windows SDK documentation, you may want to check out blogs from Aaron Margosis and Larry Osterman for comments on these topics as well as Keith Brown's Programming Windows Security.
A write-restricted token (new to Windows Vista) is one that is flagged as WRITE_RESTRICTED (have a look at winnt.h). With a write-restricted token, the evaluation of the Restricting SIDs is only effective for write access checks. So a write-restricted token can be seen as less restrictive than a restricted token which is restricted for all types of accesses, and not only writes.
The write-restricted token for a "Restricted" service will have the following restricting SIDs: the per-service SID, the logon SID, the Everyone SID, and the (new to Vista) write-restricted SID (S-1-5-33 or NT AUTHORITY\WRITE RESTRICTED). The per-service SID and the write-restricted SID are also added to the Group SIDs. What does that mean?
Let's try:
· Writes are only possible by virtue of the service SID, the logon SID, Everyone SID, or write-restricted SID, and not the service account nor its groups. Reads are unaffected.
· The write-restricted SID allows for granting access to write-restricted services as a class, without forehand knowledge of which services will be write-restricted.
· By default, the write-restricted service looses write access to a lot of resources it would normally have access to by virtue of its account and groups. Write access must be explicitly granted to the service SID, the logon SID, the write-restricted class, or Everyone to be possible.
While running your service as "Unrestricted" (see our previous post “Per-service SID”) allows you to protect your resources using the per-service SID, running your service as "Restricted" protects the system in the event your code would get compromised (how can that be? J). It is a measure of good citizenship: your code runs write-restricted and its impact on the system in case of an exploit is mitigated. Is it expensive? You bet it is. You have to determine all write accesses your code will need and make sure you explicitly grant that access to your service. Are there tools to do so? We don't know, please comment…
A built-in example
In Windows Vista, only a few services are natively provided as “write-restricted”. The
sc qsidtype MpsSvc
command will show you that the Windows Firewall service (MpsSvc, short for Microsoft Protection Service) is configured to be a “Restricted” service:
[SC] QueryServiceConfig2 SUCCESS
SERVICE_NAME: MpsSvc
SERVICE_SID_TYPE: RESTRICTED
A quick inspection with a tool showing security tokens, like Process Explorer, will confirm that this service is indeed using a write-restricted token. The Windows Firewall service is hosted in a svchost.exe process running with the Local Service account and which also contains other services: Base Filtering Engine, Diagnostic Policy Service, Windows Media Center Service Launcher, Performance Logs & Alerts.
The
icacls C:\Windows\System32\LogFiles\Firewall
command will return
NT SERVICE\MpsSvc:(OI)(F)
NT AUTHORITY\SYSTEM:(OI)(F)
BUILTIN\Administrators:(OI)(F)
NT SERVICE\TrustedInstaller:(I)(F)
NT SERVICE\TrustedInstaller:(I)(CI)(IO)(F)
NT AUTHORITY\SYSTEM:(I)(F)
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(IO)(F)
BUILTIN\Administrators:(I)(F)
BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)
BUILTIN\Users:(I)(RX)
BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)
CREATOR OWNER:(I)(OI)(CI)(IO)(F)
showing an explicit ACE granting full control to the MpsSvc service SID. This is used to protect this folder and its content, namely firewall logs. As the Windows Firewall service is a write-restricted service, the net result will be that except for this folder and its content, the service won’t be able to write anywhere else on the file system except places where Everyone can write (or that have an explicit write permission for NT AUTHORITY\WRITE RESTRICTED which we did not find. If you do, please share by posting a comment. Thank you).
The same reasoning was applied to the registry: the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy
key. Looking at its ACL shows inherited permissions granting full control to Administrators and System and read permission for Users on the key and its subkeys, full control for the owner of any subkey and explicitly grant full control for MpsSvc service on the key and its subkeys. As we’ll see in our next post, some subkeys here are used to apply network restrictions on services. Therefore, it is particularly interesting to protect those rules so that only the Windows Firewall service NT AUTHORITY\WRITE RESTRICTED, an Administrator or the System can modify or create them. Moreover, due to the use of a write-restricted token, the Windows Firewall service can only write in this part of the registry and nowhere else except on keys Everyone can write to (or that show an explicit write permission to NT AUTHORITY\WRITE RESTRICTED; so far, we don’t know any shipping with Windows Vista. If you find one please share with all of us by posting a comment. Thank you).
(This is part 3 of our series of posts on service hardening.)
Under Windows Vista/Longhorn Server, your service can now have its own SID (Security Identifier), which you can then use in ACLs to protect your service resources. You configure your service to be assigned a per-service SID during its installation with the ChangeServiceConfig2 API (dwInfoLevel= SERVICE_CONFIG_SERVICE_SID_INFO) or the sc.exe command with the sidtype verb. In either case, three values are possible:
None – 0x0
Unrestricted – 0x1
Restricted – 0x3
If you want your service to have a per-service SID (as covered in this blog post), you should use "Unrestricted" for the type of SID. This means setting the SERVICE_SID_INFO.dwServiceSidType to SERVICE_SID_TYPE_UNRESTRICTED (0x1) if you are using the API, or using the following syntax with sc.exe:
sc sidtype [service name] unrestricted
You can also query the current configuration of your service with:
sc qsidtype [service name]
We find the semantics "type of SID" is a little funny, but once you get used to it, it's okay. A type of SID "None" means your service will not have a per-service SID nor a write-restricted token. Currently this is the default configuration for a service: no per-service SID. A type of SID "Unrestricted" means your service will have a per-service SID. A type of SID "Restricted" means your service will have a per-service SID and also a "write-restricted" token (this is our next post).
When configured to have a per-service SID (i.e. type of SID either "Unrestricted" or "Restricted"), the service SID is computed as S-1-5-80-{SHA-1(service name in uppercase)} and added to the host process token. If you need to know what the SID is or would be for a given service name, you can use the
sc showsid [service name]
command. This can be done through the use of APIs as well.
Once you have configured your service to have a per-service SID, you can grant access to resources your service needs. Prior to Windows Vista, when running your service with a built-in account (Local Service or Network Service), granting access to a resource for your service meant granting access to the other services running with that account as well. To avoid that side effect, you had to run your service with a dedicated account. Now with the per-service SID mechanism of Windows Vista, you can use the built-in service accounts while benefiting from the higher granularity of the per-service SID and thus ACL resources for your service only. When using the ACL editor (either on the file system, or registry) or icacls command line tool, you can use the "NT SERVICE\<service_name>" syntax to add your service SID to a resource.
In a recent Security Briefs article, Keith Brown shows how to factor out the higher privileged protocol transition operation in a COM+ component so a network facing gateway can be ran with lower privileges. In one of our projects, the gateway is a service configured with a service SID. We tried to add the service SID in COM+ roles with the "Component Services" mmc , to allow only our service to access the protocol transition component. But we found we couldn’t. However using a local group as an indirection, and adding the service SID to the local group worked just fine.
Configuring your service for a type of SID "Unrestricted" and thus having a service SID is a great way to either protect the resources your service needs, or in an environment that has been hardened, make sure that you only open access to your service. It is cheap to implement with a good return in terms of security gain.
This is part 2 of our series of posts on service hardening.
"Need to have" and least privilege principle
Executing with least privilege is a good practice of computer security. As with the "need to know" principle for information access, there should be a "need to have" principle for privileges. If your code does not need a specific privilege why should it run with it?
With Windows Vista, User Account Control ensures that user applications execute with less (and lower) privileges by default. User Account Control does not, however, apply to nor affect Win32 services which have their own mechanism (new to Windows Vista) for execution with least privileges. In Windows Vista and Longhorn Server, the RequiredPrivileges registry key allows to specify the privileges that the service should execute with. The process hosting the service will only have the privileges specified in RequiredPrivileges , and other privileges will be removed from the process token.
Although this may seem obvious, it is still worth stating that the RequiredPrivilege mechanism cannot in any case be used to augment the privileges of services but only to reduce them. If RequiredPrivileges refers to privileges that the service account does not already have, those privileges will be ignored. This is a recurring scheme in security by which a given mechanism can be used to restrain, but not to widen access.
Configure your service for least privilege
As a developer you should determine what minimum privileges your service needs and configure your service during its installation to run with those privileges only. This is an initiative of "good citizenship" on your part to lower the potential damage to the system in the event your code gets compromised. You can configure your service for least privilege with the ChangeServiceConfig2 API. If you don't, the administrator can still do it using the sc.exe command:
sc privs [service name] [Privileges]
And the current configuration for a service can be queried with the qprivs verb:
sc qprivs [service name]
Whether you use the ChangeServiceConfig2 API or the sc.exe command, you specify a privilege by its string. For instance, for the impersonate privilege, you would use "SeImpersonatePrivilege". The Windows SDK and winnt.h has the list of those and corresponding constants for each privilege strings (look for "Privilege Constants").
How do you determine which privileges your service needs? To our knowledge, this has to be done manually (please correct us if profiling tools similar to the ones for UAC analysis are available). Fortunately, the Windows SDK documentation often mentions the privileges needed when working with a given API and also whether those privileges should be enabled before calling the API versus whether the API is taking care of that. You may need to read the Remarks section carefully though. For instance, the SDK documentation for ImpersonateLoggedOnUser states that "The calling thread does not need to have any particular privilege." Sure, the API can be called without any particular privilege for some scenarios such as "identification level" impersonation, but if you want to do real impersonation, you do need the impersonate privilege.
In practice we've found that eliminating the unneeded privileges using knowledge of what the service does, code reviews, SDK documentation, and testing all execution paths was not too expensive and well worth the effort.
If you are hosting several services in the same process, the set of privileges the process gets is the union of those of its services. You should pay attention to this and regroup services according to their privilege requirements.
Built-in service accounts
Local Service and Network Service built-in service accounts were designed to be able to run services with lower privileges (than those of the all powerful Local System) without having to use dedicated user accounts. Creating and using dedicated user accounts for running services can be less than ideal as those user accounts have to be created and managed, including their (hopefully long and strong) passwords.
Local Service has about eleven privileges and no network identity. A service running under Local Service may listen for client requests from the network but if it attempts to reach a remote service, it will be seen as anonymous and most likely will fail (unless of course the remote service accepts anonymous requests). Network Service has one less privilege (i.e. it does not have the SeSystemTimePrivilege) and its network identity is the machine account on the domain.
Before Windows Vista, using Local or Network Service built-in accounts lacked granularity as all services running under a built-in account had the same privileges. Thanks to the RequiredPrivileges mechanism you can now have a fine granularity control over the privileges of your service without having recourse to dedicated user accounts. As a matter of fact, the other service hardening mechanisms in Windows Vista, which we will cover in our next posts, all tend to facilitate the use of built-in service accounts by providing more granular control. Several scenarii that previously reckoned for a dedicated user account are now possible with built-in accounts.
That said, there are plenty situations where a dedicated domain wide user account is necessary and fully appropriate for running a service. One such example is when you need to trust your service (such as trust for delegation) or grant access to your service on a remote resource or service, and you've determined that you’d rather trust your service specifically than trust the machine account.
Windows Vista native services
Microsoft has gone at length in its effort to reduce privileges of native Win32 service in Windows Vista. You can use Process Explorer to see the processes hosting Windows Vista services. A lot of native services are hosted using instances of svchost.exe (more on how native Vista services are grouped in svchost instances in our next posts). Notice that the DHCP Client service is hosted in a svchost instance that runs under Local Service with only four privileges (compare this with Local System and its twenty or so privileges under Windows XP). Actually, the DHCP Client service only requires two privileges as shown by the sc command:
C:\Windows\System32>sc qprivs dhcp
[SC] QueryServiceConfig2 réussite(s)
SERVICE_NAME: dhcp
PRIVILEGES : SeChangeNotifyPrivilege
: SeCreateGlobalPrivilege
The total of four privileges is due to the sharing of that svchost instance with other services such as the Eventlog or lmhosts services.
By the way, if you wonder whether you could use svchost to host your service, the answer is you are not supposed to. Svchost is for operating system native services.
Voili voilou! That’s all folks. Our next posts will go over the other service hardening mechanisms of Vista which are the per-service SID, write-restricted services, and network restrictions.
You may have heard that built-in services in Windows Vista were specifically hardened by Microsoft engineers during its development process. You might be wondering what that really means, how it works and, if you are a developer, how to harden your own services the Vista way. Jean-Yves Poublan, a Principal Security Consultant at Microsoft, and I are publishing a series of posts on how to leverage Windows Vista new architecture to make your services more secure.
Today, we start with a significant change with Windows Vista and Longhorn Server: Win32 services are now isolated in Session 0. So, what does this mean for developers?
‘windows’ on ‘desktops’ in ‘window stations’ in ‘Terminal Services sessions’
Windows NT was designed to be a multi-user system through the use of sessions. The SDK refers to these as Terminal Services sessions which are not to be confused with logon sessions, as they are not the same thing. Terminal Services sessions are created and managed by the session manager (smss.exe) which is one of the first processes created when the system starts. Logon sessions and processes somehow live within a Terminal Services session.
Note : The Terminal Services session ID for a given logon session may be obtained by calling the LsaGetLogonSessionData API after having enumerated the logon sessions (LsaEnumerateLogonSessions). One may also get the Terminal Services session ID for a process with the GetTokenInformation(TokenSessionId) API after having obtained the primary token for the process (OpenProcessToken).
Previous to Windows Vista and Longhorn Server, Win32 services and user applications for the console user (as well as winlogon.exe and the Win32 subsystem – csrss.exe) were all started within Terminal Services Session 0. A second Terminal Services session (Session 1) was created when a second user logged on (such as a user connecting through Terminal Services on Windows Server 2003, or a second user logging on Windows XP through Fast User Switching), and so on.
So user applications for the console user always shared Session 0 with system services. This is no longer the case with Windows Vista and Longhorn server.
What is wrong with having system services and user applications live in the same session? Well, it mostly has to do with interactive services.
First let’s recall what desktops and window stations are. Both are securable kernel objects in the sense that they are protected by ACLs. You can think of Terminal Services sessions having window stations that in turn contain desktops. There is a special window station called Winsta0 which is the windows station that is connected to the display and input devices. Processes are attached to a window station which they are going to use (supposedly) to interact with the user. Threads within a process are themselves attached to a desktop (within the window station) on which they display windows and they get input from the user. Windows messages are confined within a desktop, and Winsta0 will typically have three desktops: the winlogon desktop, the interactive desktop, and the screen saver desktop. Winsta0 grants rights to SYSTEM and the logon SID, so only the system and the currently logged on user can access the console. When a user logs off, the logon SID is removed from Winsta0, and when a new user logs on, the new logon SID is added to Winsta0’s ACL.
Windows, on the other hand, are user objects that are not securable by ACLs. So threads that have gained access to a desktop can send messages to any window on that desktop. In the past, applications that ran with higher privileges on the desktop have been vulnerable to the infamous shatter attacks from other malicious applications.
Normally, Win32 services are not attached to Winsta0 (they don’t have the rights on Winsta0), but instead they get their own window stations. Those window stations are not connected to any hardware so if a service displays a window and waits for user input, it may well wait forever…
Interactive services – to be avoided if at all possible
Interactive services are services that are configured as such (flag SERVICE_INTERACTIVE_PROCESS for CreateService or ChangeServiceConfig APIs). When the SCM starts a process for an interactive service, it attaches the service to Winsta0 instead of the service window station. In order to do so, the service process must run as SYSTEM (since only SYSTEM - and currently logged on user - have rights on Winsta0). Service threads can then attach to the interactive desktop and interact with the user.
One can see two compounded problems here: interactive services are vulnerable to Windows messages attacks from malicious user applications, and those attacks can result in privilege elevation since interactive services run as SYSTEM with TCB privilege. So deploying an interactive service that is vulnerable could compromise the whole system.
There are other things wrong with interactive services. On Windows Server 2003 with Terminal Services, the user that is currently logged on at the console in Session 0 may not be the user that the service should interact with. On Windows XP with Fast User Switching, it is even worse. The currently active console user may not be Session 0, but Session 1 (or Session n). In that case, if the interactive service waits for user input, it may wait forever from Session 0 which is not active. It is said that interactive services with Fast User Switching just don’t work. Because of that, developing and deploying interactive services has been strongly discouraged. As a matter of fact, interactive services can be banned from the system by setting the NoInteractiveServices registry value to 1 in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows. In that case, interactive services will still be started by the SCM (Services Control Manager), but they won’t be attached to Winsta0 (the SCM does log a warning in the event log). This is valid for Windows Vista and Longhorn as well.
Isolation of services in Session 0 with Windows Vista and Longhorn Server
With Windows Vista and Longhorn Server, user applications for the first logged on console user are now started in Terminal Services Session 1, and services in Session 0 are isolated from user applications. The second logged on user gets Session 2 and so on. Services isolation in Session 0 helps protecting the system from malicious user applications. Imagine one has installed an interactive service that is vulnerable, that interactive service will not share the desktop with (potentially) malicious user applications anymore and as such will be less likely to be compromised and used as a vehicle to attack the system.
Services isolation in Session 0 affects all services that assume they are running in the same session as user applications, and not only services that configured as interactive services. For instance, a service that communicates with user applications by way of Windows messages will no longer work. Also, a service that synchronizes with user applications through synchronization objects (semaphores, mutexes, etc…) created in the session private name space will no longer work as well. The global name space should be used instead (object names prefixed with Global\).
Under Windows Vista and Longhorn, a service can still be configured to be an interactive service, but such configuration does not make a whole lot of sense, since the interactive service will be attached to the Winsta0 in Session 0, which does not have a physical console and user to interact with.
If you have a service that is designed to be an interactive service and as such interacts with the desktop, or a service that assumes it is running in the same session as user applications, it is time to change it. Windows SDK does give some ideas of how a service could interact with users, without having to be an interactive service. This includes communicating with a user process through some form of IPC (preferably secure) channel, or using Terminal Services APIs such WTSSendMessage. Determining which user (in which target session) your service should interact with is up to you but should not be overlooked.
For legacy interactive services that cannot be changed in the short term, Windows Vista provides a compatibility mechanism called Interactive Service Detection service (ui0detect.exe). UI0Detect monitors interactive services in Wintsta0 of Session 0 and when such service displays a modal dialog it notifies the user in the currently active console session. The user can choose to switch to Winsta0/interactive desktop of Session 0 to respond to the dialog, and then switch back to the user session. UI0Detect is a temporary measure designed to limit the effect of Session 0 service isolation for existing interactive services that cannot be changed. As a service developer you should not count on that mechanism.
What about MessageBox() and MessageBox(MB_SERVICE_NOTIFICATION)?
When calling the MessageBox() API - *without* the MS_SERVICE_NOTIFICATION flag - from a service that is not an interactive service, the thread waits forever. It is worth noting that if a non interactive service is programmed in managed code on the .Net Runtime, calling the System.Windows.Forms.MessageBox.Show() method will raise an exception (“System.InvalidOperationException: Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application”) instead of hanging there waiting for user input. Also if the service is an interactive service, under Windows Vista, UI0Detect will handle the interaction for MessageBox() – without MB_SERVICE_NOTIFICATION.
The MB_SERVICE_NOTIFICATION flag causes the system to redirect the message box to the interactive desktop (or winlogon desktop if there is no user logged on) on WinSta0 where it is handled by csrss.exe (the Win32 subsystem).It was designed to allow services that technically are not interactive services (i.e. they are not configured as interactive services and thus are not attached to Winsta0) to display a modal dialog message box on the interactive desktop and get user input.
Under Windows Vista RTM, this does not work however, in the sense that instead of the message box being redirected to the interactive desktop of a session with a user on it, or taken care of by UI0Detect as one could hope, the functions returns IDOK immediately with no user interaction whatsoever. It behaves that way even for services that are configured as interactive services and whose interactions are normally handled by UI0Detect. If your service uses MessageBox(MB_SERVICE_NOTIFICATION) to ask for user approval for some operation, it may need to be modified.
The following two tables summarize MessageBox behaviors under Windows XP SP2 and Windows Vista RTM.
|
NoInteractiveServices = 0 |
NoInteractiveServices = 1 |
|
SERVICE_INTERACTIVE_PROCESS (CreateService, ChangeServiceConfig)
Window station (service is running as SYSTEM) |
0x00000000
"Allow service to interact with desktop"= unchecked
Service-0x0-3e7$ |
|