Преглед на файлове

project: Fix potential buffer write-past-end for version components

This fixes two errors: not accounting for the trailing null and a
misunderstanding of what std::numeric_limits::digits10 means.
Craig Scott преди 6 години
родител
ревизия
82cdb26c93
променени са 3 файла, в които са добавени 35 реда и са изтрити 1 реда
  1. 2 1
      Source/cmProjectCommand.cxx
  2. 1 0
      Tests/RunCMake/project/RunCMakeTest.cmake
  3. 32 0
      Tests/RunCMake/project/VersionMax.cmake

+ 2 - 1
Source/cmProjectCommand.cxx

@@ -224,7 +224,8 @@ bool cmProjectCommand(std::vector<std::string> const& args,
     std::array<std::string, MAX_VERSION_COMPONENTS> version_components;
 
     if (cmp0096 == cmPolicies::OLD || cmp0096 == cmPolicies::WARN) {
-      char vb[MAX_VERSION_COMPONENTS][std::numeric_limits<unsigned>::digits10];
+      char vb[MAX_VERSION_COMPONENTS]
+             [std::numeric_limits<unsigned>::digits10 + 2];
       unsigned v[MAX_VERSION_COMPONENTS] = { 0, 0, 0, 0 };
       const int vc = std::sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1],
                                  &v[2], &v[3]);

+ 1 - 0
Tests/RunCMake/project/RunCMakeTest.cmake

@@ -22,6 +22,7 @@ run_cmake(VersionInvalid)
 run_cmake(VersionMissingLanguages)
 run_cmake(VersionMissingValueOkay)
 run_cmake(VersionTwice)
+run_cmake(VersionMax)
 
 run_cmake(CMP0048-OLD)
 run_cmake(CMP0048-OLD-VERSION)

+ 32 - 0
Tests/RunCMake/project/VersionMax.cmake

@@ -0,0 +1,32 @@
+cmake_policy(SET CMP0048 NEW)
+cmake_policy(SET CMP0096 OLD)
+
+enable_language(C)
+include(CheckTypeSize)
+check_type_size(unsigned __sizeOfUnsigned BUILTIN_TYPES_ONLY LANGUAGE C)
+
+# We can't use math() to compute this because it only supports up to
+# 64-bit signed integers, so hard-code the types we expect to encounter
+if(__sizeOfUnsigned EQUAL 0)
+  message(STATUS "Multi-architecture build, skipping project version check")
+  return()
+elseif(__sizeOfUnsigned EQUAL 4)
+  set(maxVal 4294967295)
+elseif(__sizeOfUnsigned EQUAL 8)
+  set(maxVal 18446744073709551615)
+else()
+  message(FATAL_ERROR
+    "Test needs to be updated for unsigned integer size ${__sizeOfUnsigned}")
+endif()
+
+# The real value of this test is when an address sanitizer is enabled.
+# It catches situations where the size of the buffer used to compute or
+# hold the version components as strings is too small.
+project(ProjectA VERSION ${maxVal}.${maxVal}.${maxVal}.${maxVal} LANGUAGES NONE)
+
+if(NOT ${PROJECT_VERSION_MAJOR} EQUAL ${maxVal})
+  message(FATAL_ERROR "Project version number parsing failed round trip.\n"
+    "Expected: ${maxVal}\n"
+    "Computed: ${PROJECT_VERSION_MAJOR}"
+  )
+endif()