| From f71f01394f742fc4558b3f9f4c7ef4c4cf3b07c8 Mon Sep 17 00:00:00 2001 |
| From: Willy Tarreau <w@1wt.eu> |
| Date: Sun, 8 May 2022 11:37:07 +0200 |
| Subject: floppy: use a statically allocated error counter |
| |
| From: Willy Tarreau <w@1wt.eu> |
| |
| commit f71f01394f742fc4558b3f9f4c7ef4c4cf3b07c8 upstream. |
| |
| Interrupt handler bad_flp_intr() may cause a UAF on the recently freed |
| request just to increment the error count. There's no point keeping |
| that one in the request anyway, and since the interrupt handler uses a |
| static pointer to the error which cannot be kept in sync with the |
| pending request, better make it use a static error counter that's reset |
| for each new request. This reset now happens when entering |
| redo_fd_request() for a new request via set_next_request(). |
| |
| One initial concern about a single error counter was that errors on one |
| floppy drive could be reported on another one, but this problem is not |
| real given that the driver uses a single drive at a time, as that |
| PC-compatible controllers also have this limitation by using shared |
| signals. As such the error count is always for the "current" drive. |
| |
| Reported-by: Minh Yuan <yuanmingbuaa@gmail.com> |
| Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org> |
| Tested-by: Denis Efremov <efremov@linux.com> |
| Signed-off-by: Willy Tarreau <w@1wt.eu> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/block/floppy.c | 18 ++++++++---------- |
| 1 file changed, 8 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/block/floppy.c |
| +++ b/drivers/block/floppy.c |
| @@ -509,8 +509,8 @@ static unsigned long fdc_busy; |
| static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); |
| static DECLARE_WAIT_QUEUE_HEAD(command_done); |
| |
| -/* Errors during formatting are counted here. */ |
| -static int format_errors; |
| +/* errors encountered on the current (or last) request */ |
| +static int floppy_errors; |
| |
| /* Format request descriptor. */ |
| static struct format_descr format_req; |
| @@ -530,7 +530,6 @@ static struct format_descr format_req; |
| static char *floppy_track_buffer; |
| static int max_buffer_sectors; |
| |
| -static int *errors; |
| typedef void (*done_f)(int); |
| static const struct cont_t { |
| void (*interrupt)(void); |
| @@ -1455,7 +1454,7 @@ static int interpret_errors(void) |
| if (drive_params[current_drive].flags & FTD_MSG) |
| DPRINT("Over/Underrun - retrying\n"); |
| bad = 0; |
| - } else if (*errors >= drive_params[current_drive].max_errors.reporting) { |
| + } else if (floppy_errors >= drive_params[current_drive].max_errors.reporting) { |
| print_errors(); |
| } |
| if (reply_buffer[ST2] & ST2_WC || reply_buffer[ST2] & ST2_BC) |
| @@ -2095,7 +2094,7 @@ static void bad_flp_intr(void) |
| if (!next_valid_format(current_drive)) |
| return; |
| } |
| - err_count = ++(*errors); |
| + err_count = ++floppy_errors; |
| INFBOUND(write_errors[current_drive].badness, err_count); |
| if (err_count > drive_params[current_drive].max_errors.abort) |
| cont->done(0); |
| @@ -2241,9 +2240,8 @@ static int do_format(int drive, struct f |
| return -EINVAL; |
| } |
| format_req = *tmp_format_req; |
| - format_errors = 0; |
| cont = &format_cont; |
| - errors = &format_errors; |
| + floppy_errors = 0; |
| ret = wait_til_done(redo_format, true); |
| if (ret == -EINTR) |
| return -EINTR; |
| @@ -2761,10 +2759,11 @@ static int set_next_request(void) |
| current_req = list_first_entry_or_null(&floppy_reqs, struct request, |
| queuelist); |
| if (current_req) { |
| - current_req->error_count = 0; |
| + floppy_errors = 0; |
| list_del_init(¤t_req->queuelist); |
| + return 1; |
| } |
| - return current_req != NULL; |
| + return 0; |
| } |
| |
| /* Starts or continues processing request. Will automatically unlock the |
| @@ -2823,7 +2822,6 @@ do_request: |
| _floppy = floppy_type + drive_params[current_drive].autodetect[drive_state[current_drive].probed_format]; |
| } else |
| probing = 0; |
| - errors = &(current_req->error_count); |
| tmp = make_raw_rw_request(); |
| if (tmp < 2) { |
| request_done(tmp); |