1 import cPickle
2 import cStringIO
3 import os
4 import time
5
6 from rekall import config
7 from rekall import io_manager
8 from rekall import obj
9 from rekall.ui import json_renderer
10 from rekall_lib import utils
11
12
13 config.DeclareOption(
14 "--cache", default="file", type="String",
15 choices=["file", "memory", "timed"],
16 help="Type of cache to use. ")
20
24
32
34 """Safe Unpickling.
35
36 Unpickle only safe primitives like tuples, dicts and
37 strings. Specifically does not allow arbitrary instances to be
38 recovered.
39 """
40 now = time.time()
41 unpickler = cPickle.Unpickler(cStringIO.StringIO(raw))
42 unpickler.find_global = None
43
44 try:
45 decoded = unpickler.load()
46 except Exception:
47 raise io_manager.DecodeError("Unable to unpickle cached object")
48
49 result = self.renderer.decoder.Decode(decoded)
50 self.session.logging.debug("Decoded in %s sec.", time.time() - now)
51
52 return result
53
61
62 - def Get(self, item, default=None):
64
65 - def Set(self, item, value, volatile=True):
66 _ = volatile
67 if value is None:
68 self.data.pop(item, None)
69 else:
70 self.data[item] = value
71
74
76 """Called to sync the cache to external storage if required."""
77
79 """Print the contents somewhat concisely."""
80 result = []
81 for k, v in self.data.iteritems():
82 if isinstance(v, obj.BaseObject):
83 v = repr(v)
84
85 value = "\n ".join(str(v).splitlines())
86 if len(value) > 100:
87 value = "%s ..." % value[:100]
88
89 result.append(" %s = %s" % (k, value))
90
91 return "{\n" + "\n".join(sorted(result)) + "\n}"
92
95 """A limited time Cache.
96
97 This is useful for live analysis to ensure that information is not stale.
98 """
99
100 @utils.safe_property
102
103 return self.data.get("cache_expiry_time", 600)
104
105 - def Get(self, item, default=None):
113
114 - def Set(self, item, value, volatile=True):
115 """Sets the item to the value.
116
117 The value will be cached for the expiry time if it is volatile (by
118 default). Non-volatile data will never expire.
119
120 Even on a live system, we cache information which can not change for the
121 life of the system (e.g. the profile or dtb values). These are marked
122 non-volatile and will not be expired.
123 """
124 if value is None:
125 self.data.pop(item, None)
126 else:
127 if volatile:
128 now = time.time()
129 else:
130 now = 2**63
131
132 self.data[item] = (value, now)
133
135 """Print the contents somewhat concisely."""
136 result = []
137 now = time.time()
138 for k, (v, timestamp) in self.data.items():
139 if timestamp + self.expire_time < now:
140 self.data.pop(k)
141 continue
142
143 if isinstance(v, obj.BaseObject):
144 v = repr(v)
145
146 value = "\n ".join(str(v).splitlines())
147 if len(value) > 1000:
148 value = "%s ..." % value[:1000]
149
150 result.append(" %s = %s" % (k, value))
151
152 return "{\n" + "\n".join(sorted(result)) + "\n}"
153
156 """A cache which syncs to a persistent on disk representation.
157 """
158
172
173 @utils.safe_property
175 if not self.enabled:
176 return
177
178 cache_dir = os.path.expandvars(
179 self.session.GetParameter("cache_dir", cached=False))
180
181 cache_dir = os.path.join(config.GetHomeDir(self.session), cache_dir)
182
183
184
185
186 if cache_dir != self.cache_dir:
187 self._io_manager = None
188 self.cache_dir = cache_dir
189
190 if self._io_manager is None and cache_dir:
191
192 if os.access(cache_dir, os.F_OK | os.R_OK | os.W_OK | os.X_OK):
193 self._io_manager = PicklingDirectoryIOManager(
194 "%s/sessions" % cache_dir, session=self.session,
195 mode="w")
196
197 self.cache_dir = cache_dir
198 else:
199 self.session.logging.warn(
200 "Cache directory inaccessible. Disabling.")
201 self.enabled = False
202
203 return self._io_manager
204
207
216
217 - def Get(self, item, default=None):
232
233 - def Set(self, item, value, volatile=True):
236
243
244 @utils.safe_property
246 return "%s/v1.0/sessions/%s" % (self._io_manager.location, self.name)
247
267
281
283 if self._io_manager:
284 return "<FileCache @ %s>" % self.location
285 else:
286 return "<FileCache (unbacked)>"
287
293
294 - def Test(self, address_space):
295 for offset, expected in self.test:
296 expected = utils.SmartStr(expected)
297 if (offset and expected !=
298 address_space.read(offset, len(expected))):
299 return False
300
301 return True
302
305 """Returns the path of a usable cache directory."""
306 cache_dir = os.path.expandvars(session.GetParameter("cache_dir"))
307
308 if not cache_dir:
309 raise io_manager.IOManagerError(
310 "Local profile cache is not configured - "
311 "add a cache_dir parameter to ~/.rekallrc.")
312
313
314 cache_dir = os.path.join(config.GetHomeDir(session), cache_dir)
315
316 if not os.access(cache_dir, os.F_OK | os.R_OK | os.W_OK | os.X_OK):
317 try:
318 os.makedirs(cache_dir)
319 except (IOError, OSError):
320 raise io_manager.IOManagerError(
321 "Unable to create or access cache directory %s" % cache_dir)
322
323 return cache_dir
324
325
326 -def Factory(session, cache_type):
338