io_u_qiter: Fix buffer overrun
PATCH 1/1 io_u_qiter: Fix buffer overrun
In io_u_queue.h the io_u_qiter macro is loops around io_u_queue structures. The problem comes with the end of loop initialisation:
i++, io_u = (q)->io_us[i]
For example, if io_us consists of one element and i is 0 then after the first iteration is completed i++, io_u = (q)->io_us[i] will access beyond the end of io_us.
Fix this by moving io_u initialisation to the expression part of the for loop (yuck).
Found by Dr Memory.
--- io_u_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
io_u_queue.h +1 -1
@@ -29,7 +29,7 @@ static inline int io_u_qempty(struct io_u_queue *q) }#define io_u_qiter (q, io_u, i) \ - for (i = 0, io_u = (q)->io_us[0]; i < (q)->nr; i++, io_u = (q)->io_us[i]) + for (i = 0; i < (q)->nr && (io_u = (q)->io_us[i]); i++)int io_u_qinit (struct io_u_queue *q,unsigned int nr);void io_u_qexit (struct io_u_queue *q);
Signature · 4 lines
1.8.5.3 -- Sitsofe | http://sucs.org/~sits/
Quoted 22 lines · Sitsofe Wheeler
In
io_u_queue.htheio_u_qitermacro is loops aroundio_u_queuestructures. The problem comes with the end of loop initialisation:
i++,io_u= (q)->io_us[i]
For example, ifio_usconsists of one element and i is 0 then after the first iteration is completed i++,io_u= (q)->io_us[i] will access beyond the end ofio_us.Fix this by moving
io_uinitialisation to the expression part of the for loop (yuck).Found by Dr Memory.
Signed-off-by Sitsofe Wheeler <[email protected]>--- io_u_queue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)io_u_queue.h +0
-0
io_u_queue.h static inline int io_u_qempty(struct io_u_queue *q) · line 32
Quoted 5 lines
io_u_queue.h +1
-1@@ -29,7 +29,7 @@ static inline int io_u_qempty(struct io_u_queue *q) }#define io_u_qiter (q, io_u, i) \ - for (i = 0, io_u = (q)->io_us[0]; i < (q)->nr; i++, io_u = (q)->io_us[i]) + for (i = 0; i < (q)->nr && (io_u = (q)->io_us[i]); i++)
Initially I didn't see the issue, but then I realized that ->io_us is a pointer to the io_u pointer. So it is an issue. The fix isn't super pretty, but it gets rid of the bug, so I'll apply it. It might be nicer to split it into a top and bottom define.
Signature · 1 line
Jens Axboe
Quoted 5 lines · Jens Axboe
Initially I didn't see the issue, but then I realized that ->io_us is a pointer to the
io_upointer. So it is an issue. The fix isn't super pretty, but it gets rid of the bug, so I'll apply it. It might be nicer to split it into a top and bottom define.
Can you explain this top and bottom define more - would this let me turn it into a while loop?
The only reason for the current abuse was because I couldn't think of a another way to fix it while preserving the macro...
Signature · 1 line
Sitsofe | http://sucs.org/~sits/
Quoted 7 lines · Sitsofe Wheeler
Quoted 5 lines · Jens Axboe
Initially I didn't see the issue, but then I realized that ->io_us is a pointer to the
io_upointer. So it is an issue. The fix isn't super pretty, but it gets rid of the bug, so I'll apply it. It might be nicer to split it into a top and bottom define.
Quoted 5 lines
Can you explain this top and bottom define more - would this let me turn it into a while loop?
The only reason for the current abuse was because I couldn't think of a another way to fix it while preserving the macro...
Basically you turn it into a do-while with two macros. Ala the below, completely untested...
backend.c +2 -2
@@ -255,13 +255,13 @@ static void cleanup_pending_aio(struct thread_data *td)struct io_u *io_u;int i; - io_u_qiter(&td->io_u_all, io_u, i) { + io_u_do_qiter(&td->io_u_all, io_u, i) {if (io_u->flags &IO_U_F_FLIGHT ) { r = td->io_ops->cancel (td, io_u);if (!r)put_io_u (td, io_u); } - } + }while_each_io_u (&td->io_u_all, io_u, i); }if (td->cur_depth)
engines/posixaio.c +2 -2
@@ -111,7 +111,7 @@ static int fio_posixaio_getevents(struct thread_data *td, unsigned int min, restart:memset (suspend_list,0 ,sizeof (*suspend_list)); suspend_entries =0 ; - io_u_qiter(&td->io_u_all, io_u, i) { + io_u_do_qiter(&td->io_u_all, io_u, i) {int err;if (io_u->seen || !(io_u->flags &IO_U_F_FLIGHT ))
@@ -138,7 +138,7 @@ restart: io_u->resid = io_u->xfer_buflen - retval; }else io_u->error = err; - } + }while_each_io_u (&td->io_u_all, io_u, i);if (r >= min)return r;
engines/windowsaio.c +2 -2
@@ -275,7 +275,7 @@ static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min, } do { - io_u_qiter(&td->io_u_all, io_u, i) { + io_u_do_qiter(&td->io_u_all, io_u, i) { if (!(io_u->flags & IO_U_F_FLIGHT)) continue;
@@ -290,7 +290,7 @@ static int fio_windowsaio_getevents(struct thread_data *td, unsigned int min,if (dequeued >= min)break ; - } + }while_each_io_u (&td->io_u_all, io_u, i);if (dequeued < min) { status =WaitForSingleObject (wd->iocomplete_event, mswait);
io_u_queue.h +8 -2
@@ -28,8 +28,14 @@ static inline int io_u_qempty(struct io_u_queue *q)return !q->nr; } -#define io_u_qiter (q, io_u, i) \ - for (i = 0; i < (q)->nr && (io_u = (q)->io_us[i]); i++) +#define io_u_do_qiter (q, io_u, i) \ + (i) = 0; \ + do { \ + (io_u) = (q)->io_us[i]; \ + (i)++; \ + +#define while_each_io_u (q, io_u, i) \ + } while ((i) < (q)->nr); \int io_u_qinit (struct io_u_queue *q,unsigned int nr);void io_u_qexit (struct io_u_queue *q);
Signature · 1 line
Jens Axboe