1*7c3d14c8STreehugger Robot //===-- esan_shadow.h -------------------------------------------*- C++ -*-===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of EfficiencySanitizer, a family of performance tuners.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Shadow memory mappings for the esan run-time.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot #ifndef ESAN_SHADOW_H
16*7c3d14c8STreehugger Robot #define ESAN_SHADOW_H
17*7c3d14c8STreehugger Robot
18*7c3d14c8STreehugger Robot #include <sanitizer_common/sanitizer_platform.h>
19*7c3d14c8STreehugger Robot
20*7c3d14c8STreehugger Robot #if SANITIZER_WORDSIZE != 64
21*7c3d14c8STreehugger Robot #error Only 64-bit is supported
22*7c3d14c8STreehugger Robot #endif
23*7c3d14c8STreehugger Robot
24*7c3d14c8STreehugger Robot namespace __esan {
25*7c3d14c8STreehugger Robot
26*7c3d14c8STreehugger Robot #if SANITIZER_LINUX && defined(__x86_64__)
27*7c3d14c8STreehugger Robot // Linux x86_64
28*7c3d14c8STreehugger Robot //
29*7c3d14c8STreehugger Robot // Application memory falls into these 5 regions (ignoring the corner case
30*7c3d14c8STreehugger Robot // of PIE with a non-zero PT_LOAD base):
31*7c3d14c8STreehugger Robot //
32*7c3d14c8STreehugger Robot // [0x00000000'00000000, 0x00000100'00000000) non-PIE + heap
33*7c3d14c8STreehugger Robot // [0x00005500'00000000, 0x00005700'00000000) PIE
34*7c3d14c8STreehugger Robot // [0x00007e00'00000000, 0x00007fff'ff600000) libraries + stack, part 1
35*7c3d14c8STreehugger Robot // [0x00007fff'ff601000, 0x00008000'00000000) libraries + stack, part 2
36*7c3d14c8STreehugger Robot // [0xffffffff'ff600000, 0xffffffff'ff601000) vsyscall
37*7c3d14c8STreehugger Robot //
38*7c3d14c8STreehugger Robot // Although we can ignore the vsyscall for the most part as there are few data
39*7c3d14c8STreehugger Robot // references there (other sanitizers ignore it), we enforce a gap inside the
40*7c3d14c8STreehugger Robot // library region to distinguish the vsyscall's shadow, considering this gap to
41*7c3d14c8STreehugger Robot // be an invalid app region.
42*7c3d14c8STreehugger Robot // We disallow application memory outside of those 5 regions.
43*7c3d14c8STreehugger Robot // Our regions assume that the stack rlimit is less than a terabyte (otherwise
44*7c3d14c8STreehugger Robot // the Linux kernel's default mmap region drops below 0x7e00'), which we enforce
45*7c3d14c8STreehugger Robot // at init time (we can support larger and unlimited sizes for shadow
46*7c3d14c8STreehugger Robot // scaledowns, but it is difficult for 1:1 mappings).
47*7c3d14c8STreehugger Robot //
48*7c3d14c8STreehugger Robot // Our shadow memory is scaled from a 1:1 mapping and supports a scale
49*7c3d14c8STreehugger Robot // specified at library initialization time that can be any power-of-2
50*7c3d14c8STreehugger Robot // scaledown (1x, 2x, 4x, 8x, 16x, etc.).
51*7c3d14c8STreehugger Robot //
52*7c3d14c8STreehugger Robot // We model our shadow memory after Umbra, a library used by the Dr. Memory
53*7c3d14c8STreehugger Robot // tool: https://github.com/DynamoRIO/drmemory/blob/master/umbra/umbra_x64.c.
54*7c3d14c8STreehugger Robot // We use Umbra's scheme as it was designed to support different
55*7c3d14c8STreehugger Robot // offsets, it supports two different shadow mappings (which we may want to
56*7c3d14c8STreehugger Robot // use for future tools), and it ensures that the shadow of a shadow will
57*7c3d14c8STreehugger Robot // not overlap either shadow memory or application memory.
58*7c3d14c8STreehugger Robot //
59*7c3d14c8STreehugger Robot // This formula translates from application memory to shadow memory:
60*7c3d14c8STreehugger Robot //
61*7c3d14c8STreehugger Robot // shadow(app) = ((app & 0x00000fff'ffffffff) + offset) >> scale
62*7c3d14c8STreehugger Robot //
63*7c3d14c8STreehugger Robot // Where the offset for 1:1 is 0x00001300'00000000. For other scales, the
64*7c3d14c8STreehugger Robot // offset is shifted left by the scale, except for scales of 1 and 2 where
65*7c3d14c8STreehugger Robot // it must be tweaked in order to pass the double-shadow test
66*7c3d14c8STreehugger Robot // (see the "shadow(shadow)" comments below):
67*7c3d14c8STreehugger Robot // scale == 0: 0x00001300'000000000
68*7c3d14c8STreehugger Robot // scale == 1: 0x00002200'000000000
69*7c3d14c8STreehugger Robot // scale == 2: 0x00004400'000000000
70*7c3d14c8STreehugger Robot // scale >= 3: (0x00001300'000000000 << scale)
71*7c3d14c8STreehugger Robot //
72*7c3d14c8STreehugger Robot // Do not pass in the open-ended end value to the formula as it will fail.
73*7c3d14c8STreehugger Robot //
74*7c3d14c8STreehugger Robot // The resulting shadow memory regions for a 0 scaling are:
75*7c3d14c8STreehugger Robot //
76*7c3d14c8STreehugger Robot // [0x00001300'00000000, 0x00001400'00000000)
77*7c3d14c8STreehugger Robot // [0x00001800'00000000, 0x00001a00'00000000)
78*7c3d14c8STreehugger Robot // [0x00002100'00000000, 0x000022ff'ff600000)
79*7c3d14c8STreehugger Robot // [0x000022ff'ff601000, 0x00002300'00000000)
80*7c3d14c8STreehugger Robot // [0x000022ff'ff600000, 0x000022ff'ff601000]
81*7c3d14c8STreehugger Robot //
82*7c3d14c8STreehugger Robot // We also want to ensure that a wild access by the application into the shadow
83*7c3d14c8STreehugger Robot // regions will not corrupt our own shadow memory. shadow(shadow) ends up
84*7c3d14c8STreehugger Robot // disjoint from shadow(app):
85*7c3d14c8STreehugger Robot //
86*7c3d14c8STreehugger Robot // [0x00001600'00000000, 0x00001700'00000000)
87*7c3d14c8STreehugger Robot // [0x00001b00'00000000, 0x00001d00'00000000)
88*7c3d14c8STreehugger Robot // [0x00001400'00000000, 0x000015ff'ff600000]
89*7c3d14c8STreehugger Robot // [0x000015ff'ff601000, 0x00001600'00000000]
90*7c3d14c8STreehugger Robot // [0x000015ff'ff600000, 0x000015ff'ff601000]
91*7c3d14c8STreehugger Robot
92*7c3d14c8STreehugger Robot struct ApplicationRegion {
93*7c3d14c8STreehugger Robot uptr Start;
94*7c3d14c8STreehugger Robot uptr End;
95*7c3d14c8STreehugger Robot bool ShadowMergedWithPrev;
96*7c3d14c8STreehugger Robot };
97*7c3d14c8STreehugger Robot
98*7c3d14c8STreehugger Robot static const struct ApplicationRegion AppRegions[] = {
99*7c3d14c8STreehugger Robot {0x0000000000000000ull, 0x0000010000000000u, false},
100*7c3d14c8STreehugger Robot {0x0000550000000000u, 0x0000570000000000u, false},
101*7c3d14c8STreehugger Robot // We make one shadow mapping to hold the shadow regions for all 3 of these
102*7c3d14c8STreehugger Robot // app regions, as the mappings interleave, and the gap between the 3rd and
103*7c3d14c8STreehugger Robot // 4th scales down below a page.
104*7c3d14c8STreehugger Robot {0x00007e0000000000u, 0x00007fffff600000u, false},
105*7c3d14c8STreehugger Robot {0x00007fffff601000u, 0x0000800000000000u, true},
106*7c3d14c8STreehugger Robot {0xffffffffff600000u, 0xffffffffff601000u, true},
107*7c3d14c8STreehugger Robot };
108*7c3d14c8STreehugger Robot static const u32 NumAppRegions = sizeof(AppRegions)/sizeof(AppRegions[0]);
109*7c3d14c8STreehugger Robot
110*7c3d14c8STreehugger Robot // See the comment above: we do not currently support a stack size rlimit
111*7c3d14c8STreehugger Robot // equal to or larger than 1TB.
112*7c3d14c8STreehugger Robot static const uptr MaxStackSize = (1ULL << 40) - 4096;
113*7c3d14c8STreehugger Robot
114*7c3d14c8STreehugger Robot class ShadowMapping {
115*7c3d14c8STreehugger Robot public:
116*7c3d14c8STreehugger Robot static const uptr Mask = 0x00000fffffffffffu;
117*7c3d14c8STreehugger Robot // The scale and offset vary by tool.
118*7c3d14c8STreehugger Robot uptr Scale;
119*7c3d14c8STreehugger Robot uptr Offset;
initialize(uptr ShadowScale)120*7c3d14c8STreehugger Robot void initialize(uptr ShadowScale) {
121*7c3d14c8STreehugger Robot static const uptr OffsetArray[3] = {
122*7c3d14c8STreehugger Robot 0x0000130000000000u,
123*7c3d14c8STreehugger Robot 0x0000220000000000u,
124*7c3d14c8STreehugger Robot 0x0000440000000000u,
125*7c3d14c8STreehugger Robot };
126*7c3d14c8STreehugger Robot Scale = ShadowScale;
127*7c3d14c8STreehugger Robot if (Scale <= 2)
128*7c3d14c8STreehugger Robot Offset = OffsetArray[Scale];
129*7c3d14c8STreehugger Robot else
130*7c3d14c8STreehugger Robot Offset = OffsetArray[0] << Scale;
131*7c3d14c8STreehugger Robot }
132*7c3d14c8STreehugger Robot };
133*7c3d14c8STreehugger Robot extern ShadowMapping Mapping;
134*7c3d14c8STreehugger Robot #else
135*7c3d14c8STreehugger Robot // We'll want to use templatized functions over the ShadowMapping once
136*7c3d14c8STreehugger Robot // we support more platforms.
137*7c3d14c8STreehugger Robot #error Platform not supported
138*7c3d14c8STreehugger Robot #endif
139*7c3d14c8STreehugger Robot
getAppRegion(u32 i,uptr * Start,uptr * End)140*7c3d14c8STreehugger Robot static inline bool getAppRegion(u32 i, uptr *Start, uptr *End) {
141*7c3d14c8STreehugger Robot if (i >= NumAppRegions)
142*7c3d14c8STreehugger Robot return false;
143*7c3d14c8STreehugger Robot *Start = AppRegions[i].Start;
144*7c3d14c8STreehugger Robot *End = AppRegions[i].End;
145*7c3d14c8STreehugger Robot return true;
146*7c3d14c8STreehugger Robot }
147*7c3d14c8STreehugger Robot
148*7c3d14c8STreehugger Robot ALWAYS_INLINE
isAppMem(uptr Mem)149*7c3d14c8STreehugger Robot bool isAppMem(uptr Mem) {
150*7c3d14c8STreehugger Robot for (u32 i = 0; i < NumAppRegions; ++i) {
151*7c3d14c8STreehugger Robot if (Mem >= AppRegions[i].Start && Mem < AppRegions[i].End)
152*7c3d14c8STreehugger Robot return true;
153*7c3d14c8STreehugger Robot }
154*7c3d14c8STreehugger Robot return false;
155*7c3d14c8STreehugger Robot }
156*7c3d14c8STreehugger Robot
157*7c3d14c8STreehugger Robot ALWAYS_INLINE
appToShadow(uptr App)158*7c3d14c8STreehugger Robot uptr appToShadow(uptr App) {
159*7c3d14c8STreehugger Robot return (((App & ShadowMapping::Mask) + Mapping.Offset) >> Mapping.Scale);
160*7c3d14c8STreehugger Robot }
161*7c3d14c8STreehugger Robot
getShadowRegion(u32 i,uptr * Start,uptr * End)162*7c3d14c8STreehugger Robot static inline bool getShadowRegion(u32 i, uptr *Start, uptr *End) {
163*7c3d14c8STreehugger Robot if (i >= NumAppRegions)
164*7c3d14c8STreehugger Robot return false;
165*7c3d14c8STreehugger Robot u32 UnmergedShadowCount = 0;
166*7c3d14c8STreehugger Robot u32 AppIdx;
167*7c3d14c8STreehugger Robot for (AppIdx = 0; AppIdx < NumAppRegions; ++AppIdx) {
168*7c3d14c8STreehugger Robot if (!AppRegions[AppIdx].ShadowMergedWithPrev) {
169*7c3d14c8STreehugger Robot if (UnmergedShadowCount == i)
170*7c3d14c8STreehugger Robot break;
171*7c3d14c8STreehugger Robot UnmergedShadowCount++;
172*7c3d14c8STreehugger Robot }
173*7c3d14c8STreehugger Robot }
174*7c3d14c8STreehugger Robot if (AppIdx >= NumAppRegions || UnmergedShadowCount != i)
175*7c3d14c8STreehugger Robot return false;
176*7c3d14c8STreehugger Robot *Start = appToShadow(AppRegions[AppIdx].Start);
177*7c3d14c8STreehugger Robot // The formula fails for the end itself.
178*7c3d14c8STreehugger Robot *End = appToShadow(AppRegions[AppIdx].End - 1) + 1;
179*7c3d14c8STreehugger Robot // Merge with adjacent shadow regions:
180*7c3d14c8STreehugger Robot for (++AppIdx; AppIdx < NumAppRegions; ++AppIdx) {
181*7c3d14c8STreehugger Robot if (!AppRegions[AppIdx].ShadowMergedWithPrev)
182*7c3d14c8STreehugger Robot break;
183*7c3d14c8STreehugger Robot *Start = Min(*Start, appToShadow(AppRegions[AppIdx].Start));
184*7c3d14c8STreehugger Robot *End = Max(*End, appToShadow(AppRegions[AppIdx].End - 1) + 1);
185*7c3d14c8STreehugger Robot }
186*7c3d14c8STreehugger Robot return true;
187*7c3d14c8STreehugger Robot }
188*7c3d14c8STreehugger Robot
189*7c3d14c8STreehugger Robot ALWAYS_INLINE
isShadowMem(uptr Mem)190*7c3d14c8STreehugger Robot bool isShadowMem(uptr Mem) {
191*7c3d14c8STreehugger Robot // We assume this is not used on any critical performance path and so there's
192*7c3d14c8STreehugger Robot // no need to hardcode the mapping results.
193*7c3d14c8STreehugger Robot for (uptr i = 0; i < NumAppRegions; ++i) {
194*7c3d14c8STreehugger Robot if (Mem >= appToShadow(AppRegions[i].Start) &&
195*7c3d14c8STreehugger Robot Mem < appToShadow(AppRegions[i].End - 1) + 1)
196*7c3d14c8STreehugger Robot return true;
197*7c3d14c8STreehugger Robot }
198*7c3d14c8STreehugger Robot return false;
199*7c3d14c8STreehugger Robot }
200*7c3d14c8STreehugger Robot
201*7c3d14c8STreehugger Robot } // namespace __esan
202*7c3d14c8STreehugger Robot
203*7c3d14c8STreehugger Robot #endif /* ESAN_SHADOW_H */
204