Commit c85449d3 authored by Willy Tarreau's avatar Willy Tarreau Committed by Yongqiang Liu
Browse files

floppy: use a statically allocated error counter

mainline inclusion
from mainline-v5.18-rc6
commit f71f0139
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I582HK


CVE: CVE-2022-1652

--------------------------------

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: default avatarMinh Yuan <yuanmingbuaa@gmail.com>
Suggested-by: default avatarLinus Torvalds <torvalds@linuxfoundation.org>
Tested-by: default avatarDenis Efremov <efremov@linux.com>
Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarLuo Meng <luomeng12@huawei.com>

Conflicts:
	drivers/block/floppy.c
Reviewed-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: default avatarYongqiang Liu <liuyongqiang13@huawei.com>
parent 458d6423
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -520,8 +520,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;
@@ -541,7 +541,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);
@@ -1434,7 +1433,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)
@@ -2054,7 +2053,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);
@@ -2199,9 +2198,8 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
		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;
@@ -2684,7 +2682,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);
@@ -2818,13 +2816,13 @@ static int set_next_request(void)
		if (q) {
			current_req = blk_fetch_request(q);
			if (current_req) {
				current_req->error_count = 0;
				break;
				floppy_errors = 0;
				return 1;
			}
		}
	} while (fdc_queue != old_pos);

	return current_req != NULL;
	return 0;
}

static void redo_fd_request(void)
@@ -2880,7 +2878,6 @@ static void redo_fd_request(void)
		_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);