1From f27c12d491955c94583512603bf32c4568f20929 Mon Sep 17 00:00:00 2001
2From: Michael Walz <code@serpedon.de>
3Date: Tue, 2 Feb 2021 00:50:29 +0100
4Subject: [PATCH] Store a copy of each serialized shared_ptr within the archive
5 to prevent the shared_ptr to be freed to early. (#667)
6
7The archives use the memory address pointed by the shared_ptr as a
8unique id which must not be reused during lifetime of the archive.
9Therefore, the archives stores a copy of it.
10This problem was also reported as CVE-2020-11105.
11
12[Retrieved from:
13https://github.com/USCiLab/cereal/commit/f27c12d491955c94583512603bf32c4568f20929]
14Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
15---
16 include/cereal/cereal.hpp       | 13 +++++++++++--
17 include/cereal/types/memory.hpp |  2 +-
18 2 files changed, 12 insertions(+), 3 deletions(-)
19
20diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp
21index 99bed9d6..f0d15e8b 100644
22--- a/include/cereal/cereal.hpp
23+++ b/include/cereal/cereal.hpp
24@@ -369,12 +369,17 @@ namespace cereal
25           point to the same data.
26
27           @internal
28-          @param addr The address (see shared_ptr get()) pointed to by the shared pointer
29+          @param sharedPointer The shared pointer itself (the adress is taked via get()).
30+                               The archive takes a copy to prevent the memory location to be freed
31+                               as long as the address is used as id. This is needed to prevent CVE-2020-11105.
32           @return A key that uniquely identifies the pointer */
33-      inline std::uint32_t registerSharedPointer( void const * addr )
34+      inline std::uint32_t registerSharedPointer(const std::shared_ptr<const void>& sharedPointer)
35       {
36+        void const * addr = sharedPointer.get();
37+
38         // Handle null pointers by just returning 0
39         if(addr == 0) return 0;
40+        itsSharedPointerStorage.push_back(sharedPointer);
41
42         auto id = itsSharedPointerMap.find( addr );
43         if( id == itsSharedPointerMap.end() )
44@@ -645,6 +650,10 @@ namespace cereal
45       //! Maps from addresses to pointer ids
46       std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
47
48+      //! Copy of shared pointers used in #itsSharedPointerMap to make sure they are kept alive
49+      //  during lifetime of itsSharedPointerMap to prevent CVE-2020-11105.
50+      std::vector<std::shared_ptr<const void>> itsSharedPointerStorage;
51+
52       //! The id to be given to the next pointer
53       std::uint32_t itsCurrentPointerId;
54
55diff --git a/include/cereal/types/memory.hpp b/include/cereal/types/memory.hpp
56index 59e9da9b..cac1f334 100644
57--- a/include/cereal/types/memory.hpp
58+++ b/include/cereal/types/memory.hpp
59@@ -263,7 +263,7 @@ namespace cereal
60   {
61     auto & ptr = wrapper.ptr;
62
63-    uint32_t id = ar.registerSharedPointer( ptr.get() );
64+    uint32_t id = ar.registerSharedPointer( ptr );
65     ar( CEREAL_NVP_("id", id) );
66
67     if( id & detail::msb_32bit )
68