char * vmi_read_str_va( vmi_instance_t vmi, addr_t vaddr, vmi_pid_t pid) { unsigned char *memory = NULL; char *rtnval = NULL; addr_t paddr = 0; addr_t pfn = 0; addr_t offset = 0; int len = 0; size_t read_len = 0; int read_more = 1; rtnval = NULL; while (read_more) { if (pid) { paddr = vmi_translate_uv2p(vmi, vaddr + len, pid); } else { paddr = vmi_translate_kv2p(vmi, vaddr + len); } if (!paddr) { return rtnval; } /* access the memory */ pfn = paddr >> vmi->page_shift; offset = (vmi->page_size - 1) & paddr; memory = vmi_read_page(vmi, pfn); if (NULL == memory) { return rtnval; } /* Count new non-null characters */ read_len = 0; while (offset + read_len < vmi->page_size) { if (memory[offset + read_len] == '\0') { read_more = 0; break; } read_len++; } /* Otherwise, realloc, tack on the '\0' in case of errors and * get ready to read the next page. */ rtnval = realloc(rtnval, len + 1 + read_len); memcpy(&rtnval[len], &memory[offset], read_len); len += read_len; rtnval[len] = '\0'; } return rtnval; }
// Reads memory at a guest's physical address size_t vmi_read_pa( vmi_instance_t vmi, addr_t paddr, void *buf, size_t count) { //TODO not sure how to best handle this with respect to page size. Is this hypervisor dependent? // For example, the pfn for a given paddr should vary based on the size of the page where the // paddr resides. However, it is hard to know the page size from just the paddr. For now, just // assuming 4k pages and doing the read from there. unsigned char *memory = NULL; addr_t phys_address = 0; addr_t pfn = 0; addr_t offset = 0; size_t buf_offset = 0; while (count > 0) { size_t read_len = 0; /* access the memory */ phys_address = paddr + buf_offset; pfn = phys_address >> vmi->page_shift; offset = (vmi->page_size - 1) & phys_address; memory = vmi_read_page(vmi, pfn); if (NULL == memory) { return buf_offset; } /* determine how much we can read */ if ((offset + count) > vmi->page_size) { read_len = vmi->page_size - offset; } else { read_len = count; } /* do the read */ memcpy(((char *) buf) + (addr_t) buf_offset, memory + (addr_t) offset, read_len); /* set variables for next loop */ count -= read_len; buf_offset += read_len; } return buf_offset; }
/////////////////////////////////////////////////////////// // Classic read functions for access to memory status_t vmi_read( vmi_instance_t vmi, const access_context_t *ctx, size_t count, void *buf, size_t *bytes_read) { status_t ret = VMI_FAILURE; unsigned char *memory = NULL; addr_t start_addr = 0; addr_t paddr = 0; addr_t pfn = 0; addr_t offset = 0; addr_t dtb = 0; size_t buf_offset = 0; #ifdef ENABLE_SAFETY_CHECKS if (NULL == vmi) { dbprint(VMI_DEBUG_READ, "--%s: vmi passed as NULL, returning without read\n", __FUNCTION__); goto done; } if (NULL == ctx) { dbprint(VMI_DEBUG_READ, "--%s: ctx passed as NULL, returning without read\n", __FUNCTION__); goto done; } if (NULL == buf) { dbprint(VMI_DEBUG_READ, "--%s: buf passed as NULL, returning without read\n", __FUNCTION__); goto done; } #endif switch (ctx->translate_mechanism) { case VMI_TM_NONE: start_addr = ctx->addr; break; case VMI_TM_KERNEL_SYMBOL: #ifdef ENABLE_SAFETY_CHECKS if (!vmi->arch_interface || !vmi->os_interface || !vmi->kpgd) goto done; #endif dtb = vmi->kpgd; if ( VMI_FAILURE == vmi_translate_ksym2v(vmi, ctx->ksym, &start_addr) ) goto done; break; case VMI_TM_PROCESS_PID: #ifdef ENABLE_SAFETY_CHECKS if (!vmi->arch_interface || !vmi->os_interface) goto done; #endif if ( !ctx->pid ) dtb = vmi->kpgd; else if (ctx->pid > 0) { if ( VMI_FAILURE == vmi_pid_to_dtb(vmi, ctx->pid, &dtb) ) goto done; } if (!dtb) goto done; start_addr = ctx->addr; break; case VMI_TM_PROCESS_DTB: #ifdef ENABLE_SAFETY_CHECKS if (!vmi->arch_interface) goto done; #endif dtb = ctx->dtb; start_addr = ctx->addr; break; default: errprint("%s error: translation mechanism is not defined.\n", __FUNCTION__); goto done; } while (count > 0) { size_t read_len = 0; if (dtb) { if (VMI_SUCCESS != vmi_pagetable_lookup_cache(vmi, dtb, start_addr + buf_offset, &paddr)) goto done; } else { paddr = start_addr + buf_offset; } /* access the memory */ pfn = paddr >> vmi->page_shift; offset = (vmi->page_size - 1) & paddr; memory = vmi_read_page(vmi, pfn); if (NULL == memory) goto done; /* determine how much we can read */ if ((offset + count) > vmi->page_size) { read_len = vmi->page_size - offset; } else { read_len = count; } /* do the read */ memcpy(((char *) buf) + (addr_t) buf_offset, memory + (addr_t) offset, read_len); /* set variables for next loop */ count -= read_len; buf_offset += read_len; } ret = VMI_SUCCESS; done: if ( bytes_read ) *bytes_read = buf_offset; return ret; }
/////////////////////////////////////////////////////////// // Classic read functions for access to memory size_t vmi_read( vmi_instance_t vmi, access_context_t *ctx, void *buf, size_t count) { unsigned char *memory = NULL; addr_t start_addr = 0; addr_t paddr = 0; addr_t pfn = 0; addr_t offset = 0; addr_t dtb = 0; size_t buf_offset = 0; if (NULL == ctx) { dbprint(VMI_DEBUG_READ, "--%s: ctx passed as NULL, returning without read\n", __FUNCTION__); return 0; } if (NULL == buf) { dbprint(VMI_DEBUG_READ, "--%s: buf passed as NULL, returning without read\n", __FUNCTION__); return 0; } switch (ctx->translate_mechanism) { case VMI_TM_NONE: start_addr = ctx->addr; break; case VMI_TM_KERNEL_SYMBOL: if (!vmi->arch_interface || !vmi->os_interface) { return 0; } dtb = vmi->kpgd; start_addr = vmi_translate_ksym2v(vmi, ctx->ksym); break; case VMI_TM_PROCESS_PID: if (!vmi->arch_interface || !vmi->os_interface) { return 0; } if(ctx->pid) { dtb = vmi_pid_to_dtb(vmi, ctx->pid); } else { dtb = vmi->kpgd; } start_addr = ctx->addr; break; case VMI_TM_PROCESS_DTB: if (!vmi->arch_interface) { return 0; } dtb = ctx->dtb; start_addr = ctx->addr; break; default: errprint("%s error: translation mechanism is not defined.\n", __FUNCTION__); return 0; } while (count > 0) { size_t read_len = 0; if(dtb) { paddr = vmi_pagetable_lookup(vmi, dtb, start_addr + buf_offset); } else { paddr = start_addr + buf_offset; } if (!paddr) { return buf_offset; } /* access the memory */ pfn = paddr >> vmi->page_shift; offset = (vmi->page_size - 1) & paddr; memory = vmi_read_page(vmi, pfn); if (NULL == memory) { return buf_offset; } /* determine how much we can read */ if ((offset + count) > vmi->page_size) { read_len = vmi->page_size - offset; } else { read_len = count; } /* do the read */ memcpy(((char *) buf) + (addr_t) buf_offset, memory + (addr_t) offset, read_len); /* set variables for next loop */ count -= read_len; buf_offset += read_len; } return buf_offset; }
size_t vmi_read_va( vmi_instance_t vmi, addr_t vaddr, vmi_pid_t pid, void *buf, size_t count) { unsigned char *memory = NULL; addr_t paddr = 0; addr_t pfn = 0; addr_t offset = 0; size_t buf_offset = 0; if (NULL == buf) { dbprint("--%s: buf passed as NULL, returning without read\n", __FUNCTION__); return 0; } while (count > 0) { size_t read_len = 0; if (pid) { paddr = vmi_translate_uv2p(vmi, vaddr + buf_offset, pid); } else { paddr = vmi_translate_kv2p(vmi, vaddr + buf_offset); } if (!paddr) { return buf_offset; } /* access the memory */ pfn = paddr >> vmi->page_shift; offset = (vmi->page_size - 1) & paddr; memory = vmi_read_page(vmi, pfn); if (NULL == memory) { return buf_offset; } /* determine how much we can read */ if ((offset + count) > vmi->page_size) { read_len = vmi->page_size - offset; } else { read_len = count; } /* do the read */ memcpy(((char *) buf) + (addr_t) buf_offset, memory + (addr_t) offset, read_len); /* set variables for next loop */ count -= read_len; buf_offset += read_len; } return buf_offset; }