| 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: Denis Efremov <efremov@linux.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/block/floppy.c | 20 +++++++++----------- |
| 1 file changed, 9 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/block/floppy.c |
| +++ b/drivers/block/floppy.c |
| @@ -521,8 +521,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; |
| @@ -542,7 +542,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); |
| @@ -1435,7 +1434,7 @@ static int interpret_errors(void) |
| if (DP->flags & FTD_MSG) |
| DPRINT("Over/Underrun - retrying\n"); |
| bad = 0; |
| - } else if (*errors >= DP->max_errors.reporting) { |
| + } else if (floppy_errors >= DP->max_errors.reporting) { |
| print_errors(); |
| } |
| if (ST2 & ST2_WC || ST2 & ST2_BC) |
| @@ -2055,7 +2054,7 @@ static void bad_flp_intr(void) |
| if (!next_valid_format()) |
| return; |
| } |
| - err_count = ++(*errors); |
| + err_count = ++floppy_errors; |
| INFBOUND(DRWE->badness, err_count); |
| if (err_count > DP->max_errors.abort) |
| cont->done(0); |
| @@ -2200,9 +2199,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; |
| @@ -2677,7 +2675,7 @@ static int make_raw_rw_request(void) |
| */ |
| if (!direct || |
| (indirect * 2 > direct * 3 && |
| - *errors < DP->max_errors.read_track && |
| + floppy_errors < DP->max_errors.read_track && |
| ((!probing || |
| (DP->read_track & (1 << DRS->probed_format)))))) { |
| max_size = blk_rq_sectors(current_req); |
| @@ -2801,10 +2799,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; |
| } |
| |
| static void redo_fd_request(void) |
| @@ -2860,7 +2859,6 @@ do_request: |
| _floppy = floppy_type + DP->autodetect[DRS->probed_format]; |
| } else |
| probing = 0; |
| - errors = &(current_req->error_count); |
| tmp = make_raw_rw_request(); |
| if (tmp < 2) { |
| request_done(tmp); |