1*cf84ac9aSAndroid Build Coastguard Worker /*
2*cf84ac9aSAndroid Build Coastguard Worker * Copyright (c) 2013 Luca Clementi <[email protected]>
3*cf84ac9aSAndroid Build Coastguard Worker * Copyright (c) 2013-2018 The strace developers.
4*cf84ac9aSAndroid Build Coastguard Worker *
5*cf84ac9aSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*cf84ac9aSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*cf84ac9aSAndroid Build Coastguard Worker * are met:
8*cf84ac9aSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
9*cf84ac9aSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*cf84ac9aSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
11*cf84ac9aSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
12*cf84ac9aSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
13*cf84ac9aSAndroid Build Coastguard Worker * 3. The name of the author may not be used to endorse or promote products
14*cf84ac9aSAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*cf84ac9aSAndroid Build Coastguard Worker *
16*cf84ac9aSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*cf84ac9aSAndroid Build Coastguard Worker * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*cf84ac9aSAndroid Build Coastguard Worker * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*cf84ac9aSAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*cf84ac9aSAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*cf84ac9aSAndroid Build Coastguard Worker * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*cf84ac9aSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*cf84ac9aSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*cf84ac9aSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*cf84ac9aSAndroid Build Coastguard Worker * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*cf84ac9aSAndroid Build Coastguard Worker */
27*cf84ac9aSAndroid Build Coastguard Worker
28*cf84ac9aSAndroid Build Coastguard Worker #include "defs.h"
29*cf84ac9aSAndroid Build Coastguard Worker #include <limits.h>
30*cf84ac9aSAndroid Build Coastguard Worker
31*cf84ac9aSAndroid Build Coastguard Worker #include "largefile_wrappers.h"
32*cf84ac9aSAndroid Build Coastguard Worker #include "mmap_cache.h"
33*cf84ac9aSAndroid Build Coastguard Worker #include "mmap_notify.h"
34*cf84ac9aSAndroid Build Coastguard Worker #include "xstring.h"
35*cf84ac9aSAndroid Build Coastguard Worker
36*cf84ac9aSAndroid Build Coastguard Worker static unsigned int mmap_cache_generation;
37*cf84ac9aSAndroid Build Coastguard Worker
38*cf84ac9aSAndroid Build Coastguard Worker static void
mmap_cache_invalidate(struct tcb * tcp,void * unused)39*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_invalidate(struct tcb *tcp, void *unused)
40*cf84ac9aSAndroid Build Coastguard Worker {
41*cf84ac9aSAndroid Build Coastguard Worker #if SUPPORTED_PERSONALITIES > 1
42*cf84ac9aSAndroid Build Coastguard Worker if (tcp->currpers != DEFAULT_PERSONALITY) {
43*cf84ac9aSAndroid Build Coastguard Worker /* disable stack trace */
44*cf84ac9aSAndroid Build Coastguard Worker return;
45*cf84ac9aSAndroid Build Coastguard Worker }
46*cf84ac9aSAndroid Build Coastguard Worker #endif
47*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_generation++;
48*cf84ac9aSAndroid Build Coastguard Worker debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p",
49*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache ? tcp->mmap_cache->generation : 0,
50*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_generation, tcp,
51*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache ? tcp->mmap_cache->entry : 0);
52*cf84ac9aSAndroid Build Coastguard Worker }
53*cf84ac9aSAndroid Build Coastguard Worker
54*cf84ac9aSAndroid Build Coastguard Worker void
mmap_cache_enable(void)55*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_enable(void)
56*cf84ac9aSAndroid Build Coastguard Worker {
57*cf84ac9aSAndroid Build Coastguard Worker static bool use_mmap_cache;
58*cf84ac9aSAndroid Build Coastguard Worker
59*cf84ac9aSAndroid Build Coastguard Worker if (!use_mmap_cache) {
60*cf84ac9aSAndroid Build Coastguard Worker mmap_notify_register_client(mmap_cache_invalidate, NULL);
61*cf84ac9aSAndroid Build Coastguard Worker use_mmap_cache = true;
62*cf84ac9aSAndroid Build Coastguard Worker }
63*cf84ac9aSAndroid Build Coastguard Worker }
64*cf84ac9aSAndroid Build Coastguard Worker
65*cf84ac9aSAndroid Build Coastguard Worker /* deleting the cache */
66*cf84ac9aSAndroid Build Coastguard Worker static void
delete_mmap_cache(struct tcb * tcp,const char * caller)67*cf84ac9aSAndroid Build Coastguard Worker delete_mmap_cache(struct tcb *tcp, const char *caller)
68*cf84ac9aSAndroid Build Coastguard Worker {
69*cf84ac9aSAndroid Build Coastguard Worker debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s",
70*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache ? tcp->mmap_cache->generation : 0,
71*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_generation, tcp,
72*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache ? tcp->mmap_cache->entry : 0, caller);
73*cf84ac9aSAndroid Build Coastguard Worker
74*cf84ac9aSAndroid Build Coastguard Worker if (!tcp->mmap_cache)
75*cf84ac9aSAndroid Build Coastguard Worker return;
76*cf84ac9aSAndroid Build Coastguard Worker
77*cf84ac9aSAndroid Build Coastguard Worker while (tcp->mmap_cache->size) {
78*cf84ac9aSAndroid Build Coastguard Worker unsigned int i = --tcp->mmap_cache->size;
79*cf84ac9aSAndroid Build Coastguard Worker free(tcp->mmap_cache->entry[i].binary_filename);
80*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache->entry[i].binary_filename = NULL;
81*cf84ac9aSAndroid Build Coastguard Worker }
82*cf84ac9aSAndroid Build Coastguard Worker
83*cf84ac9aSAndroid Build Coastguard Worker free(tcp->mmap_cache->entry);
84*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache->entry = NULL;
85*cf84ac9aSAndroid Build Coastguard Worker
86*cf84ac9aSAndroid Build Coastguard Worker free(tcp->mmap_cache);
87*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache = NULL;
88*cf84ac9aSAndroid Build Coastguard Worker }
89*cf84ac9aSAndroid Build Coastguard Worker
90*cf84ac9aSAndroid Build Coastguard Worker /*
91*cf84ac9aSAndroid Build Coastguard Worker * caching of /proc/ID/maps for each process to speed up stack tracing
92*cf84ac9aSAndroid Build Coastguard Worker *
93*cf84ac9aSAndroid Build Coastguard Worker * The cache must be refreshed after syscalls that affect memory mappings,
94*cf84ac9aSAndroid Build Coastguard Worker * e.g. mmap, mprotect, munmap, execve.
95*cf84ac9aSAndroid Build Coastguard Worker */
96*cf84ac9aSAndroid Build Coastguard Worker extern enum mmap_cache_rebuild_result
mmap_cache_rebuild_if_invalid(struct tcb * tcp,const char * caller)97*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_rebuild_if_invalid(struct tcb *tcp, const char *caller)
98*cf84ac9aSAndroid Build Coastguard Worker {
99*cf84ac9aSAndroid Build Coastguard Worker if (tcp->mmap_cache
100*cf84ac9aSAndroid Build Coastguard Worker && tcp->mmap_cache->generation != mmap_cache_generation)
101*cf84ac9aSAndroid Build Coastguard Worker delete_mmap_cache(tcp, caller);
102*cf84ac9aSAndroid Build Coastguard Worker
103*cf84ac9aSAndroid Build Coastguard Worker if (tcp->mmap_cache)
104*cf84ac9aSAndroid Build Coastguard Worker return MMAP_CACHE_REBUILD_READY;
105*cf84ac9aSAndroid Build Coastguard Worker
106*cf84ac9aSAndroid Build Coastguard Worker char filename[sizeof("/proc/4294967296/maps")];
107*cf84ac9aSAndroid Build Coastguard Worker xsprintf(filename, "/proc/%u/maps", tcp->pid);
108*cf84ac9aSAndroid Build Coastguard Worker
109*cf84ac9aSAndroid Build Coastguard Worker FILE *fp = fopen_stream(filename, "r");
110*cf84ac9aSAndroid Build Coastguard Worker if (!fp) {
111*cf84ac9aSAndroid Build Coastguard Worker perror_msg("fopen: %s", filename);
112*cf84ac9aSAndroid Build Coastguard Worker return MMAP_CACHE_REBUILD_NOCACHE;
113*cf84ac9aSAndroid Build Coastguard Worker }
114*cf84ac9aSAndroid Build Coastguard Worker
115*cf84ac9aSAndroid Build Coastguard Worker struct mmap_cache_t cache = {
116*cf84ac9aSAndroid Build Coastguard Worker .free_fn = delete_mmap_cache,
117*cf84ac9aSAndroid Build Coastguard Worker .generation = mmap_cache_generation
118*cf84ac9aSAndroid Build Coastguard Worker };
119*cf84ac9aSAndroid Build Coastguard Worker
120*cf84ac9aSAndroid Build Coastguard Worker /* start with a small dynamically-allocated array and then expand it */
121*cf84ac9aSAndroid Build Coastguard Worker size_t allocated = 0;
122*cf84ac9aSAndroid Build Coastguard Worker char buffer[PATH_MAX + 80];
123*cf84ac9aSAndroid Build Coastguard Worker
124*cf84ac9aSAndroid Build Coastguard Worker while (fgets(buffer, sizeof(buffer), fp) != NULL) {
125*cf84ac9aSAndroid Build Coastguard Worker unsigned long start_addr, end_addr, mmap_offset;
126*cf84ac9aSAndroid Build Coastguard Worker char read_bit;
127*cf84ac9aSAndroid Build Coastguard Worker char write_bit;
128*cf84ac9aSAndroid Build Coastguard Worker char exec_bit;
129*cf84ac9aSAndroid Build Coastguard Worker char shared_bit;
130*cf84ac9aSAndroid Build Coastguard Worker unsigned long major, minor;
131*cf84ac9aSAndroid Build Coastguard Worker char binary_path[sizeof(buffer)];
132*cf84ac9aSAndroid Build Coastguard Worker
133*cf84ac9aSAndroid Build Coastguard Worker if (sscanf(buffer, "%lx-%lx %c%c%c%c %lx %lx:%lx %*d %[^\n]",
134*cf84ac9aSAndroid Build Coastguard Worker &start_addr, &end_addr,
135*cf84ac9aSAndroid Build Coastguard Worker &read_bit, &write_bit, &exec_bit, &shared_bit,
136*cf84ac9aSAndroid Build Coastguard Worker &mmap_offset,
137*cf84ac9aSAndroid Build Coastguard Worker &major, &minor,
138*cf84ac9aSAndroid Build Coastguard Worker binary_path) != 10)
139*cf84ac9aSAndroid Build Coastguard Worker continue;
140*cf84ac9aSAndroid Build Coastguard Worker
141*cf84ac9aSAndroid Build Coastguard Worker /* skip mappings that have unknown protection */
142*cf84ac9aSAndroid Build Coastguard Worker if (!(read_bit == '-' || read_bit == 'r'))
143*cf84ac9aSAndroid Build Coastguard Worker continue;
144*cf84ac9aSAndroid Build Coastguard Worker if (!(write_bit == '-' || write_bit == 'w'))
145*cf84ac9aSAndroid Build Coastguard Worker continue;
146*cf84ac9aSAndroid Build Coastguard Worker if (!(exec_bit == '-' || exec_bit == 'x'))
147*cf84ac9aSAndroid Build Coastguard Worker continue;
148*cf84ac9aSAndroid Build Coastguard Worker if (!(shared_bit == 'p' || shared_bit == 's'))
149*cf84ac9aSAndroid Build Coastguard Worker continue;
150*cf84ac9aSAndroid Build Coastguard Worker
151*cf84ac9aSAndroid Build Coastguard Worker if (end_addr < start_addr) {
152*cf84ac9aSAndroid Build Coastguard Worker error_msg("%s: unrecognized file format", filename);
153*cf84ac9aSAndroid Build Coastguard Worker break;
154*cf84ac9aSAndroid Build Coastguard Worker }
155*cf84ac9aSAndroid Build Coastguard Worker
156*cf84ac9aSAndroid Build Coastguard Worker struct mmap_cache_entry_t *entry;
157*cf84ac9aSAndroid Build Coastguard Worker /*
158*cf84ac9aSAndroid Build Coastguard Worker * sanity check to make sure that we're storing
159*cf84ac9aSAndroid Build Coastguard Worker * non-overlapping regions in ascending order
160*cf84ac9aSAndroid Build Coastguard Worker */
161*cf84ac9aSAndroid Build Coastguard Worker if (cache.size > 0) {
162*cf84ac9aSAndroid Build Coastguard Worker entry = &cache.entry[cache.size - 1];
163*cf84ac9aSAndroid Build Coastguard Worker if (entry->start_addr == start_addr &&
164*cf84ac9aSAndroid Build Coastguard Worker entry->end_addr == end_addr) {
165*cf84ac9aSAndroid Build Coastguard Worker /* duplicate entry, e.g. [vsyscall] */
166*cf84ac9aSAndroid Build Coastguard Worker continue;
167*cf84ac9aSAndroid Build Coastguard Worker }
168*cf84ac9aSAndroid Build Coastguard Worker if (start_addr <= entry->start_addr ||
169*cf84ac9aSAndroid Build Coastguard Worker start_addr < entry->end_addr) {
170*cf84ac9aSAndroid Build Coastguard Worker debug_msg("%s: overlapping memory region: "
171*cf84ac9aSAndroid Build Coastguard Worker "\"%s\" [%08lx-%08lx] overlaps with "
172*cf84ac9aSAndroid Build Coastguard Worker "\"%s\" [%08lx-%08lx]",
173*cf84ac9aSAndroid Build Coastguard Worker filename, binary_path, start_addr,
174*cf84ac9aSAndroid Build Coastguard Worker end_addr, entry->binary_filename,
175*cf84ac9aSAndroid Build Coastguard Worker entry->start_addr, entry->end_addr);
176*cf84ac9aSAndroid Build Coastguard Worker continue;
177*cf84ac9aSAndroid Build Coastguard Worker }
178*cf84ac9aSAndroid Build Coastguard Worker }
179*cf84ac9aSAndroid Build Coastguard Worker
180*cf84ac9aSAndroid Build Coastguard Worker if (cache.size >= allocated)
181*cf84ac9aSAndroid Build Coastguard Worker cache.entry = xgrowarray(cache.entry, &allocated,
182*cf84ac9aSAndroid Build Coastguard Worker sizeof(*cache.entry));
183*cf84ac9aSAndroid Build Coastguard Worker
184*cf84ac9aSAndroid Build Coastguard Worker entry = &cache.entry[cache.size];
185*cf84ac9aSAndroid Build Coastguard Worker entry->start_addr = start_addr;
186*cf84ac9aSAndroid Build Coastguard Worker entry->end_addr = end_addr;
187*cf84ac9aSAndroid Build Coastguard Worker entry->mmap_offset = mmap_offset;
188*cf84ac9aSAndroid Build Coastguard Worker entry->protections = (
189*cf84ac9aSAndroid Build Coastguard Worker 0
190*cf84ac9aSAndroid Build Coastguard Worker | ((read_bit == 'r')? MMAP_CACHE_PROT_READABLE : 0)
191*cf84ac9aSAndroid Build Coastguard Worker | ((write_bit == 'w')? MMAP_CACHE_PROT_WRITABLE : 0)
192*cf84ac9aSAndroid Build Coastguard Worker | ((exec_bit == 'x')? MMAP_CACHE_PROT_EXECUTABLE: 0)
193*cf84ac9aSAndroid Build Coastguard Worker | ((shared_bit == 's')? MMAP_CACHE_PROT_SHARED : 0)
194*cf84ac9aSAndroid Build Coastguard Worker );
195*cf84ac9aSAndroid Build Coastguard Worker entry->major = major;
196*cf84ac9aSAndroid Build Coastguard Worker entry->minor = minor;
197*cf84ac9aSAndroid Build Coastguard Worker entry->binary_filename = xstrdup(binary_path);
198*cf84ac9aSAndroid Build Coastguard Worker cache.size++;
199*cf84ac9aSAndroid Build Coastguard Worker }
200*cf84ac9aSAndroid Build Coastguard Worker fclose(fp);
201*cf84ac9aSAndroid Build Coastguard Worker
202*cf84ac9aSAndroid Build Coastguard Worker if (!cache.size)
203*cf84ac9aSAndroid Build Coastguard Worker return MMAP_CACHE_REBUILD_NOCACHE;
204*cf84ac9aSAndroid Build Coastguard Worker
205*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache = xmalloc(sizeof(*tcp->mmap_cache));
206*cf84ac9aSAndroid Build Coastguard Worker memcpy(tcp->mmap_cache, &cache, sizeof(cache));
207*cf84ac9aSAndroid Build Coastguard Worker
208*cf84ac9aSAndroid Build Coastguard Worker debug_func_msg("tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s",
209*cf84ac9aSAndroid Build Coastguard Worker tcp->mmap_cache->generation, mmap_cache_generation,
210*cf84ac9aSAndroid Build Coastguard Worker tcp, tcp->mmap_cache->entry, caller);
211*cf84ac9aSAndroid Build Coastguard Worker
212*cf84ac9aSAndroid Build Coastguard Worker return MMAP_CACHE_REBUILD_RENEWED;
213*cf84ac9aSAndroid Build Coastguard Worker }
214*cf84ac9aSAndroid Build Coastguard Worker
215*cf84ac9aSAndroid Build Coastguard Worker struct mmap_cache_entry_t *
mmap_cache_search(struct tcb * tcp,unsigned long ip)216*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_search(struct tcb *tcp, unsigned long ip)
217*cf84ac9aSAndroid Build Coastguard Worker {
218*cf84ac9aSAndroid Build Coastguard Worker if (!tcp->mmap_cache)
219*cf84ac9aSAndroid Build Coastguard Worker return NULL;
220*cf84ac9aSAndroid Build Coastguard Worker
221*cf84ac9aSAndroid Build Coastguard Worker int lower = 0;
222*cf84ac9aSAndroid Build Coastguard Worker int upper = (int) tcp->mmap_cache->size - 1;
223*cf84ac9aSAndroid Build Coastguard Worker
224*cf84ac9aSAndroid Build Coastguard Worker while (lower <= upper) {
225*cf84ac9aSAndroid Build Coastguard Worker int mid = (upper + lower) / 2;
226*cf84ac9aSAndroid Build Coastguard Worker struct mmap_cache_entry_t *entry = &tcp->mmap_cache->entry[mid];
227*cf84ac9aSAndroid Build Coastguard Worker
228*cf84ac9aSAndroid Build Coastguard Worker if (ip >= entry->start_addr &&
229*cf84ac9aSAndroid Build Coastguard Worker ip < entry->end_addr)
230*cf84ac9aSAndroid Build Coastguard Worker return entry;
231*cf84ac9aSAndroid Build Coastguard Worker else if (ip < entry->start_addr)
232*cf84ac9aSAndroid Build Coastguard Worker upper = mid - 1;
233*cf84ac9aSAndroid Build Coastguard Worker else
234*cf84ac9aSAndroid Build Coastguard Worker lower = mid + 1;
235*cf84ac9aSAndroid Build Coastguard Worker }
236*cf84ac9aSAndroid Build Coastguard Worker return NULL;
237*cf84ac9aSAndroid Build Coastguard Worker }
238*cf84ac9aSAndroid Build Coastguard Worker
239*cf84ac9aSAndroid Build Coastguard Worker struct mmap_cache_entry_t *
mmap_cache_search_custom(struct tcb * tcp,mmap_cache_search_fn fn,void * data)240*cf84ac9aSAndroid Build Coastguard Worker mmap_cache_search_custom(struct tcb *tcp, mmap_cache_search_fn fn, void *data)
241*cf84ac9aSAndroid Build Coastguard Worker {
242*cf84ac9aSAndroid Build Coastguard Worker for (unsigned int i = 0; i < tcp->mmap_cache->size; i++) {
243*cf84ac9aSAndroid Build Coastguard Worker if (fn(tcp->mmap_cache->entry + i, data))
244*cf84ac9aSAndroid Build Coastguard Worker return tcp->mmap_cache->entry + i;
245*cf84ac9aSAndroid Build Coastguard Worker }
246*cf84ac9aSAndroid Build Coastguard Worker return NULL;
247*cf84ac9aSAndroid Build Coastguard Worker }
248