/** * @brief PPP callback to retrieve OsiModules from the running OS. * * Current implementation returns all the memory areas mapped by the * process and the files they were mapped from. Libraries that have * many mappings will appear multiple times. * * @todo Remove duplicates from results. */ void on_get_libraries(CPUState *env, OsiProc *p, OsiModules **out_ms) { PTR ts_first, ts_current; target_ulong current_pid; OsiModules *ms; OsiModule *m; uint32_t ms_capacity = 16; PTR vma_first, vma_current; // Find the process with the indicated pid. ts_first = ts_current = get_task_struct(env, (_ESP & THREADINFO_MASK)); if (ts_current == (PTR)NULL) goto error0; do { if ((current_pid = get_pid(env, ts_current)) == p->pid) break; ts_current = get_task_struct_next(env, ts_current); } while(ts_current != (PTR)NULL && ts_current != ts_first); // memory read error or process not found if (ts_current == (PTR)NULL || current_pid != p->pid) goto error0; // Read the module info for the process. vma_first = vma_current = get_vma_first(env, ts_current); if (vma_current == (PTR)NULL) goto error0; ms = (OsiModules *)g_malloc0(sizeof(OsiModules)); ms->module = g_new(OsiModule, ms_capacity); do { if (ms->num == ms_capacity) { ms_capacity *= 2; ms->module = g_renew(OsiModule, ms->module, ms_capacity); } m = &ms->module[ms->num++]; memset(m, 0, sizeof(OsiModule)); fill_osimodule(env, m, vma_current); vma_current = get_vma_next(env, vma_current); } while(vma_current != (PTR)NULL && vma_current != vma_first); *out_ms = ms; return; error0: *out_ms = NULL; return; }
/** * @brief PPP callback to retrieve OsiModules from the running OS. * * Current implementation returns all the memory areas mapped by the * process and the files they were mapped from. Libraries that have * many mappings will appear multiple times. * * @todo Remove duplicates from results. */ void on_get_libraries(CPUState *env, OsiProc *p, OsiModules **out_ms) { PTR ts_first, ts_current; target_ulong current_pid; OsiModules *ms; OsiModule *m; uint32_t ms_capacity = 16; PTR vma_first, vma_current; #ifdef OSI_LINUX_LIST_THREADS PTR tg_first, tg_next; #endif // Get a starting process. ts_first = ts_current = get_task_struct(env, (_ESP & THREADINFO_MASK)); if (ts_current == (PTR)NULL) goto error0; if (ts_current+ki.task.thread_group_offset != get_thread_group(env, ts_current)) { ts_first = ts_current = get_task_struct_next(env, ts_current); } // Find the process that matches p->pid. // XXX: We could probably just use p->offset instead of traversing // the process list. // XXX: An infinite loop will be triggered if p is a thread and // OSI_LINUX_LIST_THREADS is not enabled. do { if ((current_pid = get_pid(env, ts_current)) == p->pid) goto pid_found; #ifdef OSI_LINUX_LIST_THREADS tg_first = ts_current+ki.task.thread_group_offset; while ((tg_next = get_thread_group(env, ts_current)) != tg_first) { ts_current = tg_next-ki.task.thread_group_offset; if ((current_pid = get_pid(env, ts_current)) == p->pid) goto pid_found; } ts_current = tg_first-ki.task.thread_group_offset; #endif ts_current = get_task_struct_next(env, ts_current); } while(ts_current != (PTR)NULL && ts_current != ts_first); pid_found: // memory read error or process not found if (ts_current == (PTR)NULL || current_pid != p->pid) goto error0; // Read the module info for the process. vma_first = vma_current = get_vma_first(env, ts_current); if (vma_current == (PTR)NULL) goto error0; ms = (OsiModules *)g_malloc0(sizeof(OsiModules)); ms->module = g_new(OsiModule, ms_capacity); do { if (ms->num == ms_capacity) { ms_capacity *= 2; ms->module = g_renew(OsiModule, ms->module, ms_capacity); } m = &ms->module[ms->num++]; memset(m, 0, sizeof(OsiModule)); fill_osimodule(env, m, vma_current); vma_current = get_vma_next(env, vma_current); } while(vma_current != (PTR)NULL && vma_current != vma_first); *out_ms = ms; return; error0: *out_ms = NULL; return; }
/** * @brief PPP callback to retrieve process list from the running OS. */ void on_get_processes(CPUState *env, OsiProcs **out_ps) { PTR ts_first, ts_current; OsiProcs *ps; OsiProc *p; uint32_t ps_capacity = 16; ts_first = ts_current = get_task_struct(env, (_ESP & THREADINFO_MASK)); if (ts_current == (PTR)NULL) goto error0; // When thread_group points to itself, the task_struct belongs to a thread // (see kernel_structs.md for details). This will trigger an infinite loop // in the traversal loop. // Following next will lead us to a task_struct belonging to a process and // help avoid the condition. if (ts_current+ki.task.thread_group_offset != get_thread_group(env, ts_current)) { ts_first = ts_current = get_task_struct_next(env, ts_current); } ps = (OsiProcs *)g_malloc0(sizeof(OsiProcs)); ps->proc = g_new(OsiProc, ps_capacity); do { if (ps->num == ps_capacity) { ps_capacity *= 2; ps->proc = g_renew(OsiProc, ps->proc, ps_capacity); } p = &ps->proc[ps->num++]; // Garbage in p->name will cause fill_osiproc() to segfault. memset(p, 0, sizeof(OsiProc)); fill_osiproc(env, p, ts_current); #if 0 /*********************************************************/ // Test of fd -> name resolution. /*********************************************************/ for (int fdn=0; fdn<10; fdn++) { char *s = get_fd_name(env, ts_current, fdn); LOG_INFO("%s fd%d -> %s", p->name, fdn, s); g_free(s); } /*********************************************************/ #endif ts_current = get_task_struct_next(env, ts_current); } while(ts_current != (PTR)NULL && ts_current != ts_first); // memory read error if (ts_current == (PTR)NULL) goto error1; *out_ps = ps; return; error1: do { ps->num--; g_free(ps->proc[ps->num].name); } while (ps->num != 0); g_free(ps->proc); g_free(ps); error0: *out_ps = NULL; return; }
/** * @brief PPP callback to retrieve process list from the running OS. */ void on_get_processes(CPUState *env, OsiProcs **out_ps) { PTR ts_first, ts_current; OsiProcs *ps; OsiProc *p; uint32_t ps_capacity = 16; #ifdef OSI_LINUX_LIST_THREADS PTR tg_first, tg_next; #endif // Get a task_struct of a process to start iterating the process list. If // current task is a thread (ts->t_group != &ts->t_group), follow ts->next // to get to a process. // Always starting the traversal with a process has the benefits of: // a. Simplifying the traversal when OSI_LINUX_LIST_THREADS is disabled. // b. Avoiding an infinite loop when OSI_LINUX_LIST_THREADS is enabled and // the current task is a thread. // See kernel_structs.md for details. ts_first = ts_current = get_task_struct(env, (_ESP & THREADINFO_MASK)); if (ts_current == (PTR)NULL) goto error0; if (ts_current+ki.task.thread_group_offset != get_thread_group(env, ts_current)) { ts_first = ts_current = get_task_struct_next(env, ts_current); } ps = (OsiProcs *)g_malloc0(sizeof(OsiProcs)); ps->proc = g_new(OsiProc, ps_capacity); do { if (ps->num == ps_capacity) { ps_capacity *= 2; ps->proc = g_renew(OsiProc, ps->proc, ps_capacity); } p = &ps->proc[ps->num++]; memset(p, 0, sizeof(OsiProc)); // fill_osiproc() expects p to be zeroed-out. fill_osiproc(env, p, ts_current); #ifdef OSI_LINUX_LIST_THREADS // Traverse thread group list. // It is assumed that ts_current is a thread group leader. tg_first = ts_current+ki.task.thread_group_offset; while ((tg_next = get_thread_group(env, ts_current)) != tg_first) { ts_current = tg_next-ki.task.thread_group_offset; if (ps->num == ps_capacity) { ps_capacity *= 2; ps->proc = g_renew(OsiProc, ps->proc, ps_capacity); } p = &ps->proc[ps->num++]; memset(p, 0, sizeof(OsiProc)); // fill_osiproc() expects p to be zeroed-out. fill_osiproc(env, p, ts_current); } ts_current = tg_first-ki.task.thread_group_offset; #endif #if 0 /*********************************************************/ // Test of fd -> name resolution. /*********************************************************/ for (int fdn=0; fdn<256; fdn++) { char *s = get_fd_name(env, ts_current, fdn); LOG_INFO("%s fd%d -> %s", p->name, fdn, s); g_free(s); } /*********************************************************/ #endif ts_current = get_task_struct_next(env, ts_current); } while(ts_current != (PTR)NULL && ts_current != ts_first); // memory read error if (ts_current == (PTR)NULL) goto error1; *out_ps = ps; return; error1: do { ps->num--; g_free(ps->proc[ps->num].name); } while (ps->num != 0); g_free(ps->proc); g_free(ps); error0: *out_ps = NULL; return; }