| 246 | } |
| 247 | |
| 248 | bool |
| 249 | AbstractProcessManager::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; |
nothing calls this directly
no test coverage detected