123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// found in the LICENSE file.
423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include <stdint.h>
623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include <windows.h>
723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/basictypes.h"
923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "sandbox/win/src/interception_internal.h"
1023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "sandbox/win/src/internal_types.h"
1123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "sandbox/win/src/sandbox_utils.h"
1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "sandbox/win/src/service_resolver.h"
1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)namespace {
1523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)enum Version {
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_PRE_XP_SP2 = 0,  // Not supported.
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_XP_SP2,
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_SERVER_2003,  // Also includes XP Pro x64 and Server 2003 R2.
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_VISTA,        // Also includes Windows Server 2008.
2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_WIN7,         // Also includes Windows Server 2008 R2.
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_WIN8,         // Also includes Windows Server 2012.
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_WIN8_1,
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VERSION_WIN_LAST,  // Indicates error condition.
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Whether a process is running under WOW64 (the wrapper that allows 32-bit
2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// processes to run on 64-bit versions of Windows).  This will return
2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Chrome on 64-bit Windows".  WOW64_UNKNOWN means "an error occurred", e.g.
3023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// the process does not have sufficient access rights to determine this.
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)enum WOW64Status { WOW64_DISABLED, WOW64_ENABLED, WOW64_UNKNOWN, };
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)WOW64Status GetWOW64StatusForCurrentProcess() {
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!is_wow64_process)
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return WOW64_DISABLED;
3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  BOOL is_wow64 = FALSE;
4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (!is_wow64_process(GetCurrentProcess(), &is_wow64))
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return WOW64_UNKNOWN;
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)class OSInfo {
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public:
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  struct VersionNumber {
4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int major;
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int minor;
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int build;
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  };
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  struct ServicePack {
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int major;
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    int minor;
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  };
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  OSInfo() {
5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    OSVERSIONINFOEX version_info = {sizeof(version_info)};
6023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    version_number_.major = version_info.dwMajorVersion;
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    version_number_.minor = version_info.dwMinorVersion;
6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    version_number_.build = version_info.dwBuildNumber;
6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if ((version_number_.major == 5) && (version_number_.minor > 0)) {
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      version_ =
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          (version_number_.minor == 1) ? VERSION_XP_SP2 : VERSION_SERVER_2003;
6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (version_ == VERSION_XP_SP2 && version_info.wServicePackMajor < 2)
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        version_ = VERSION_PRE_XP_SP2;
7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else if (version_number_.major == 6) {
7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      switch (version_number_.minor) {
7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        case 0:
7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          // Treat Windows Server 2008 the same as Windows Vista.
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          version_ = VERSION_VISTA;
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          break;
7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        case 1:
7723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          // Treat Windows Server 2008 R2 the same as Windows 7.
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          version_ = VERSION_WIN7;
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          break;
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        case 2:
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          // Treat Windows Server 2012 the same as Windows 8.
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          version_ = VERSION_WIN8;
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          break;
8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        default:
8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          version_ = VERSION_WIN8_1;
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          break;
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else if (version_number_.major > 6) {
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      version_ = VERSION_WIN_LAST;
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else {
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      version_ = VERSION_PRE_XP_SP2;
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    service_pack_.major = version_info.wServicePackMajor;
9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    service_pack_.minor = version_info.wServicePackMinor;
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  Version version() const { return version_; }
9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VersionNumber version_number() const { return version_number_; }
10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ServicePack service_pack() const { return service_pack_; }
10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private:
10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  Version version_;
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  VersionNumber version_number_;
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ServicePack service_pack_;
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OSInfo);
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)};
10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}  // namespace
11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)sandbox::ServiceResolverThunk* GetThunk(bool relaxed) {
11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Create a thunk via the appropriate ServiceResolver instance.
11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sandbox::ServiceResolverThunk* thunk = NULL;
11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
11623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // No thunks for unsupported OS versions.
11723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  OSInfo os_info;
11823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (os_info.version() <= VERSION_PRE_XP_SP2)
11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return thunk;
12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Pseudo-handle, no need to close.
12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  HANDLE current_process = ::GetCurrentProcess();
12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(_WIN64)
12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // ServiceResolverThunk can handle all the formats in 64-bit (instead only
12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // handling one like it does in 32-bit versions).
12723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
12823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#else
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (GetWOW64StatusForCurrentProcess() == WOW64_ENABLED) {
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (os_info.version() >= VERSION_WIN8)
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      thunk = new sandbox::Wow64W8ResolverThunk(current_process, relaxed);
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    else
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      thunk = new sandbox::Wow64ResolverThunk(current_process, relaxed);
13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  } else if (os_info.version() >= VERSION_WIN8) {
13523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    thunk = new sandbox::Win8ResolverThunk(current_process, relaxed);
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  } else {
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
13823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
13923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif
14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return thunk;
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
143