base::string16 PolicyBase::GetAlternateDesktop()const{ // No alternate desktop or winstation. Return an empty string. // 如果policy在SpawnTarget前就已经指明了既不使用alternate desktop也不 // 使用alternate winstation,就返回空串 if (!use_alternate_desktop_ && !use_alternate_winstation_) { return base::string16(); }
// 如果要使用的是alternate winstation if (use_alternate_winstation_) { // The desktop and winstation should have been created by now. // If we hit this scenario, it means that the user ignored the failure // during SetAlternateDesktop, so we ignore it here too. // 理论上走到这里之前,desktop和winstation都已经创建完毕了 // 所以如果走到这里的话,就意味着用户已经忽略了失败 if (!alternate_desktop_handle_ || !alternate_winstation_handle_) { return base::string16(); } // 利用winstation和desktop的handle来调用关键Call returnGetFullDesktopName(alternate_winstation_handle_, alternate_desktop_handle_); } else { // 这就意味着不适用winstation,只用desktop,但还需要对 // alternate_desktop_local_winstation_handle_检查一下 // 如果其无效则表示设置上出现了差错 if (!alternate_desktop_local_winstation_handle_) { return base::string16(); } // 关键Call,此时winstation句柄是null returnGetFullDesktopName(nullptr, alternate_desktop_local_winstation_handle_); } }
base::string16 GetWindowObjectName(HANDLE handle){ // Get the size of the name. // 又是经典的二次调用,首次调用获取对象名称的尺寸 DWORD size = 0; ::GetUserObjectInformation(handle, UOI_NAME, nullptr, 0, &size);
if (!size) { NOTREACHED(); return base::string16(); }
// Create the buffer that will hold the name. std::unique_ptr<wchar_t[]> name_buffer(newwchar_t[size]);
// 二次调用获取对象名称 // Query the name of the object. if (!::GetUserObjectInformation(handle, UOI_NAME, name_buffer.get(), size, &size)) { NOTREACHED(); return base::string16(); }
ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation){ // 需要winstation的分支 if (alternate_winstation) { // Check if it's already created. // 防止二次create if (alternate_winstation_handle_ && alternate_desktop_handle_) return SBOX_ALL_OK;
DCHECK(!alternate_winstation_handle_); // Create the window station. // 创建winstation的关键Call,传入的句柄作为OUT型参数 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_); if (SBOX_ALL_OK != result) return result;
// Verify that everything is fine. if (!alternate_winstation_handle_ || GetWindowObjectName(alternate_winstation_handle_).empty()) return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
// Create the destkop. // 创建desktop的关键Call result = CreateAltDesktop(alternate_winstation_handle_, &alternate_desktop_handle_); if (SBOX_ALL_OK != result) return result;
// Verify that everything is fine. if (!alternate_desktop_handle_ || GetWindowObjectName(alternate_desktop_handle_).empty()) return SBOX_ERROR_CANNOT_CREATE_DESKTOP; } else { // Check if it already exists. // 这个成员作为无winstation(意味着使用local winstation)的desktop句柄 if (alternate_desktop_local_winstation_handle_) return SBOX_ALL_OK;
// Create the destkop. // 第一个参数是nullptr ResultCode result = CreateAltDesktop(nullptr, &alternate_desktop_local_winstation_handle_); if (SBOX_ALL_OK != result) return result;
// Verify that everything is fine. if (!alternate_desktop_local_winstation_handle_ || GetWindowObjectName(alternate_desktop_local_winstation_handle_).empty()) return SBOX_ERROR_CANNOT_CREATE_DESKTOP; }
if (!current_desktop) return SBOX_ERROR_CANNOT_GET_DESKTOP;
// Get the security attributes from the current desktop, we will use this as // the base security attributes for the new desktop. // 从当前desktop获取安全属性,用来给新的desktop当模板 SECURITY_ATTRIBUTES attributes = {0}; if (!GetSecurityAttributes(current_desktop, &attributes)) return SBOX_ERROR_CANNOT_QUERY_DESKTOP_SECURITY;
// Back up the current window station, in case we need to switch it. // 获取当前的winstation HWINSTA current_winsta = ::GetProcessWindowStation();
// 如果此前创建了winstation,就需要先切换到这个winstation上再创建desktop if (winsta) { // We need to switch to the alternate window station before creating the // desktop. // 这个Windows API负责切换进程的winstation if (!::SetProcessWindowStation(winsta)) { ::LocalFree(attributes.lpSecurityDescriptor); return SBOX_ERROR_CANNOT_CREATE_DESKTOP; } }
if (winsta) { // Revert to the right window station. // 切回来 if (!::SetProcessWindowStation(current_winsta)) { return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION; } }
if (*desktop) { // Replace the DACL on the new Desktop with a reduced privilege version. // We can soft fail on this for now, as it's just an extra mitigation. // 替换新desktop的DACL,做了降权处理 staticconst ACCESS_MASK kDesktopDenyMask = WRITE_DAC | WRITE_OWNER | DELETE | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_SWITCHDESKTOP; // 涉及到对象DACL的意义以及存储结构 // 可以自行参考《Windows Internals》的描述,阅读Acl.cc相关的代码 // 理解SID和DACL之间判定方法、顺序影响等 AddKnownSidToObject(*desktop, SE_WINDOW_OBJECT, Sid(WinRestrictedCodeSid), DENY_ACCESS, kDesktopDenyMask); return SBOX_ALL_OK; }
ResultCode CreateAltWindowStation(HWINSTA* winsta){ // Get the security attributes from the current window station; we will // use this as the base security attributes for the new window station. // 老套路,先用当前的winstation的安全属性做模板 HWINSTA current_winsta = ::GetProcessWindowStation(); if (!current_winsta) return SBOX_ERROR_CANNOT_GET_WINSTATION;
// Create the window station using nullptr for the name to ask the os to // generate it. // 不指定名称,由OS生成,创建出一个winstation *winsta = ::CreateWindowStationW( nullptr, 0, GENERIC_READ | WINSTA_CREATEDESKTOP, &attributes); if (!*winsta && ::GetLastError() == ERROR_ACCESS_DENIED) { *winsta = ::CreateWindowStationW( nullptr, 0, WINSTA_READATTRIBUTES | WINSTA_CREATEDESKTOP, &attributes); } LocalFree(attributes.lpSecurityDescriptor);