int main(int argc, char **argv) { char src[10]; char dst[10]; int size = sizeof(src); int ret; // __copy_user(dst, src, size); if (*xyzzy) printf("hello\n"); getpid(&xyzzy); ret = validate_ptr(xyzzy); printf("ret=%d\n", ret); }
void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { uint64_t *pcstack_end = pcstack + pcstack_limit; volatile uint8_t *flags = (volatile uint8_t *)&cpu_core[cpu_get_id()].cpuc_dtrace_flags; unsigned long *sp; unsigned long *bos; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; *pcstack++ = (uint64_t)current->pid; if (pcstack >= pcstack_end) return; /***********************************************/ /* Linux provides a built in function which */ /* is good because stack walking is arch */ /* dependent. (save_stack_trace) */ /* */ /* Unfortunately this is options dependent */ /* (CONFIG_STACKTRACE) so we cannot use it. */ /* And its GPL anyhow, so we cannot copy */ /* it. */ /* */ /* Whats worse is that we might be compiled */ /* with a frame pointer (only on x86-32) so */ /* we have three scenarios to handle. */ /***********************************************/ /***********************************************/ /* Ye gods! The world is an awful place to */ /* live. The target process, may or may not */ /* have frame pointers. In fact, some */ /* frames may have it and some may not (eg */ /* different libraries may be compiled */ /* differently). */ /* */ /* Looks like distro owners dont care about */ /* debuggabiity, and give us no frame */ /* pointers. */ /* */ /* This function is really important and */ /* useful. On modern Linux systems, gdb */ /* (and pstack) contain all the smarts. In */ /* fact, pstack is often a wrapper around */ /* gdb - i.e. its so complex we cannot do */ /* this. */ /***********************************************/ /***********************************************/ /* Bear in mind that user stacks can be */ /* megabytes in size, vs kernel stacks */ /* which are limited to a few K (4 or 8K */ /* typically). */ /***********************************************/ // sp = current->thread.rsp; # if defined(__i386) bos = sp = KSTK_ESP(current); # define ALIGN_MASK 3 # else /***********************************************/ /* KSTK_ESP() doesnt exist for x86_64 (its */ /* set to -1). */ /***********************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) # if defined(KSTK_EIP) /***********************************************/ /* Handle ARM and more kernel independent, */ /* but might not exist. */ /***********************************************/ bos = sp = (unsigned long *) KSTK_EIP(current); # else bos = sp = (unsigned long *) task_pt_regs(current)->sp; # endif #else bos = sp = task_pt_regs(current)->rsp; #endif # define ALIGN_MASK 7 #endif /***********************************************/ /* Walk the stack. We cannot rely on a */ /* frame pointer at each level, and we */ /* really want to avoid probing every word */ /* in the stack - a large stack will eat */ /* cpu looking at thousands of entries. So */ /* try and heuristically see if we have a */ /* likely frame pointer to jump over the */ /* frame, but, if not, just go one word at */ /* a time. */ /* */ /* Try and be careful we dont walk outside */ /* the stack or walk backwards in the */ /* stack, too. */ /***********************************************/ { uintptr_t *spend = sp + 1024; struct vm_area_struct *vma = find_vma(current->mm, (unsigned long) sp); if (vma) spend = (uintptr_t *) (vma->vm_end - sizeof(int *)); /*printk("xbos=%p %p\n", bos, spend);*/ /***********************************************/ /* Have you ever looked at the output from */ /* GCC in amd64 mode? Things like: */ /* */ /* push %r12 */ /* push %rbp */ /* */ /* will make you come out in a cold sweat - */ /* no way to find the frame pointer, */ /* without doing what GDB does (ie read the */ /* DWARF stack unwind info). So, for now, */ /* you get some false positives in the */ /* output - but we try to be conservative. */ /***********************************************/ while (sp >= bos && sp < spend && validate_ptr(sp)) { /*printk(" %p %d: %p %d\n", sp, validate_ptr(sp), sp[0], validate_ptr(sp[0]));*/ if (validate_ptr((void *) sp[0])) { uintptr_t p = sp[-1]; /***********************************************/ /* Try and avoid false positives in stack */ /* entries - we want this to be an */ /* executable instruction. */ /***********************************************/ if (((unsigned long *) sp[0] < bos || (unsigned long *) sp[0] > spend) && (vma = find_vma(current->mm, sp[0])) != NULL && vma->vm_flags & VM_EXEC) { *pcstack++ = sp[0]; if (pcstack >= pcstack_end) break; } if (((int) p & ALIGN_MASK) == 0 && p > (uintptr_t) sp && p < (uintptr_t) spend) sp = (unsigned long *) p; } sp++; } } /***********************************************/ /* Erase anything else in the buffer to */ /* avoid confusion. */ /***********************************************/ while (pcstack < pcstack_end) *pcstack++ = (pc_t) NULL; }
bool sections_virtual_to_raw(BYTE* payload, SIZE_T payload_size, OUT BYTE* destAddress, OUT SIZE_T *raw_size_ptr) { if (payload == NULL) return false; bool is64b = is64bit(payload); BYTE* payload_nt_hdr = get_nt_hrds(payload); if (payload_nt_hdr == NULL) { printf("Invalid payload: %p\n", payload); return false; } IMAGE_FILE_HEADER *fileHdr = NULL; DWORD hdrsSize = 0; LPVOID secptr = NULL; if (is64b) { IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*) payload_nt_hdr; fileHdr = &(payload_nt_hdr64->FileHeader); hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders; secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader); } else { IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*) payload_nt_hdr; fileHdr = &(payload_nt_hdr32->FileHeader); hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders; secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader); } if (!validate_ptr(payload, payload_size, payload, hdrsSize)) { return false; } //copy payload's headers: memcpy(destAddress, payload, hdrsSize); //copy all the sections, one by one: printf("Coping sections:\n"); SIZE_T raw_end = 0; for (WORD i = 0; i < fileHdr->NumberOfSections; i++) { PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i)); if (!validate_ptr(payload, payload_size, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) { return false; } LPVOID section_mapped = (BYTE*) payload + next_sec->VirtualAddress; LPVOID section_raw_ptr = destAddress + next_sec->PointerToRawData; SIZE_T sec_size = next_sec->SizeOfRawData; raw_end = next_sec->SizeOfRawData + next_sec->PointerToRawData; if (next_sec->VirtualAddress + sec_size >= payload_size) { printf("[!] Virtual section size is out ouf bounds: %lx\n", sec_size); sec_size = SIZE_T(payload_size - next_sec->VirtualAddress); printf("[!] Truncated to maximal size: %lx\n", sec_size); } if (next_sec->VirtualAddress >= payload_size && sec_size != 0) { printf("[-] VirtualAddress of section is out ouf bounds: %lx\n", static_cast<SIZE_T>(next_sec->VirtualAddress)); return false; } if (next_sec->PointerToRawData + sec_size >= payload_size) { printf("[-] Raw section size is out ouf bounds: %lx\n", sec_size); return false; } printf("[+] %s to: %p\n", next_sec->Name, section_raw_ptr); memcpy(section_raw_ptr, section_mapped, sec_size); } if (raw_end > payload_size) raw_end = payload_size; if (raw_size_ptr != NULL) { (*raw_size_ptr) = raw_end; } return true; }
/*ARGSUSED*/ static void instr_provide_module(void *arg, struct modctl *ctl) { int i; struct module *mp = (struct module *) ctl; char *modname = mp->name; char *str = mp->strtab; char *name; par_module_t *pmp; int init; /***********************************************/ /* Possible memleak here...we allocate a */ /* parallel struct, but need to free if we */ /* are offloaded. */ /***********************************************/ pmp = par_alloc(mp, sizeof *pmp, &init); if (pmp->fbt_nentries) { /* * This module has some FBT entries allocated; we're afraid * to screw with it. */ return; } if (dtrace_here) printk("%s(%d):modname=%s num_symtab=%u\n", __FILE__, __LINE__, modname, (unsigned) mp->num_symtab); if (strcmp(modname, "dtracedrv") == 0) return; for (i = 1; i < mp->num_symtab; i++) { uint8_t *instr, *limit; Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i]; int dtrace_here = 0; if (strcmp(modname, "dummy") == 0) dtrace_here = 1; name = str + sym->st_name; if (sym->st_name == NULL || *name == '\0') continue; /***********************************************/ /* Linux re-encodes the symbol types. */ /***********************************************/ if (sym->st_info != 't' && sym->st_info != 'T') continue; // if (strstr(name, "init")) // continue; //if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;} #if 0 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) continue; /* * Weak symbols are not candidates. This could be made to * work (where weak functions and their underlying function * appear as two disjoint probes), but it's not simple. */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; #endif if (strstr(name, "dtrace_") == name && strstr(name, "dtrace_safe_") != name) { /* * Anything beginning with "dtrace_" may be called * from probe context unless it explitly indicates * that it won't be called from probe context by * using the prefix "dtrace_safe_". */ continue; } if (strstr(name, "dtracedrv_") == name) continue; if (strstr(name, "kdi_") == name || strstr(name, "kprobe") == name) { /* * Anything beginning with "kdi_" is a part of the * kernel debugger interface and may be called in * arbitrary context -- including probe context. */ continue; } if (strcmp(name, "_init") == 0) continue; if (strcmp(name, "_fini") == 0) continue; instr = (uint8_t *)sym->st_value; limit = (uint8_t *)(sym->st_value + sym->st_size); //printk("trying -- %02d %c:%s\n", i, sym->st_info, name); //HERE(); /***********************************************/ /* Ignore the init function of modules - we */ /* will never execute them now the module */ /* is loaded, and we dont want to be poking */ /* potential pages which dont exist in */ /* memory or which are being used for data. */ /***********************************************/ if (instr == (uint8_t *) mp->init) continue; /***********************************************/ /* We do have syms that appear to point to */ /* unmapped pages. Maybe these are freed */ /* pages after a driver loads. Double check */ /* - if /proc/kallsyms says its not there, */ /* then ignore it. */ /***********************************************/ if (!validate_ptr(instr)) continue; /***********************************************/ /* Look at the section this symbol is in - */ /* we dont want sections which can */ /* disappear or have disappeared (eg */ /* .init). */ /* */ /* I'm not sure I follow this code for all */ /* kernel releases - if we have the field, */ /* it should have a fixed meaning, but some */ /* modules have bogus section attributes */ /* pointers (maybe pointers to freed */ /* segments?). Lets be careful out there. */ /* */ /* 20090425 Ok - heres the deal. In 2.6.9 */ /* (at least) the section table is */ /* allocated but only for sections which */ /* are SHF_ALLOC. This means the array of */ /* sections cannot be indexed by */ /* sym->st_shndx since the mappings are now */ /* bogus (kernel doesnt adjust the symbol */ /* section indexes). What we need to do is */ /* attempt to find the section by address. */ /***********************************************/ if (!instr_in_text_seg(mp, name, sym)) continue; /***********************************************/ /* We are good to go... */ /***********************************************/ instr_provide_function(mp, pmp, modname, name, (uint8_t *) sym->st_value, instr, limit, i); } }
/*ARGSUSED*/ static void fbt_provide_module(void *arg, struct modctl *ctl) { int i; struct module *mp = (struct module *) ctl; char *modname = mp->name; char *str = mp->strtab; char *name; par_module_t *pmp; int ret; # if 0 struct module *mp = ctl->mod_mp; char *str = mp->strings; int nsyms = mp->nsyms; Shdr *symhdr = mp->symhdr; char *name; size_t symsize; /* * Employees of dtrace and their families are ineligible. Void * where prohibited. */ if (strcmp(modname, "dtrace") == 0) return; TODO(); if (ctl->mod_requisites != NULL) { struct modctl_list *list; list = (struct modctl_list *)ctl->mod_requisites; for (; list != NULL; list = list->modl_next) { if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0) return; } } TODO(); /* * KMDB is ineligible for instrumentation -- it may execute in * any context, including probe context. */ if (strcmp(modname, "kmdbmod") == 0) return; if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) { /* * If this module doesn't (yet) have its string or symbol * table allocated, clear out. */ return; } symsize = symhdr->sh_entsize; # endif int init; if (strcmp(modname, "dtracedrv") == 0) return; /***********************************************/ /* Possible memleak here...we allocate a */ /* parallel struct, but need to free if we */ /* are offloaded. */ /***********************************************/ pmp = par_alloc(PARD_FBT, mp, sizeof *pmp, &init); if (pmp == NULL || pmp->fbt_nentries) { /* * This module has some FBT entries allocated; we're afraid * to screw with it. */ return; } if (dtrace_here) printk("%s(%d):modname=%s num_symtab=%u\n", dtrace_basename(__FILE__), __LINE__, modname, (unsigned) mp->num_symtab); for (i = 1; i < mp->num_symtab; i++) { uint8_t *instr, *limit; Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i]; int dtrace_here = 0; if (strcmp(modname, "dummy") == 0) dtrace_here = 1; name = str + sym->st_name; if (sym->st_name == NULL || *name == '\0') continue; /***********************************************/ /* Linux re-encodes the symbol types. */ /***********************************************/ if (sym->st_info != 't' && sym->st_info != 'T') continue; // if (strstr(name, "init")) // continue; //if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;} #if 0 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) continue; /* * Weak symbols are not candidates. This could be made to * work (where weak functions and their underlying function * appear as two disjoint probes), but it's not simple. */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; #endif if (strstr(name, "dtrace_") == name && strstr(name, "dtrace_safe_") != name) { /* * Anything beginning with "dtrace_" may be called * from probe context unless it explitly indicates * that it won't be called from probe context by * using the prefix "dtrace_safe_". */ continue; } if (strstr(name, "dtracedrv_") == name) continue; if (strstr(name, "kdi_") == name || strstr(name, "kprobe") == name) { /* * Anything beginning with "kdi_" is a part of the * kernel debugger interface and may be called in * arbitrary context -- including probe context. */ continue; } /* * Due to 4524008, _init and _fini may have a bloated st_size. * While this bug was fixed quite some time ago, old drivers * may be lurking. We need to develop a better solution to * this problem, such that correct _init and _fini functions * (the vast majority) may be correctly traced. One solution * may be to scan through the entire symbol table to see if * any symbol overlaps with _init. If none does, set a bit in * the module structure that this module has correct _init and * _fini sizes. This will cause some pain the first time a * module is scanned, but at least it would be O(N) instead of * O(N log N)... */ if (strcmp(name, "_init") == 0) continue; if (strcmp(name, "_fini") == 0) continue; /* * In order to be eligible, the function must begin with the * following sequence: * * pushl %esp * movl %esp, %ebp * * Note that there are two variants of encodings that generate * the movl; we must check for both. For 64-bit, we would * normally insist that a function begin with the following * sequence: * * pushq %rbp * movq %rsp, %rbp * * However, the compiler for 64-bit often splits these two * instructions -- and the first instruction in the function * is often not the pushq. As a result, on 64-bit we look * for any "pushq %rbp" in the function and we instrument * this with a breakpoint instruction. */ instr = (uint8_t *)sym->st_value; limit = (uint8_t *)(sym->st_value + sym->st_size); //printk("trying -- %02d %c:%s\n", i, sym->st_info, name); //HERE(); /***********************************************/ /* If we were called because a module is */ /* loaded after dtrace, then mp contains */ /* references to the .init section. We want */ /* to ignore these because the pages where */ /* the code resides will go away. Not only */ /* dont we want to put probes on */ /* non-existant pages, but /proc/dtrace/fbt */ /* will have problems and, fbt_enable will */ /* if that page is now used by some other */ /* driver. */ /***********************************************/ if (mp->module_init && mp->init_size && instr >= (uint8_t *) mp->module_init && instr < (uint8_t *) mp->module_init + mp->init_size) { continue; } /***********************************************/ /* We do have syms that appear to point to */ /* unmapped pages. Maybe these are freed */ /* pages after a driver loads. Double check */ /* - if /proc/kallsyms says its not there, */ /* then ignore it. */ /***********************************************/ if (!validate_ptr(instr)) continue; /***********************************************/ /* Look at the section this symbol is in - */ /* we dont want sections which can */ /* disappear or have disappeared (eg */ /* .init). */ /* */ /* I'm not sure I follow this code for all */ /* kernel releases - if we have the field, */ /* it should have a fixed meaning, but some */ /* modules have bogus section attributes */ /* pointers (maybe pointers to freed */ /* segments?). Lets be careful out there. */ /* */ /* 20090425 Ok - heres the deal. In 2.6.9 */ /* (at least) the section table is */ /* allocated but only for sections which */ /* are SHF_ALLOC. This means the array of */ /* sections cannot be indexed by */ /* sym->st_shndx since the mappings are now */ /* bogus (kernel doesnt adjust the symbol */ /* section indexes). What we need to do is */ /* attempt to find the section by address. */ /***********************************************/ ret = instr_in_text_seg(mp, name, sym); if (!ret) continue; /***********************************************/ /* We are good to go... */ /***********************************************/ fbt_provide_function(mp, pmp, modname, name, (uint8_t *) sym->st_value, instr, limit, i); } }
static int fbt_seq_show(struct seq_file *seq, void *v) { int i, s; int n = (int) (long) v; int target; fbt_probe_t *fbt = NULL; unsigned long size; unsigned long offset; char *modname = NULL; char name[KSYM_NAME_LEN]; char ibuf[64]; char *cp; //printk("%s v=%p\n", __func__, v); if (n == 1) { seq_printf(seq, "# count patchpoint opcode inslen modrm name\n"); return 0; } if (n > num_probes) return 0; /***********************************************/ /* Find first probe. This is incredibly */ /* slow and inefficient, but we dont want */ /* to waste memory keeping a list (an extra */ /* ptr for each probe). */ /***********************************************/ target = n; for (i = 0; target > 0 && i < fbt_probetab_size; i++) { fbt = fbt_probetab[i]; if (fbt == NULL) continue; target--; while (target > 0 && fbt) { if ((fbt = fbt->fbtp_hashnext) == NULL) break; target--; } } if (fbt == NULL) return 0; /***********************************************/ /* Dump the instruction so we can make sure */ /* we can single step them in the adjust */ /* cpu code. */ /* When a module is loaded and we parse the */ /* module, this may include syms which may */ /* get unmapped later on. So, trying to */ /* access a patchpoint instruction can GPF. */ /* We need to tread very carefully here not */ /* to GPF whilst catting /proc/dtrace/fbt. */ /* We actually need to disable these */ /* probes. */ /***********************************************/ //printk("fbtproc %p\n", fbt->fbtp_patchpoint); if (!validate_ptr(fbt->fbtp_patchpoint)) { s = 0xfff; strcpy(ibuf, "<unmapped>"); } else { s = dtrace_instr_size((uchar_t *) fbt->fbtp_patchpoint); ibuf[0] = '\0'; for (cp = ibuf, i = 0; i < s; i++) { snprintf(cp, sizeof ibuf - (cp - ibuf) - 3, "%02x ", fbt->fbtp_patchpoint[i] & 0xff); cp += 3; } } cp = (char *) my_kallsyms_lookup((unsigned long) fbt->fbtp_patchpoint, &size, &offset, &modname, name); # if defined(__arm__) seq_printf(seq, "%d %04u%c %p %08x %d %2d %s:%s:%s %s\n", n-1, # else seq_printf(seq, "%d %04u%c %p %02x %d %2d %s:%s:%s %s\n", n-1, # endif fbt->fbtp_fired, fbt->fbtp_overrun ? '*' : ' ', fbt->fbtp_patchpoint, fbt->fbtp_savedval, fbt->fbtp_inslen, fbt->fbtp_modrm, modname ? modname : "kernel", cp ? cp : "NULL", fbt->fbtp_type ? "return" : "entry", ibuf); return 0; }