Advertisement
Guest User

Quarkys awesome ASAN

a guest
May 16th, 2020
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.56 KB | None | 0 0
  1. /****************************************************************
  2.  * This file is part of NUSspli.                                *
  3.  * (c) 2020 V10lator <v10lator@myway.de>                        *
  4.  *                                                              *
  5.  * Licensed under the MIT license (see LICENSE.txt for details) *
  6.  ****************************************************************/
  7.  
  8. // This is based on Quarkys awesome ASAN from
  9. // https://github.com/QuarkTheAwesome/RetroArch/blob/asan/wiiu/system/memory.c
  10. // Quarky gave permission to relicense these codes under the MIT license.
  11. // Copyright of Quarky applies to this file, too.
  12.  
  13. #include <wut-fixups.h>
  14.  
  15. #include <coreinit/memdefaultheap.h>
  16.  
  17. #include <memdebug.h>
  18. #include <utils.h>
  19.  
  20. #ifdef NUSSPLI_DEBUG
  21.  
  22. #include <string.h>
  23.  
  24. #include <coreinit/debug.h>
  25. #include <coreinit/dynload.h>
  26. #include <coreinit/memory.h>
  27. #include <coreinit/memexpheap.h>
  28.  
  29. typedef struct
  30. {
  31.     bool allocated;
  32.     void *addr;
  33.     size_t size;
  34.     void *owner;
  35. } lsan_allocation;
  36.  
  37. typedef struct
  38. {
  39.     char *name;
  40.     void *codeStart;
  41.     uint32_t unk01;
  42.     uint32_t codeSize;
  43.     void *dataStart;
  44.     uint32_t unk02;
  45.     uint32_t dataSize;
  46.     uint32_t unk03;
  47.     uint32_t unk04;
  48.     uint32_t unk05;
  49. } RPX_Info;
  50.  
  51. extern int OSDynLoad_GetRPLInfo(uint32_t unk01, uint32_t size, RPX_Info *out);
  52.  
  53. #define LSAN_ALLOCS_SZ 0x20000
  54. static lsan_allocation lsan_allocs[LSAN_ALLOCS_SZ];
  55. static MEMHeapHandle asan_heap;
  56. static void *asan_heap_mem;
  57. static unsigned int asan_sz;
  58.  
  59. static void *asan_shadow;
  60. static unsigned int asan_shadow_off;
  61. static bool asan_ready = false;
  62.  
  63. static void *codeStart;
  64. static void *codeEnd;
  65.  
  66. #define MEM_TO_SHADOW(ptr) (unsigned char*)((((void*)ptr - asan_heap_mem) >> 3) + asan_shadow)
  67. #define SET_SHADOW(shadow, ptr) (*shadow) |= 1 << (((unsigned int)ptr) & 0x7)
  68. #define CLR_SHADOW(shadow, ptr) (*shadow) &= ~(1 << (((unsigned int)ptr) & 0x7))
  69. #define GET_SHADOW(shadow, ptr) (*shadow >> (((unsigned int)ptr) & 0x7)) & 0x1
  70.  
  71. bool __asan_checkrange(void* ptr, size_t sz)
  72. {
  73.     if(ptr >= asan_heap_mem && ptr <= asan_shadow)
  74.         for(int i = 0; i < sz; i++)
  75.             if(!GET_SHADOW(MEM_TO_SHADOW(ptr + i), ptr + i))
  76.                 return false;
  77.     return true;
  78. }
  79.  
  80. void getSymbolName(void *ptr, char *out, int outLen)
  81. {
  82.     OSGetSymbolName((unsigned int)ptr, out, outLen);
  83.     if(ptr >= codeStart && ptr < codeEnd)
  84.     {
  85.         char* tmp = strchr(out, '|') + sizeof(char);
  86.         strcpy(out, tmp);
  87.     }
  88. }
  89.  
  90. void __asan_doreport(void* ptr, void* caller, const char* type)
  91. {
  92.     debugPrintf("======================== ASAN: out-of-bounds %s", type);
  93.    
  94.     char symbolName[128];
  95.     getSymbolName(caller, symbolName, 127);
  96.     debugPrintf("Source: 0x%08X: %s", caller, symbolName);
  97.    
  98.     //Thanks, LSAN!
  99.     int closest_over = -1, closest_under = -1, uaf = -1;
  100.     for(uint32_t i = 0; i < LSAN_ALLOCS_SZ; i++)
  101.     {
  102.         if(lsan_allocs[i].allocated)
  103.         {
  104.             if(ptr > lsan_allocs[i].addr + lsan_allocs[i].size)
  105.             {
  106.                 if(closest_over == -1 || ptr - (lsan_allocs[i].addr + lsan_allocs[i].size) < ptr - (lsan_allocs[closest_over].addr + lsan_allocs[closest_over].size))
  107.                     closest_over = i;
  108.             }
  109.             else if(ptr < lsan_allocs[i].addr)
  110.             {
  111.                 if (closest_under == -1 || lsan_allocs[i].addr - ptr < lsan_allocs[closest_under].addr - ptr)
  112.                     closest_under = i;
  113.             }
  114.         }
  115.         else if(ptr > lsan_allocs[i].addr && ptr < lsan_allocs[i].addr + lsan_allocs[i].size && uaf == -1)
  116.             uaf = i;
  117.     }
  118.    
  119.     debugPrintf("Bad %s was on address 0x%08X. Guessing possible issues:", type, ptr);
  120.     debugPrintf("Guess     Chunk      ChunkSz    Dist       ChunkOwner");
  121.     if(closest_over >= 0)
  122.     {
  123.         getSymbolName(lsan_allocs[closest_over].owner, symbolName, 127);
  124.         debugPrintf("Overflow  0x%08X 0x%08X 0x%08X %s", lsan_allocs[closest_over].addr, lsan_allocs[closest_over].size, ptr - (lsan_allocs[closest_over].addr + lsan_allocs[closest_over].size), symbolName);
  125.     }
  126.     if(closest_under >= 0)
  127.     {
  128.         getSymbolName(lsan_allocs[closest_under].owner, symbolName, 127);
  129.         debugPrintf("Underflow 0x%08X 0x%08X 0x%08X %s", lsan_allocs[closest_under].addr, lsan_allocs[closest_under].size, ptr - (lsan_allocs[closest_under].addr + lsan_allocs[closest_under].size), symbolName);
  130.     }
  131.     if(uaf >= 0)
  132.     {
  133.         getSymbolName(lsan_allocs[uaf].owner, symbolName, 127);
  134.         debugPrintf("UaF       0x%08X 0x%08X 0x%08X %s", lsan_allocs[uaf].addr, lsan_allocs[uaf].size, ptr - (lsan_allocs[uaf].addr + lsan_allocs[uaf].size), symbolName);
  135.     }
  136. }
  137.  
  138. void __asan_before_dynamic_init(const char *module_name)
  139. {
  140.     debugPrintf("STUB: __asan_before_dynamic_init(%s)", module_name);
  141. }
  142.  
  143. void __asan_after_dynamic_init()
  144. {
  145.     debugPrintf("STUB: __asan_after_dynamic_init()");
  146. }
  147.  
  148. void __asan_loadN_noabort(void* ptr, unsigned int size)
  149. {
  150.     if(asan_ready && !__asan_checkrange(ptr, (size_t)size))
  151.         __asan_doreport(ptr, __builtin_return_address(0), "load");
  152. }
  153.  
  154. void __asan_storeN_noabort(void* ptr, unsigned int size)
  155. {
  156.     if(asan_ready && !__asan_checkrange(ptr, (size_t)size))
  157.         __asan_doreport(ptr, __builtin_return_address(0), "store");
  158. }
  159.  
  160. #define ASAN_GENFUNC(type, num) void __asan_##type##num##_noabort(void* ptr) \
  161. { \
  162.     if(asan_ready && !__asan_checkrange(ptr, num)) \
  163.         __asan_doreport(ptr, __builtin_return_address(0), #type); \
  164. }
  165. ASAN_GENFUNC(load, 1);
  166. ASAN_GENFUNC(store, 1);
  167. ASAN_GENFUNC(load, 2);
  168. ASAN_GENFUNC(store, 2);
  169. ASAN_GENFUNC(load, 4);
  170. ASAN_GENFUNC(store, 4);
  171. ASAN_GENFUNC(load, 8);
  172. ASAN_GENFUNC(store, 8);
  173. ASAN_GENFUNC(load, 16);
  174. ASAN_GENFUNC(store, 16);
  175.  
  176. void __asan_handle_no_return()
  177. {
  178.     //We only do heap checking, so no need to fiddle here
  179.     debugPrintf("__asan_handle_no_return()");
  180. }
  181.  
  182. static inline void setShadow(void *ptr, uint32_t size) // inline so we don't have to use __builtin_return_address(1)
  183. {
  184.     if(ptr != NULL)
  185.     {
  186.         bool lsan_ok = false;
  187.         for(int i = 0; i < LSAN_ALLOCS_SZ; i++)
  188.             if(!lsan_allocs[i].allocated)
  189.             {
  190.                 lsan_allocs[i].allocated = true;
  191.                 lsan_allocs[i].addr = ptr;
  192.                 lsan_allocs[i].size = size;
  193.                 lsan_allocs[i].owner = __builtin_return_address(0);
  194.                 lsan_ok = true;
  195.                 break;
  196.             }
  197.        
  198.         if(!lsan_ok)
  199.             debugPrintf("[A/LSAN] WARNING: Too many allocs!");
  200.         else
  201.             for(size_t i = 0; i < size; i++)
  202.                 SET_SHADOW(MEM_TO_SHADOW(ptr + i), ptr + i);
  203.        
  204.     }
  205. }
  206.  
  207. void *ASANAllocAligned(uint32_t size, int align)
  208. {
  209.     void *ptr = MEMAllocFromExpHeapEx(asan_heap, size, align);
  210.     setShadow(ptr, size);
  211.     return ptr;
  212. }
  213.  
  214. void *ASANAlloc(uint32_t size)
  215. {
  216.     void *ptr = MEMAllocFromExpHeapEx(asan_heap, size, 4);
  217.     setShadow(ptr, size);
  218.     return ptr;
  219. }
  220.  
  221. void ASANFree(void *ptr)
  222. {
  223.     if(ptr == NULL)
  224.         return;
  225.    
  226.     size_t sz = 0;
  227.    
  228.     bool lsan_ok = false;
  229.     for(int i = 0; i < LSAN_ALLOCS_SZ; i++)
  230.     {
  231.         if(lsan_allocs[i].allocated && lsan_allocs[i].addr == ptr)
  232.         {
  233.             lsan_allocs[i].allocated = false;
  234.             sz = lsan_allocs[i].size; //Thanks, LSAN!
  235.             lsan_ok = true;
  236.             break;
  237.         }
  238.     }
  239.    
  240.     if(!lsan_ok)
  241.     {
  242.         debugPrintf("[LSAN] WARNING: attempted free 0x%08X; not in table!", ptr);
  243.         return;
  244.     }
  245.    
  246.     for(size_t i = 0; i < sz; i++)
  247.         CLR_SHADOW(MEM_TO_SHADOW(ptr + i), ptr + i);
  248.    
  249.     MEMFreeToExpHeap(asan_heap, ptr);
  250. }
  251.  
  252. MEMAllocFromDefaultHeapFn defaultAllocFn;
  253. MEMAllocFromDefaultHeapExFn defaultAllocAlignedFn;
  254. MEMFreeToDefaultHeapFn defaultFreeFn;
  255.  
  256. void injectASAN()
  257. {
  258.     MEMAllocFromDefaultHeap = ASANAlloc;
  259.     MEMAllocFromDefaultHeapEx = ASANAllocAligned;
  260.     MEMFreeToDefaultHeap = ASANFree;
  261. }
  262.  
  263. void initASAN()
  264. {
  265.     RPX_Info rpxInfo[1];
  266.     OSDynLoad_GetRPLInfo(0, 1, rpxInfo);
  267.     codeStart = rpxInfo[0].codeStart;
  268.     codeEnd = codeStart + rpxInfo[0].codeSize;
  269.    
  270.     for(uint32_t i = 0; i < LSAN_ALLOCS_SZ; i++)
  271.         lsan_allocs[i].allocated = false;
  272.    
  273.     debugPrintf("[LSAN] LSAN initialized. Stack from 0x%08X to 0x%08X.", codeStart, codeEnd);
  274.    
  275.     MEMHeapHandle mem2 = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
  276.     asan_sz = (MEMGetAllocatableSizeForExpHeapEx(mem2, 4) >> 2) & ~0x3;
  277.     asan_heap_mem = MEMAllocFromDefaultHeap(asan_sz << 1);
  278.    
  279.     asan_heap = MEMCreateExpHeapEx(asan_heap_mem, asan_sz, 0);
  280.     uint32_t asan_heap_sz = MEMGetTotalFreeSizeForExpHeap(asan_heap);
  281.    
  282.     char *multiplierName[2];
  283.     if(asan_heap_sz < 1024)
  284.         multiplierName[0] = "B";
  285.     else if(asan_heap_sz < 1024 * 1024)
  286.     {
  287.         asan_heap_sz >>= 10;
  288.         multiplierName[0] = "KB";
  289.     }
  290.     else
  291.     {
  292.         asan_heap_sz >>= 20;
  293.         multiplierName[0] = "MB";
  294.     }
  295.    
  296.     uint32_t wrapsize = asan_sz;
  297.     if(wrapsize < 1024)
  298.         multiplierName[1] = "B";
  299.     else if(wrapsize < 1024 * 1024)
  300.     {
  301.         wrapsize >>= 10;
  302.         multiplierName[1] = "KB";
  303.     }
  304.     else
  305.     {
  306.         wrapsize >>= 20;
  307.         multiplierName[1] = "MB";
  308.     }
  309.    
  310.     debugPrintf("[ASAN] Allocated wrapheap at 0x%08X, size %d %s. Avail RAM is %d %s.", asan_heap, wrapsize, multiplierName[1], asan_heap_sz, multiplierName[0]);
  311.    
  312.     asan_shadow = (void*)(((unsigned int)asan_heap_mem) + asan_sz);
  313.     asan_shadow_off = (unsigned int)asan_heap - (unsigned int)asan_shadow;
  314.    
  315.     OSBlockSet(asan_shadow, 0, asan_sz);
  316.  
  317.     debugPrintf("[ASAN] Shadow at 0x%08X. Final shadow address at 0x%08X, final alloced at 0x%08X", asan_shadow, asan_shadow + asan_sz, asan_heap_mem + (asan_sz << 1));
  318.     asan_ready = true;
  319.    
  320.     defaultAllocFn = MEMAllocFromDefaultHeap;
  321.     defaultAllocAlignedFn = MEMAllocFromDefaultHeapEx;
  322.     defaultFreeFn = MEMFreeToDefaultHeap;
  323.    
  324.     injectASAN();
  325. }
  326.  
  327. void deinitASAN()
  328. {
  329.     unsigned long long alc = 0;
  330.     for(uint32_t i = 0; i < LSAN_ALLOCS_SZ; i++)
  331.         if(lsan_allocs[i].allocated)
  332.             alc++;
  333.     debugPrintf("[LSAN] Currently allocated: %llu", alc);
  334.    
  335.     MEMAllocFromDefaultHeap = defaultAllocFn;
  336.     MEMAllocFromDefaultHeapEx = defaultAllocAlignedFn;
  337.     MEMFreeToDefaultHeap = defaultFreeFn;
  338.    
  339.     asan_ready = false;
  340.    
  341.     MEMDestroyExpHeap(asan_heap);
  342.     MEMFreeToDefaultHeap(asan_heap_mem);
  343. }
  344.  
  345. #endif // ifdef NUSSPLI_DEBUG
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement