Windows 2008 RenderFarm服务:CreateProcessAsUser“会话0隔离”和OpenGL

时间:2010-03-17 16:53:33

标签: opengl windows-services windows-server-2008 createprocessasuser session-0-isolation

我有一个传统的Windows服务器服务和(衍生的)应用程序在XP-64和W2K3中运行良好,但在W2K8上运行失败。我认为这是因为新的“Session 0 isolation”功能。

因此,我正在寻找代码示例/安全设置mojo,它允许您从Windows 2008 Server的Windows服务创建一个新进程,以便我可以恢复(并可能超过)以前的行为。我需要一个解决方案:

  1. 在非零会话中创建新进程以绕过会话0隔离限制(无法从会话0访问图形硬件) - 官方MS线路上是:
  2.   

    因为会话0不再是用户   会话,正在运行的服务   会话0无权访问   视频驱动。这意味着任何   尝试服务进行渲染   图形失败。查询显示   Session中的分辨率和颜色深度   0报告正确的结果   系统最高可达1920x1200 at   每像素32位。

    1. 新进程获取可用于创建Windows DC的Windows工作站/桌面(例如winsta0 / default)。我在这里找到了一个解决方案(在交互式会话中启动OK):Starting an Interactive Client Process in C++

    2. 当用作OpenGL DescribePixelFormat enumeration的基础时,Windows DC能够找到并使用硬件加速格式(在适当配备OpenGL硬件的系统上)。请注意我们当前的解决方案在XP-64和W2K3上工作正常,除非终端服务会话正在运行(VNC工作正常。)一个允许进程工作的解决方案(即使在终端服务会话打开时运行OpenGL硬件加速)将是虽然不是必需的,但是很神奇。

    3. 我目前只停留在第1项,虽然有一些类似的帖子可以讨论这个问题(例如thisthis - 但它们并不适合,因为无法保证已登录的用户会话已“从”获取会话ID,我也没有从LocalSystem帐户运行(我正在从该服务的域帐户运行,为此我可以在合理范围内调整权限,尽管我我宁愿不必将优先级升级到包括SeTcbPrivileges。)

      例如 - 这是我认为应该工作的存根,但总是在SetTokenInformation调用上返回错误1314(即使AdjustTokenPrivileges没有返回任何错误)我也使用了一些涉及“LogonUser”的替代策略(而不是打开现有的进程令牌),但我似乎无法换出会话ID。

      我也怀疑在所有情况下都使用WTSActiveConsoleSessionId(例如,如果没有交互式用户登录) - 尽管对没有登录会话的服务运行的快速测试似乎返回了合理的会话值(1 )。

      我已经删除了错误处理以便于阅读(仍然有点混乱 - 道歉)

          //Also tried using LogonUser(..) here
      OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
                               | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_SESSIONID
                               | TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY
                               | TOKEN_DUPLICATE, &hToken)
      
      GetTokenInformation( hToken, TokenSessionId, &logonSessionId, sizeof(DWORD), &dwTokenLength )
      
      DWORD consoleSessionId = WTSGetActiveConsoleSessionId();
      
      /* Can't use this - requires very elevated privileges (LOCAL only, SeTcbPrivileges as well)   
         if( !WTSQueryUserToken(consoleSessionId, &hToken))
      ...
         */
      
      DuplicateTokenEx(hToken, (TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_SESSIONID | TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE), NULL, SecurityIdentification, TokenPrimary, &hDupToken))
      
      
          // Look up the LUID for the TCB Name privilege.
      LookupPrivilegeValue(NULL, SE_TCB_NAME, &tp.Privileges[0].Luid))
      
          // Enable the TCB Name privilege in the token.
      tp.PrivilegeCount = 1;
      tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
      
          if (!AdjustTokenPrivileges(hDupToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, 0))
          {
              DisplayError("AdjustTokenPrivileges");
                 ...
          }
      
          if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
          {
              DEBUG( "Token does not have the necessary privilege.\n");
          } else {
              DEBUG( "No error reported from AdjustTokenPrivileges!\n");
          }                                                                                                                                                                                        // Never errors here
      
         DEBUG(LM_INFO, "Attempting setting of sessionId to: %d\n", consoleSessionId );
      
         if (!SetTokenInformation(hDupToken, TokenSessionId, &consoleSessionId, sizeof(DWORD)))
                 *** ALWAYS FAILS WITH 1314 HERE ***
      

      所有调试输出在SetTokenInformation调用之前看起来很好 - 我看到会话0是我当前的进程会话,在我的情况下,它正在尝试设置会话1(WTSGetActiveConsoleSessionId的结果)。 (注意我是通过VNC而不是RDC登录到W2K8盒子)

      所以 - 一个问题:

      1. 此方法是否有效,或者是否故意将所有服务启动的进程限制为会话0?
      2. 是否有更好的方法(缺少“登录时启动”和服务器的自动登录?)
      3. 此代码是否有问题,或者创建进程令牌的方法不同,我可以交换会话ID以指示我想在新会话中生成进程?我确实尝试使用LogonUser而不是OpenProcessToken,但这也不起作用。 (我不在乎所有衍生进程是否共享相同的非零会话。)
      4. 非常感谢任何帮助 - 谢谢!

3 个答案:

答案 0 :(得分:9)

对于有兴趣解决此问题的任何人:

我在LogonSDK团队的MS支持中讨论了这个问题。似乎不可能以编程方式完全模仿交互式用户,这样你就可以获得一个物理控制台和相关的GDI结构,而且我们基本上“幸运”它直到现在才有效。他们确实确认会话0隔离是回归的根本原因。

他们的建议是启用自动登录到交互式会话,并重构服务以与交互式会话中的新客户端组件通信。为了解决这方面的安全缺点,他们建议实施shell替换以在登录时将服务器置于“Kiosk”模式(例如,没有适当凭据的资源管理器访问等)。

从好的方面来说,这应该解决我们遇到的终端服务会议遇到的问题,这些问题会导致硬件加速。

我将向MS提交一个请求,考虑在未来的版本中使用“代理用户会话”支持的这种“渲染农场”用例,这样服务器就可以产生硬件加速的进程而不需要现有的安全性。要在控制台上登录的客户端用户进程。

答案 1 :(得分:0)

我还没有完成培训课程,但我找到了一个" Session 0隔离解决方法" Microsoft-MSDN站点上的教程:

http://msdn.microsoft.com/en-us/windows7trainingcourse_sessionisolation_unit.aspx

我在计划任务中表现出相同的session-0隔离问题。

答案 2 :(得分:0)

farmComm会将您选择的应用程序启动到会话0,没有可见的GUI,但可以访问图形硬件,无论用户是否登录。它还响应任何活动会话中的用户活动(包括会话0或“安全桌面”,当它是活动会话时)。它设计用于在用户空闲时启动应用程序,并在用户从空闲状态恢复时终止应用程序,但这些运行条件可以在源AutoHotkey脚本中轻松更改。

https://github.com/r-alex-hall/farmComm

它会在会话0中“无形地”生成应用程序,但它可以很容易地被修改(将值为“hide”的变量更改为“show”)以使生成的进程的GUI可见(如果它们具有GUI) 。但是,如果它们是可见的,它们可以触发Windows nags以在会话0中看到“消息”,和/或仅在会话0中可见(这似乎包括“安全桌面”可见的任何时间 - 对于例如,当工作站被锁定或与用户会话断开连接,或者没有用户登录时。)

在撰写本文时,如果在由farmComm运行的进程运行时开始任何远程桌面(RDP)会话,则farmComm将终止这些进程并尝试重新启动它们以响应RDP会话,如果它们是应用程序,则尝试访问图形硬件,可能会导致它们崩溃(因为RDP限制对图形硬件的访问)。可能这个RDP问题也可以解决。 。 。或者您可以调整源以永不终止进程,或永远不会迁移到其他会话。 (注意:可能的计划更改是使您能够编写脚本是否以及何时终止,不终止,暂停或恢复进程 - 或者就此而言,编写脚本以在用户从空闲状态恢复时运行完全不同的进程。)< / p>

脚本可以编译为可执行文件,在我的发行版中,它们是。

此工具集的关键字是paexec的特定版本(将应用程序启动到会话0),以及AutoHotkey对用户活动(或缺少)的非常可靠的响应,以及有关会话的系统信息的检索。启动流程“隐藏”(没有GUI可见)的选项也可以通过AutoHotkey。

披露:我编写了(或编码)farmComm,并将其发布到公共域中。