[tor-commits] [tor/release-0.2.9] Windows: fix uname on recent Windows versions

teor at torproject.org teor at torproject.org
Wed Mar 13 23:06:43 UTC 2019


commit 2fbc58cf07fd7367ddaf81b82868b5f37d7883ae
Author: teor <teor at torproject.org>
Date:   Mon Oct 22 14:02:43 2018 +1000

    Windows: fix uname on recent Windows versions
    
    Correctly identify Windows 8.1, Windows 10, and Windows Server 2008
    and later from their NT versions.
    
    On recent Windows versions, the GetVersionEx() function may report
    an earlier Windows version than the running OS. To avoid user
    confusion, add "[or later]" to Tor's version string on affected
    versions of Windows.
    
    Remove Windows versions that were never supported by the
    GetVersionEx() function.
    
    Stop duplicating the latest Windows version in get_uname().
    
    Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
---
 changes/bug28096    | 13 ++++++++
 src/common/compat.c | 95 ++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 77 insertions(+), 31 deletions(-)

diff --git a/changes/bug28096 b/changes/bug28096
new file mode 100644
index 000000000..6847df979
--- /dev/null
+++ b/changes/bug28096
@@ -0,0 +1,13 @@
+  o Minor bugfixes (Windows):
+    - Correctly identify Windows 8.1, Windows 10, and Windows Server 2008
+      and later from their NT versions.
+      Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
+    - On recent Windows versions, the GetVersionEx() function may report
+      an earlier Windows version than the running OS. To avoid user
+      confusion, add "[or later]" to Tor's version string on affected
+      versions of Windows.
+      Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
+    - Remove Windows versions that were never supported by the
+      GetVersionEx() function. Stop duplicating the latest Windows
+      version in get_uname().
+      Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
diff --git a/src/common/compat.c b/src/common/compat.c
index 4ac443c13..975875112 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -2689,22 +2689,33 @@ MOCK_IMPL(const char *, get_uname, (void))
 #ifdef _WIN32
         OSVERSIONINFOEX info;
         int i;
+        int is_client = 0;
+        int is_server = 0;
         const char *plat = NULL;
         static struct {
-          unsigned major; unsigned minor; const char *version;
+          unsigned major; unsigned minor;
+          const char *client_version; const char *server_version;
         } win_version_table[] = {
-          { 6, 2, "Windows 8" },
-          { 6, 1, "Windows 7" },
-          { 6, 0, "Windows Vista" },
-          { 5, 2, "Windows Server 2003" },
-          { 5, 1, "Windows XP" },
-          { 5, 0, "Windows 2000" },
-          /* { 4, 0, "Windows NT 4.0" }, */
-          { 4, 90, "Windows Me" },
-          { 4, 10, "Windows 98" },
-          /* { 4, 0, "Windows 95" } */
-          { 3, 51, "Windows NT 3.51" },
-          { 0, 0, NULL }
+    /* This table must be sorted in descending order.
+     * Sources:
+     *   https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
+     *   https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
+     *     ns-winnt-_osversioninfoexa#remarks
+     */
+    /* Windows Server 2019 is indistinguishable from Windows Server 2016
+     * using GetVersionEx().
+    { 10,  0, NULL,                        "Windows Server 2019" }, */
+    { 10,  0, "Windows 10",                "Windows Server 2016" },
+    {  6,  3, "Windows 8.1",               "Windows Server 2012 R2" },
+    {  6,  2, "Windows 8",                 "Windows Server 2012" },
+    {  6,  1, "Windows 7",                 "Windows Server 2008 R2" },
+    {  6,  0, "Windows Vista",             "Windows Server 2008" },
+    {  5,  2, "Windows XP Professional",   "Windows Server 2003" },
+    /* Windows XP did not have a server version, but we need something here */
+    {  5,  1, "Windows XP",                "Windows XP Server" },
+    {  5,  0, "Windows 2000 Professional", "Windows 2000 Server" },
+    /* Earlier versions are not supported by GetVersionEx(). */
+    {  0,  0, NULL,                        NULL }
         };
         memset(&info, 0, sizeof(info));
         info.dwOSVersionInfoSize = sizeof(info);
@@ -2714,25 +2725,34 @@ MOCK_IMPL(const char *, get_uname, (void))
           uname_result_is_set = 1;
           return uname_result;
         }
-        if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
-          if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
-            plat = "Windows NT 4.0";
-          else
-            plat = "Windows 95";
+#ifdef VER_NT_SERVER
+        if (info.wProductType == VER_NT_SERVER ||
+            info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
+          is_server = 1;
         } else {
-          for (i=0; win_version_table[i].major>0; ++i) {
-            if (win_version_table[i].major == info.dwMajorVersion &&
-                win_version_table[i].minor == info.dwMinorVersion) {
-              plat = win_version_table[i].version;
-              break;
+          is_client = 1;
+        }
+#endif
+        /* Search the version table for a matching version */
+        for (i=0; win_version_table[i].major>0; ++i) {
+          if (win_version_table[i].major == info.dwMajorVersion &&
+              win_version_table[i].minor == info.dwMinorVersion) {
+            if (is_server) {
+              plat = win_version_table[i].server_version;
+            } else {
+              /* Use client versions for clients, and when we don't know if it
+              * is a client or a server. */
+              plat = win_version_table[i].client_version;
             }
+            break;
           }
         }
         if (plat) {
           strlcpy(uname_result, plat, sizeof(uname_result));
         } else {
-          if (info.dwMajorVersion > 6 ||
-              (info.dwMajorVersion==6 && info.dwMinorVersion>2))
+          if (info.dwMajorVersion > win_version_table[0].major ||
+              (info.dwMajorVersion == win_version_table[0].major &&
+               info.dwMinorVersion > win_version_table[0].minor))
             tor_snprintf(uname_result, sizeof(uname_result),
                          "Very recent version of Windows [major=%d,minor=%d]",
                          (int)info.dwMajorVersion,(int)info.dwMinorVersion);
@@ -2741,12 +2761,25 @@ MOCK_IMPL(const char *, get_uname, (void))
                          "Unrecognized version of Windows [major=%d,minor=%d]",
                          (int)info.dwMajorVersion,(int)info.dwMinorVersion);
         }
-#ifdef VER_NT_SERVER
-      if (info.wProductType == VER_NT_SERVER ||
-          info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
-        strlcat(uname_result, " [server]", sizeof(uname_result));
-      }
-#endif
+        /* Now append extra information to the name.
+         *
+         * Microsoft's API documentation says that on Windows 8.1 and later,
+         * GetVersionEx returns Windows 8 (6.2) for applications without an
+         * app compatibility manifest (including tor's default build).
+         *
+         * But in our testing, we have seen the actual Windows version on
+         * Windows Server 2012 R2, even without a manifest. */
+        if (info.dwMajorVersion > 6 ||
+            (info.dwMajorVersion == 6 && info.dwMinorVersion >= 2)) {
+          /* When GetVersionEx() returns Windows 8, the actual OS may be any
+           * later version. */
+          strlcat(uname_result, " [or later]", sizeof(uname_result));
+        }
+        /* When we don't know if the OS is a client or server version, we use
+         * the client version, and this qualifier. */
+        if (!is_server && !is_client) {
+          strlcat(uname_result, " [client or server]", sizeof(uname_result));
+        }
 #else
         /* LCOV_EXCL_START -- can't provoke uname failure */
         strlcpy(uname_result, "Unknown platform", sizeof(uname_result));





More information about the tor-commits mailing list