MCPcopy Create free account
hub / github.com/bloomberg/pystack / isValidInterpreterState

Method isValidInterpreterState

src/pystack/_pystack/process.cpp:248–339  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

246}
247
248bool
249AbstractProcessManager::isValidInterpreterState(remote_addr_t addr) const
250{
251 /* The main idea here is that the PyInterpreterState has a pointer to the
252 current thread state:
253
254 typedef struct _is
255 {
256 struct PyThreadState *next;
257 struct PyThreadState *tstate_head;
258 } PyInterpreterState;
259
260 and the PyThreadState has a pointer back to the PyInterpreterState:
261
262 typedef struct PyThreadState
263 {
264 struct PyThreadState *next;
265 PyInterpreterState *interp;
266 ...
267 }
268
269 Using this information we can proceed as follows:
270
271 - Interpret the memory region at the current position as PyInterpreterState.
272 - Look at the address that the *tstate_head* member looks to, if the address
273 does not look like garbage, copy the memory that the address points to from
274 the remote process.
275 - Reinterpret the memory we just copied as a PyThreadState and look at the
276 address the *interp* member points to. This must point back to the address we
277 started with, this is, the address of we are assuming that corresponds to a
278 PyInterpreterState.
279 - As a last security check: try to construct a single frame and the
280 associated code object from the executing thread and check that the results
281 make sense. We need to do this because, although very rare, there may be some
282 random memory regions that have the previous properties but they are still
283 garbage.
284
285 If any of the previous steps fail, we continue with the next memory chunk
286 until we find the PyInterpreterState or we run out of chunks.
287 */
288 if (!isAddressValid(addr)) {
289 return false;
290 }
291
292 Structure<py_is_v> is(shared_from_this(), addr);
293 // The check for valid addresses may fail if the address falls in the stack
294 // space (there are "holes" in the address map space so just checking for
295 // min_addr < addr < max_addr does not guarantee a valid address) so we need
296 // to catch InvalidRemoteAddress exceptions.
297 try {
298 is.copyFromRemote();
299 } catch (RemoteMemCopyError& ex) {
300 return false;
301 }
302
303 auto current_thread_addr = is.getField(&py_is_v::o_tstate_head);
304 if (!isAddressValid(current_thread_addr)) {
305 return false;

Callers

nothing calls this directly

Calls 2

LOGClass · 0.85
copyFromRemoteMethod · 0.80

Tested by

no test coverage detected