/** * @brief PPP callback to retrieve current process info for the running OS. */ void on_get_current_process(CPUState *env, OsiProc **out_p) { OsiProc *p; PTR ts; p = (OsiProc *)g_malloc0(sizeof(OsiProc)); ts = get_task_struct(env, (_ESP & THREADINFO_MASK)); fill_osiproc(env, p, ts); *out_p = p; }
/** * @brief PPP callback to retrieve current process info for the running OS. */ void on_get_current_process(CPUState *env, OsiProc **out_p) { OsiProc *p = NULL; PTR ts; // target_long asid = panda_current_asid(env); ts = get_task_struct(env, (_ESP & THREADINFO_MASK)); if (ts) { // valid task struct // got a reasonable looking process. // return it and save in cache p = (OsiProc *)g_malloc0(sizeof(OsiProc)); fill_osiproc(env, p, ts); } *out_p = p; }
/** * @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; }