-From 33b5b1783bcff0ca134b4d7b2b1e3da3d83b5f43 Mon Sep 17 00:00:00 2001
+From 26cf267767b46f0ea5c6312838085fa01c7a1b9c Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:20 +0300
Subject: floppy: fix div-by-zero in setup_format_params
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/block/floppy.c | 5 +++++
+ drivers/block/floppy.c | 5 +++++
1 file changed, 5 insertions(+)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 5fe9e899d2a6..3fca5246bbaf 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -2113,6 +2113,9 @@ static void setup_format_params(int trac
+@@ -2114,6 +2114,9 @@ static void setup_format_params(int track)
raw_cmd->kernel_data = floppy_track_buffer;
raw_cmd->length = 4 * F_SECT_PER_TRACK;
/* allow for about 30ms for data transport per track */
head_shift = (F_SECT_PER_TRACK + 5) / 6;
-@@ -3235,6 +3238,8 @@ static int set_geometry(unsigned int cmd
+@@ -3236,6 +3239,8 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
/* sanity checking for parameters. */
if (g->sect <= 0 ||
g->head <= 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
/* check if reserved bits are set */
(g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
+--
+2.20.1
+
-From 9b04609b784027968348796a18f601aed9db3789 Mon Sep 17 00:00:00 2001
+From 2e8dfc077179a0a9886c94e2467a392024d16f3a Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:22 +0300
Subject: floppy: fix invalid pointer dereference in drive_name
-From: Denis Efremov <efremov@ispras.ru>
-
-commit 9b04609b784027968348796a18f601aed9db3789 upstream.
+[ Upstream commit 9b04609b784027968348796a18f601aed9db3789 ]
This fixes the invalid pointer dereference in the drive_name function of
the floppy driver.
Signed-off-by: Denis Efremov <efremov@ispras.ru>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
+Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- drivers/block/floppy.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
+ drivers/block/floppy.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index e319fb6c96a7..013c25bad540 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3383,7 +3383,8 @@ static int fd_getgeo(struct block_device
+@@ -3384,7 +3384,8 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
{
size_t floppy_type_size = ARRAY_SIZE(floppy_type);
size_t i = 0;
-@@ -3394,6 +3395,9 @@ static bool valid_floppy_drive_params(co
+@@ -3395,6 +3396,9 @@ static bool valid_floppy_drive_params(const short autodetect[8])
return false;
}
return true;
}
-@@ -3523,7 +3527,8 @@ static int fd_locked_ioctl(struct block_
+@@ -3524,7 +3528,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
return -EINVAL;
*UDP = inparam.dp;
break;
+@@ -3723,7 +3728,7 @@ static int compat_setdrvprm(int drive,
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
+- if (!valid_floppy_drive_params(v.autodetect))
++ if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+ return -EINVAL;
+ mutex_lock(&floppy_mutex);
+ UDP->cmos = v.cmos;
+--
+2.20.1
+
-From ab1e593f24d8a821cb8b37e8c3562e72c4fb1cd0 Mon Sep 17 00:00:00 2001
+From 7f25f4a37e8351cf70762583aa024bd229466db5 Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:23 +0300
Subject: floppy: fix out-of-bounds read in copy_buffer
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/block/floppy.c | 6 ++++--
+ drivers/block/floppy.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 013c25bad540..35b2d2c86a1f 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3236,8 +3236,10 @@ static int set_geometry(unsigned int cmd
+@@ -3237,8 +3237,10 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
int cnt;
/* sanity checking for parameters. */
/* check for zero in F_SECT_PER_TRACK */
(unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
+--
+2.20.1
+
-From 5635f897ed83fd539df78e98ba69ee91592f9bb8 Mon Sep 17 00:00:00 2001
+From 57927747a6b775b792d184a51a53c6bf101e92c1 Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:21 +0300
Subject: floppy: fix out-of-bounds read in next_valid_format
-From: Denis Efremov <efremov@ispras.ru>
-
-commit 5635f897ed83fd539df78e98ba69ee91592f9bb8 upstream.
+[ Upstream commit 5635f897ed83fd539df78e98ba69ee91592f9bb8 ]
This fixes a global out-of-bounds read access in the next_valid_format
function of the floppy driver.
Signed-off-by: Denis Efremov <efremov@ispras.ru>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
+Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- drivers/block/floppy.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
+ drivers/block/floppy.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 3fca5246bbaf..e319fb6c96a7 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3383,6 +3383,20 @@ static int fd_getgeo(struct block_device
+@@ -3384,6 +3384,20 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
-@@ -3509,6 +3523,8 @@ static int fd_locked_ioctl(struct block_
+@@ -3510,6 +3524,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
*UDP = inparam.dp;
break;
case FDGETDRVPRM:
+@@ -3707,6 +3723,8 @@ static int compat_setdrvprm(int drive,
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
++ if (!valid_floppy_drive_params(v.autodetect))
++ return -EINVAL;
+ mutex_lock(&floppy_mutex);
+ UDP->cmos = v.cmos;
+ UDP->max_dtr = v.max_dtr;
+--
+2.20.1
+
bluetooth-6lowpan-search-for-destination-address-in-.patch
bluetooth-check-state-in-l2cap_disconnect_rsp.patch
bluetooth-validate-ble-connection-interval-updates.patch
-floppy-fix-div-by-zero-in-setup_format_params.patch
-floppy-fix-out-of-bounds-read-in-next_valid_format.patch
-floppy-fix-invalid-pointer-dereference-in-drive_name.patch
-floppy-fix-out-of-bounds-read-in-copy_buffer.patch
crypto-ghash-fix-unaligned-memory-access-in-ghash_setkey.patch
crypto-arm64-sha1-ce-correct-digest-for-empty-data-in-finup.patch
crypto-arm64-sha2-ce-correct-digest-for-empty-data-in-finup.patch
padata-use-smp_mb-in-padata_reorder-to-avoid-orphaned-padata-jobs.patch
9p-virtio-add-cleanup-path-in-p9_virtio_init.patch
pci-do-not-poll-for-pme-if-the-device-is-in-d3cold.patch
+take-floppy-compat-ioctls-to-sodding-floppy.c.patch
+floppy-fix-div-by-zero-in-setup_format_params.patch
+floppy-fix-out-of-bounds-read-in-next_valid_format.patch
+floppy-fix-invalid-pointer-dereference-in-drive_name.patch
+floppy-fix-out-of-bounds-read-in-copy_buffer.patch
--- /dev/null
+From b56b2384505e0d7032b45a5f4edbc3e451271c84 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Tue, 27 Jun 2017 15:47:56 -0400
+Subject: take floppy compat ioctls to sodding floppy.c
+
+[ Upstream commit 229b53c9bf4e1132a4aa6feb9632a7a1f1d08c5c ]
+
+all other drivers recognizing those ioctls are very much *not*
+biarch.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/compat_ioctl.c | 340 -----------------------------------------
+ drivers/block/floppy.c | 328 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 328 insertions(+), 340 deletions(-)
+
+diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
+index f678c733df40..d2c46454ffa8 100644
+--- a/block/compat_ioctl.c
++++ b/block/compat_ioctl.c
+@@ -4,7 +4,6 @@
+ #include <linux/cdrom.h>
+ #include <linux/compat.h>
+ #include <linux/elevator.h>
+-#include <linux/fd.h>
+ #include <linux/hdreg.h>
+ #include <linux/slab.h>
+ #include <linux/syscalls.h>
+@@ -209,318 +208,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
+ #define BLKBSZSET_32 _IOW(0x12, 113, int)
+ #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
+
+-struct compat_floppy_drive_params {
+- char cmos;
+- compat_ulong_t max_dtr;
+- compat_ulong_t hlt;
+- compat_ulong_t hut;
+- compat_ulong_t srt;
+- compat_ulong_t spinup;
+- compat_ulong_t spindown;
+- unsigned char spindown_offset;
+- unsigned char select_delay;
+- unsigned char rps;
+- unsigned char tracks;
+- compat_ulong_t timeout;
+- unsigned char interleave_sect;
+- struct floppy_max_errors max_errors;
+- char flags;
+- char read_track;
+- short autodetect[8];
+- compat_int_t checkfreq;
+- compat_int_t native_format;
+-};
+-
+-struct compat_floppy_drive_struct {
+- signed char flags;
+- compat_ulong_t spinup_date;
+- compat_ulong_t select_date;
+- compat_ulong_t first_read_date;
+- short probed_format;
+- short track;
+- short maxblock;
+- short maxtrack;
+- compat_int_t generation;
+- compat_int_t keep_data;
+- compat_int_t fd_ref;
+- compat_int_t fd_device;
+- compat_int_t last_checked;
+- compat_caddr_t dmabuf;
+- compat_int_t bufblocks;
+-};
+-
+-struct compat_floppy_fdc_state {
+- compat_int_t spec1;
+- compat_int_t spec2;
+- compat_int_t dtr;
+- unsigned char version;
+- unsigned char dor;
+- compat_ulong_t address;
+- unsigned int rawcmd:2;
+- unsigned int reset:1;
+- unsigned int need_configure:1;
+- unsigned int perp_mode:2;
+- unsigned int has_fifo:1;
+- unsigned int driver_version;
+- unsigned char track[4];
+-};
+-
+-struct compat_floppy_write_errors {
+- unsigned int write_errors;
+- compat_ulong_t first_error_sector;
+- compat_int_t first_error_generation;
+- compat_ulong_t last_error_sector;
+- compat_int_t last_error_generation;
+- compat_uint_t badness;
+-};
+-
+-#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
+-#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
+-#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
+-#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
+-#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
+-#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
+-#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
+-#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
+-
+-static struct {
+- unsigned int cmd32;
+- unsigned int cmd;
+-} fd_ioctl_trans_table[] = {
+- { FDSETPRM32, FDSETPRM },
+- { FDDEFPRM32, FDDEFPRM },
+- { FDGETPRM32, FDGETPRM },
+- { FDSETDRVPRM32, FDSETDRVPRM },
+- { FDGETDRVPRM32, FDGETDRVPRM },
+- { FDGETDRVSTAT32, FDGETDRVSTAT },
+- { FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+- { FDGETFDCSTAT32, FDGETFDCSTAT },
+- { FDWERRORGET32, FDWERRORGET }
+-};
+-
+-#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
+-
+-static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
+- unsigned int cmd, unsigned long arg)
+-{
+- mm_segment_t old_fs = get_fs();
+- void *karg = NULL;
+- unsigned int kcmd = 0;
+- int i, err;
+-
+- for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+- if (cmd == fd_ioctl_trans_table[i].cmd32) {
+- kcmd = fd_ioctl_trans_table[i].cmd;
+- break;
+- }
+- if (!kcmd)
+- return -EINVAL;
+-
+- switch (cmd) {
+- case FDSETPRM32:
+- case FDDEFPRM32:
+- case FDGETPRM32:
+- {
+- compat_uptr_t name;
+- struct compat_floppy_struct __user *uf;
+- struct floppy_struct *f;
+-
+- uf = compat_ptr(arg);
+- f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- if (cmd == FDGETPRM32)
+- break;
+- err = __get_user(f->size, &uf->size);
+- err |= __get_user(f->sect, &uf->sect);
+- err |= __get_user(f->head, &uf->head);
+- err |= __get_user(f->track, &uf->track);
+- err |= __get_user(f->stretch, &uf->stretch);
+- err |= __get_user(f->gap, &uf->gap);
+- err |= __get_user(f->rate, &uf->rate);
+- err |= __get_user(f->spec1, &uf->spec1);
+- err |= __get_user(f->fmt_gap, &uf->fmt_gap);
+- err |= __get_user(name, &uf->name);
+- f->name = compat_ptr(name);
+- if (err) {
+- err = -EFAULT;
+- goto out;
+- }
+- break;
+- }
+- case FDSETDRVPRM32:
+- case FDGETDRVPRM32:
+- {
+- struct compat_floppy_drive_params __user *uf;
+- struct floppy_drive_params *f;
+-
+- uf = compat_ptr(arg);
+- f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- if (cmd == FDGETDRVPRM32)
+- break;
+- err = __get_user(f->cmos, &uf->cmos);
+- err |= __get_user(f->max_dtr, &uf->max_dtr);
+- err |= __get_user(f->hlt, &uf->hlt);
+- err |= __get_user(f->hut, &uf->hut);
+- err |= __get_user(f->srt, &uf->srt);
+- err |= __get_user(f->spinup, &uf->spinup);
+- err |= __get_user(f->spindown, &uf->spindown);
+- err |= __get_user(f->spindown_offset, &uf->spindown_offset);
+- err |= __get_user(f->select_delay, &uf->select_delay);
+- err |= __get_user(f->rps, &uf->rps);
+- err |= __get_user(f->tracks, &uf->tracks);
+- err |= __get_user(f->timeout, &uf->timeout);
+- err |= __get_user(f->interleave_sect, &uf->interleave_sect);
+- err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
+- err |= __get_user(f->flags, &uf->flags);
+- err |= __get_user(f->read_track, &uf->read_track);
+- err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
+- err |= __get_user(f->checkfreq, &uf->checkfreq);
+- err |= __get_user(f->native_format, &uf->native_format);
+- if (err) {
+- err = -EFAULT;
+- goto out;
+- }
+- break;
+- }
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- case FDGETFDCSTAT32:
+- karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- case FDWERRORGET32:
+- karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- default:
+- return -EINVAL;
+- }
+- set_fs(KERNEL_DS);
+- err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
+- set_fs(old_fs);
+- if (err)
+- goto out;
+- switch (cmd) {
+- case FDGETPRM32:
+- {
+- struct floppy_struct *f = karg;
+- struct compat_floppy_struct __user *uf = compat_ptr(arg);
+-
+- err = __put_user(f->size, &uf->size);
+- err |= __put_user(f->sect, &uf->sect);
+- err |= __put_user(f->head, &uf->head);
+- err |= __put_user(f->track, &uf->track);
+- err |= __put_user(f->stretch, &uf->stretch);
+- err |= __put_user(f->gap, &uf->gap);
+- err |= __put_user(f->rate, &uf->rate);
+- err |= __put_user(f->spec1, &uf->spec1);
+- err |= __put_user(f->fmt_gap, &uf->fmt_gap);
+- err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
+- break;
+- }
+- case FDGETDRVPRM32:
+- {
+- struct compat_floppy_drive_params __user *uf;
+- struct floppy_drive_params *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->cmos, &uf->cmos);
+- err |= __put_user(f->max_dtr, &uf->max_dtr);
+- err |= __put_user(f->hlt, &uf->hlt);
+- err |= __put_user(f->hut, &uf->hut);
+- err |= __put_user(f->srt, &uf->srt);
+- err |= __put_user(f->spinup, &uf->spinup);
+- err |= __put_user(f->spindown, &uf->spindown);
+- err |= __put_user(f->spindown_offset, &uf->spindown_offset);
+- err |= __put_user(f->select_delay, &uf->select_delay);
+- err |= __put_user(f->rps, &uf->rps);
+- err |= __put_user(f->tracks, &uf->tracks);
+- err |= __put_user(f->timeout, &uf->timeout);
+- err |= __put_user(f->interleave_sect, &uf->interleave_sect);
+- err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
+- err |= __put_user(f->flags, &uf->flags);
+- err |= __put_user(f->read_track, &uf->read_track);
+- err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
+- err |= __put_user(f->checkfreq, &uf->checkfreq);
+- err |= __put_user(f->native_format, &uf->native_format);
+- break;
+- }
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- {
+- struct compat_floppy_drive_struct __user *uf;
+- struct floppy_drive_struct *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->flags, &uf->flags);
+- err |= __put_user(f->spinup_date, &uf->spinup_date);
+- err |= __put_user(f->select_date, &uf->select_date);
+- err |= __put_user(f->first_read_date, &uf->first_read_date);
+- err |= __put_user(f->probed_format, &uf->probed_format);
+- err |= __put_user(f->track, &uf->track);
+- err |= __put_user(f->maxblock, &uf->maxblock);
+- err |= __put_user(f->maxtrack, &uf->maxtrack);
+- err |= __put_user(f->generation, &uf->generation);
+- err |= __put_user(f->keep_data, &uf->keep_data);
+- err |= __put_user(f->fd_ref, &uf->fd_ref);
+- err |= __put_user(f->fd_device, &uf->fd_device);
+- err |= __put_user(f->last_checked, &uf->last_checked);
+- err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
+- err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
+- break;
+- }
+- case FDGETFDCSTAT32:
+- {
+- struct compat_floppy_fdc_state __user *uf;
+- struct floppy_fdc_state *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->spec1, &uf->spec1);
+- err |= __put_user(f->spec2, &uf->spec2);
+- err |= __put_user(f->dtr, &uf->dtr);
+- err |= __put_user(f->version, &uf->version);
+- err |= __put_user(f->dor, &uf->dor);
+- err |= __put_user(f->address, &uf->address);
+- err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
+- (char *)&f->address + sizeof(f->address), sizeof(int));
+- err |= __put_user(f->driver_version, &uf->driver_version);
+- err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
+- break;
+- }
+- case FDWERRORGET32:
+- {
+- struct compat_floppy_write_errors __user *uf;
+- struct floppy_write_errors *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->write_errors, &uf->write_errors);
+- err |= __put_user(f->first_error_sector, &uf->first_error_sector);
+- err |= __put_user(f->first_error_generation, &uf->first_error_generation);
+- err |= __put_user(f->last_error_sector, &uf->last_error_sector);
+- err |= __put_user(f->last_error_generation, &uf->last_error_generation);
+- err |= __put_user(f->badness, &uf->badness);
+- break;
+- }
+- default:
+- break;
+- }
+- if (err)
+- err = -EFAULT;
+-
+-out:
+- kfree(karg);
+- return err;
+-}
+-
+ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
+ {
+@@ -537,16 +224,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ case HDIO_GET_ADDRESS:
+ case HDIO_GET_BUSSTATE:
+ return compat_hdio_ioctl(bdev, mode, cmd, arg);
+- case FDSETPRM32:
+- case FDDEFPRM32:
+- case FDGETPRM32:
+- case FDSETDRVPRM32:
+- case FDGETDRVPRM32:
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- case FDGETFDCSTAT32:
+- case FDWERRORGET32:
+- return compat_fd_ioctl(bdev, mode, cmd, arg);
+ case CDROMREADAUDIO:
+ return compat_cdrom_read_audio(bdev, mode, cmd, arg);
+ case CDROM_SEND_PACKET:
+@@ -566,23 +243,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ case HDIO_DRIVE_CMD:
+ /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
+ case 0x330:
+- /* 0x02 -- Floppy ioctls */
+- case FDMSGON:
+- case FDMSGOFF:
+- case FDSETEMSGTRESH:
+- case FDFLUSH:
+- case FDWERRORCLR:
+- case FDSETMAXERRS:
+- case FDGETMAXERRS:
+- case FDGETDRVTYP:
+- case FDEJECT:
+- case FDCLRPRM:
+- case FDFMTBEG:
+- case FDFMTEND:
+- case FDRESET:
+- case FDTWADDLE:
+- case FDFMTTRK:
+- case FDRAWCMD:
+ /* CDROM stuff */
+ case CDROMPAUSE:
+ case CDROMRESUME:
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 2daa5b84abbc..5fe9e899d2a6 100644
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -192,6 +192,7 @@ static int print_unex = 1;
+ #include <linux/io.h>
+ #include <linux/uaccess.h>
+ #include <linux/async.h>
++#include <linux/compat.h>
+
+ /*
+ * PS/2 floppies have much slower step rates than regular floppies.
+@@ -3569,6 +3570,330 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
+ return ret;
+ }
+
++#ifdef CONFIG_COMPAT
++
++struct compat_floppy_drive_params {
++ char cmos;
++ compat_ulong_t max_dtr;
++ compat_ulong_t hlt;
++ compat_ulong_t hut;
++ compat_ulong_t srt;
++ compat_ulong_t spinup;
++ compat_ulong_t spindown;
++ unsigned char spindown_offset;
++ unsigned char select_delay;
++ unsigned char rps;
++ unsigned char tracks;
++ compat_ulong_t timeout;
++ unsigned char interleave_sect;
++ struct floppy_max_errors max_errors;
++ char flags;
++ char read_track;
++ short autodetect[8];
++ compat_int_t checkfreq;
++ compat_int_t native_format;
++};
++
++struct compat_floppy_drive_struct {
++ signed char flags;
++ compat_ulong_t spinup_date;
++ compat_ulong_t select_date;
++ compat_ulong_t first_read_date;
++ short probed_format;
++ short track;
++ short maxblock;
++ short maxtrack;
++ compat_int_t generation;
++ compat_int_t keep_data;
++ compat_int_t fd_ref;
++ compat_int_t fd_device;
++ compat_int_t last_checked;
++ compat_caddr_t dmabuf;
++ compat_int_t bufblocks;
++};
++
++struct compat_floppy_fdc_state {
++ compat_int_t spec1;
++ compat_int_t spec2;
++ compat_int_t dtr;
++ unsigned char version;
++ unsigned char dor;
++ compat_ulong_t address;
++ unsigned int rawcmd:2;
++ unsigned int reset:1;
++ unsigned int need_configure:1;
++ unsigned int perp_mode:2;
++ unsigned int has_fifo:1;
++ unsigned int driver_version;
++ unsigned char track[4];
++};
++
++struct compat_floppy_write_errors {
++ unsigned int write_errors;
++ compat_ulong_t first_error_sector;
++ compat_int_t first_error_generation;
++ compat_ulong_t last_error_sector;
++ compat_int_t last_error_generation;
++ compat_uint_t badness;
++};
++
++#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
++#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
++#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
++#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
++#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
++#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
++#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
++#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
++
++static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
++ struct compat_floppy_struct __user *arg)
++{
++ struct floppy_struct v;
++ int drive, type;
++ int err;
++
++ BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
++ offsetof(struct compat_floppy_struct, name));
++
++ if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
++ return -EPERM;
++
++ memset(&v, 0, sizeof(struct floppy_struct));
++ if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
++ return -EFAULT;
++
++ mutex_lock(&floppy_mutex);
++ drive = (long)bdev->bd_disk->private_data;
++ type = ITYPE(UDRS->fd_device);
++ err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
++ &v, drive, type, bdev);
++ mutex_unlock(&floppy_mutex);
++ return err;
++}
++
++static int compat_get_prm(int drive,
++ struct compat_floppy_struct __user *arg)
++{
++ struct compat_floppy_struct v;
++ struct floppy_struct *p;
++ int err;
++
++ memset(&v, 0, sizeof(v));
++ mutex_lock(&floppy_mutex);
++ err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
++ if (err) {
++ mutex_unlock(&floppy_mutex);
++ return err;
++ }
++ memcpy(&v, p, offsetof(struct floppy_struct, name));
++ mutex_unlock(&floppy_mutex);
++ if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_setdrvprm(int drive,
++ struct compat_floppy_drive_params __user *arg)
++{
++ struct compat_floppy_drive_params v;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
++ return -EFAULT;
++ mutex_lock(&floppy_mutex);
++ UDP->cmos = v.cmos;
++ UDP->max_dtr = v.max_dtr;
++ UDP->hlt = v.hlt;
++ UDP->hut = v.hut;
++ UDP->srt = v.srt;
++ UDP->spinup = v.spinup;
++ UDP->spindown = v.spindown;
++ UDP->spindown_offset = v.spindown_offset;
++ UDP->select_delay = v.select_delay;
++ UDP->rps = v.rps;
++ UDP->tracks = v.tracks;
++ UDP->timeout = v.timeout;
++ UDP->interleave_sect = v.interleave_sect;
++ UDP->max_errors = v.max_errors;
++ UDP->flags = v.flags;
++ UDP->read_track = v.read_track;
++ memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
++ UDP->checkfreq = v.checkfreq;
++ UDP->native_format = v.native_format;
++ mutex_unlock(&floppy_mutex);
++ return 0;
++}
++
++static int compat_getdrvprm(int drive,
++ struct compat_floppy_drive_params __user *arg)
++{
++ struct compat_floppy_drive_params v;
++
++ memset(&v, 0, sizeof(struct compat_floppy_drive_params));
++ mutex_lock(&floppy_mutex);
++ v.cmos = UDP->cmos;
++ v.max_dtr = UDP->max_dtr;
++ v.hlt = UDP->hlt;
++ v.hut = UDP->hut;
++ v.srt = UDP->srt;
++ v.spinup = UDP->spinup;
++ v.spindown = UDP->spindown;
++ v.spindown_offset = UDP->spindown_offset;
++ v.select_delay = UDP->select_delay;
++ v.rps = UDP->rps;
++ v.tracks = UDP->tracks;
++ v.timeout = UDP->timeout;
++ v.interleave_sect = UDP->interleave_sect;
++ v.max_errors = UDP->max_errors;
++ v.flags = UDP->flags;
++ v.read_track = UDP->read_track;
++ memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
++ v.checkfreq = UDP->checkfreq;
++ v.native_format = UDP->native_format;
++ mutex_unlock(&floppy_mutex);
++
++ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_getdrvstat(int drive, bool poll,
++ struct compat_floppy_drive_struct __user *arg)
++{
++ struct compat_floppy_drive_struct v;
++
++ memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
++ mutex_lock(&floppy_mutex);
++
++ if (poll) {
++ if (lock_fdc(drive))
++ goto Eintr;
++ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
++ goto Eintr;
++ process_fd_request();
++ }
++ v.spinup_date = UDRS->spinup_date;
++ v.select_date = UDRS->select_date;
++ v.first_read_date = UDRS->first_read_date;
++ v.probed_format = UDRS->probed_format;
++ v.track = UDRS->track;
++ v.maxblock = UDRS->maxblock;
++ v.maxtrack = UDRS->maxtrack;
++ v.generation = UDRS->generation;
++ v.keep_data = UDRS->keep_data;
++ v.fd_ref = UDRS->fd_ref;
++ v.fd_device = UDRS->fd_device;
++ v.last_checked = UDRS->last_checked;
++ v.dmabuf = (uintptr_t)UDRS->dmabuf;
++ v.bufblocks = UDRS->bufblocks;
++ mutex_unlock(&floppy_mutex);
++
++ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
++ return -EFAULT;
++ return 0;
++Eintr:
++ mutex_unlock(&floppy_mutex);
++ return -EINTR;
++}
++
++static int compat_getfdcstat(int drive,
++ struct compat_floppy_fdc_state __user *arg)
++{
++ struct compat_floppy_fdc_state v32;
++ struct floppy_fdc_state v;
++
++ mutex_lock(&floppy_mutex);
++ v = *UFDCS;
++ mutex_unlock(&floppy_mutex);
++
++ memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
++ v32.spec1 = v.spec1;
++ v32.spec2 = v.spec2;
++ v32.dtr = v.dtr;
++ v32.version = v.version;
++ v32.dor = v.dor;
++ v32.address = v.address;
++ v32.rawcmd = v.rawcmd;
++ v32.reset = v.reset;
++ v32.need_configure = v.need_configure;
++ v32.perp_mode = v.perp_mode;
++ v32.has_fifo = v.has_fifo;
++ v32.driver_version = v.driver_version;
++ memcpy(v32.track, v.track, 4);
++ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_werrorget(int drive,
++ struct compat_floppy_write_errors __user *arg)
++{
++ struct compat_floppy_write_errors v32;
++ struct floppy_write_errors v;
++
++ memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
++ mutex_lock(&floppy_mutex);
++ v = *UDRWE;
++ mutex_unlock(&floppy_mutex);
++ v32.write_errors = v.write_errors;
++ v32.first_error_sector = v.first_error_sector;
++ v32.first_error_generation = v.first_error_generation;
++ v32.last_error_sector = v.last_error_sector;
++ v32.last_error_generation = v.last_error_generation;
++ v32.badness = v.badness;
++ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
++ return -EFAULT;
++ return 0;
++}
++
++static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
++ unsigned long param)
++{
++ int drive = (long)bdev->bd_disk->private_data;
++ switch (cmd) {
++ case FDMSGON:
++ case FDMSGOFF:
++ case FDSETEMSGTRESH:
++ case FDFLUSH:
++ case FDWERRORCLR:
++ case FDEJECT:
++ case FDCLRPRM:
++ case FDFMTBEG:
++ case FDRESET:
++ case FDTWADDLE:
++ return fd_ioctl(bdev, mode, cmd, param);
++ case FDSETMAXERRS:
++ case FDGETMAXERRS:
++ case FDGETDRVTYP:
++ case FDFMTEND:
++ case FDFMTTRK:
++ case FDRAWCMD:
++ return fd_ioctl(bdev, mode, cmd,
++ (unsigned long)compat_ptr(param));
++ case FDSETPRM32:
++ case FDDEFPRM32:
++ return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
++ case FDGETPRM32:
++ return compat_get_prm(drive, compat_ptr(param));
++ case FDSETDRVPRM32:
++ return compat_setdrvprm(drive, compat_ptr(param));
++ case FDGETDRVPRM32:
++ return compat_getdrvprm(drive, compat_ptr(param));
++ case FDPOLLDRVSTAT32:
++ return compat_getdrvstat(drive, true, compat_ptr(param));
++ case FDGETDRVSTAT32:
++ return compat_getdrvstat(drive, false, compat_ptr(param));
++ case FDGETFDCSTAT32:
++ return compat_getfdcstat(drive, compat_ptr(param));
++ case FDWERRORGET32:
++ return compat_werrorget(drive, compat_ptr(param));
++ }
++ return -EINVAL;
++}
++#endif
++
+ static void __init config_types(void)
+ {
+ bool has_drive = false;
+@@ -3885,6 +4210,9 @@ static const struct block_device_operations floppy_fops = {
+ .getgeo = fd_getgeo,
+ .check_events = floppy_check_events,
+ .revalidate_disk = floppy_revalidate,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = fd_compat_ioctl,
++#endif
+ };
+
+ /*
+--
+2.20.1
+
-From 77163150bdc22c8ec7a3564d95b02bbbe0392bda Mon Sep 17 00:00:00 2001
+From 5544bb65ad6f4a74df98c5d428f96539a1f939bd Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:20 +0300
Subject: floppy: fix div-by-zero in setup_format_params
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/block/floppy.c | 5 +++++
+ drivers/block/floppy.c | 5 +++++
1 file changed, 5 insertions(+)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 896dea296076..d39dc8807d3f 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -2113,6 +2113,9 @@ static void setup_format_params(int trac
+@@ -2114,6 +2114,9 @@ static void setup_format_params(int track)
raw_cmd->kernel_data = floppy_track_buffer;
raw_cmd->length = 4 * F_SECT_PER_TRACK;
/* allow for about 30ms for data transport per track */
head_shift = (F_SECT_PER_TRACK + 5) / 6;
-@@ -3235,6 +3238,8 @@ static int set_geometry(unsigned int cmd
+@@ -3236,6 +3239,8 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
/* sanity checking for parameters. */
if (g->sect <= 0 ||
g->head <= 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
/* check if reserved bits are set */
(g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
+--
+2.20.1
+
-From 9b04609b784027968348796a18f601aed9db3789 Mon Sep 17 00:00:00 2001
+From fcd20f29d0471fddfb010a536fa25ceeb9744615 Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:22 +0300
Subject: floppy: fix invalid pointer dereference in drive_name
-From: Denis Efremov <efremov@ispras.ru>
-
-commit 9b04609b784027968348796a18f601aed9db3789 upstream.
+[ Upstream commit 9b04609b784027968348796a18f601aed9db3789 ]
This fixes the invalid pointer dereference in the drive_name function of
the floppy driver.
Signed-off-by: Denis Efremov <efremov@ispras.ru>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
+Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- drivers/block/floppy.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
+ drivers/block/floppy.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 945f93d1ffe7..d651e4309371 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3383,7 +3383,8 @@ static int fd_getgeo(struct block_device
+@@ -3384,7 +3384,8 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
{
size_t floppy_type_size = ARRAY_SIZE(floppy_type);
size_t i = 0;
-@@ -3394,6 +3395,9 @@ static bool valid_floppy_drive_params(co
+@@ -3395,6 +3396,9 @@ static bool valid_floppy_drive_params(const short autodetect[8])
return false;
}
return true;
}
-@@ -3523,7 +3527,8 @@ static int fd_locked_ioctl(struct block_
+@@ -3524,7 +3528,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
return -EINVAL;
*UDP = inparam.dp;
break;
+@@ -3723,7 +3728,7 @@ static int compat_setdrvprm(int drive,
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
+- if (!valid_floppy_drive_params(v.autodetect))
++ if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+ return -EINVAL;
+ mutex_lock(&floppy_mutex);
+ UDP->cmos = v.cmos;
+--
+2.20.1
+
-From f08ab6458e0c83d14ac4e9856018fbb79b583feb Mon Sep 17 00:00:00 2001
+From 7022683a256b641c683d236b65beb59e2630f9e8 Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:23 +0300
Subject: floppy: fix out-of-bounds read in copy_buffer
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
- drivers/block/floppy.c | 6 ++++--
+ drivers/block/floppy.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index d651e4309371..6930abef42b3 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3236,8 +3236,10 @@ static int set_geometry(unsigned int cmd
+@@ -3237,8 +3237,10 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
int cnt;
/* sanity checking for parameters. */
/* check for zero in F_SECT_PER_TRACK */
(unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
+--
+2.20.1
+
-From 5635f897ed83fd539df78e98ba69ee91592f9bb8 Mon Sep 17 00:00:00 2001
+From 5d927beed36f215ae2443e260480880a5e1452a5 Mon Sep 17 00:00:00 2001
From: Denis Efremov <efremov@ispras.ru>
Date: Fri, 12 Jul 2019 21:55:21 +0300
Subject: floppy: fix out-of-bounds read in next_valid_format
-From: Denis Efremov <efremov@ispras.ru>
-
-commit 5635f897ed83fd539df78e98ba69ee91592f9bb8 upstream.
+[ Upstream commit 5635f897ed83fd539df78e98ba69ee91592f9bb8 ]
This fixes a global out-of-bounds read access in the next_valid_format
function of the floppy driver.
Signed-off-by: Denis Efremov <efremov@ispras.ru>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
+Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- drivers/block/floppy.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
+ drivers/block/floppy.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index d39dc8807d3f..945f93d1ffe7 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
-@@ -3383,6 +3383,20 @@ static int fd_getgeo(struct block_device
+@@ -3384,6 +3384,20 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
-@@ -3509,6 +3523,8 @@ static int fd_locked_ioctl(struct block_
+@@ -3510,6 +3524,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
*UDP = inparam.dp;
break;
case FDGETDRVPRM:
+@@ -3707,6 +3723,8 @@ static int compat_setdrvprm(int drive,
+ return -EPERM;
+ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
+ return -EFAULT;
++ if (!valid_floppy_drive_params(v.autodetect))
++ return -EINVAL;
+ mutex_lock(&floppy_mutex);
+ UDP->cmos = v.cmos;
+ UDP->max_dtr = v.max_dtr;
+--
+2.20.1
+
bluetooth-validate-ble-connection-interval-updates.patch
gtp-fix-illegal-context-switch-in-rcu-read-side-crit.patch
gtp-fix-use-after-free-in-gtp_newlink.patch
-floppy-fix-div-by-zero-in-setup_format_params.patch
-floppy-fix-out-of-bounds-read-in-next_valid_format.patch
-floppy-fix-invalid-pointer-dereference-in-drive_name.patch
-floppy-fix-out-of-bounds-read-in-copy_buffer.patch
xen-let-alloc_xenballooned_pages-fail-if-not-enough-memory-free.patch
scsi-ncr5380-reduce-goto-statements-in-ncr5380_select.patch
scsi-ncr5380-always-re-enable-reselection-interrupt.patch
pci-do-not-poll-for-pme-if-the-device-is-in-d3cold.patch
btrfs-add-missing-inode-version-ctime-and-mtime-updates-when-punching-hole.patch
libnvdimm-pfn-fix-fsdax-mode-namespace-info-block-zero-fields.patch
+take-floppy-compat-ioctls-to-sodding-floppy.c.patch
+floppy-fix-div-by-zero-in-setup_format_params.patch
+floppy-fix-out-of-bounds-read-in-next_valid_format.patch
+floppy-fix-invalid-pointer-dereference-in-drive_name.patch
+floppy-fix-out-of-bounds-read-in-copy_buffer.patch
--- /dev/null
+From 3850e02efae9bd24e29eae9e6c289e4d8a0b637c Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Tue, 27 Jun 2017 15:47:56 -0400
+Subject: take floppy compat ioctls to sodding floppy.c
+
+[ Upstream commit 229b53c9bf4e1132a4aa6feb9632a7a1f1d08c5c ]
+
+all other drivers recognizing those ioctls are very much *not*
+biarch.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ block/compat_ioctl.c | 340 -----------------------------------------
+ drivers/block/floppy.c | 328 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 328 insertions(+), 340 deletions(-)
+
+diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
+index 556826ac7cb4..3c9fdd6983aa 100644
+--- a/block/compat_ioctl.c
++++ b/block/compat_ioctl.c
+@@ -4,7 +4,6 @@
+ #include <linux/cdrom.h>
+ #include <linux/compat.h>
+ #include <linux/elevator.h>
+-#include <linux/fd.h>
+ #include <linux/hdreg.h>
+ #include <linux/slab.h>
+ #include <linux/syscalls.h>
+@@ -209,318 +208,6 @@ static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
+ #define BLKBSZSET_32 _IOW(0x12, 113, int)
+ #define BLKGETSIZE64_32 _IOR(0x12, 114, int)
+
+-struct compat_floppy_drive_params {
+- char cmos;
+- compat_ulong_t max_dtr;
+- compat_ulong_t hlt;
+- compat_ulong_t hut;
+- compat_ulong_t srt;
+- compat_ulong_t spinup;
+- compat_ulong_t spindown;
+- unsigned char spindown_offset;
+- unsigned char select_delay;
+- unsigned char rps;
+- unsigned char tracks;
+- compat_ulong_t timeout;
+- unsigned char interleave_sect;
+- struct floppy_max_errors max_errors;
+- char flags;
+- char read_track;
+- short autodetect[8];
+- compat_int_t checkfreq;
+- compat_int_t native_format;
+-};
+-
+-struct compat_floppy_drive_struct {
+- signed char flags;
+- compat_ulong_t spinup_date;
+- compat_ulong_t select_date;
+- compat_ulong_t first_read_date;
+- short probed_format;
+- short track;
+- short maxblock;
+- short maxtrack;
+- compat_int_t generation;
+- compat_int_t keep_data;
+- compat_int_t fd_ref;
+- compat_int_t fd_device;
+- compat_int_t last_checked;
+- compat_caddr_t dmabuf;
+- compat_int_t bufblocks;
+-};
+-
+-struct compat_floppy_fdc_state {
+- compat_int_t spec1;
+- compat_int_t spec2;
+- compat_int_t dtr;
+- unsigned char version;
+- unsigned char dor;
+- compat_ulong_t address;
+- unsigned int rawcmd:2;
+- unsigned int reset:1;
+- unsigned int need_configure:1;
+- unsigned int perp_mode:2;
+- unsigned int has_fifo:1;
+- unsigned int driver_version;
+- unsigned char track[4];
+-};
+-
+-struct compat_floppy_write_errors {
+- unsigned int write_errors;
+- compat_ulong_t first_error_sector;
+- compat_int_t first_error_generation;
+- compat_ulong_t last_error_sector;
+- compat_int_t last_error_generation;
+- compat_uint_t badness;
+-};
+-
+-#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
+-#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
+-#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
+-#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
+-#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
+-#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
+-#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
+-#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
+-
+-static struct {
+- unsigned int cmd32;
+- unsigned int cmd;
+-} fd_ioctl_trans_table[] = {
+- { FDSETPRM32, FDSETPRM },
+- { FDDEFPRM32, FDDEFPRM },
+- { FDGETPRM32, FDGETPRM },
+- { FDSETDRVPRM32, FDSETDRVPRM },
+- { FDGETDRVPRM32, FDGETDRVPRM },
+- { FDGETDRVSTAT32, FDGETDRVSTAT },
+- { FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+- { FDGETFDCSTAT32, FDGETFDCSTAT },
+- { FDWERRORGET32, FDWERRORGET }
+-};
+-
+-#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
+-
+-static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
+- unsigned int cmd, unsigned long arg)
+-{
+- mm_segment_t old_fs = get_fs();
+- void *karg = NULL;
+- unsigned int kcmd = 0;
+- int i, err;
+-
+- for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+- if (cmd == fd_ioctl_trans_table[i].cmd32) {
+- kcmd = fd_ioctl_trans_table[i].cmd;
+- break;
+- }
+- if (!kcmd)
+- return -EINVAL;
+-
+- switch (cmd) {
+- case FDSETPRM32:
+- case FDDEFPRM32:
+- case FDGETPRM32:
+- {
+- compat_uptr_t name;
+- struct compat_floppy_struct __user *uf;
+- struct floppy_struct *f;
+-
+- uf = compat_ptr(arg);
+- f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- if (cmd == FDGETPRM32)
+- break;
+- err = __get_user(f->size, &uf->size);
+- err |= __get_user(f->sect, &uf->sect);
+- err |= __get_user(f->head, &uf->head);
+- err |= __get_user(f->track, &uf->track);
+- err |= __get_user(f->stretch, &uf->stretch);
+- err |= __get_user(f->gap, &uf->gap);
+- err |= __get_user(f->rate, &uf->rate);
+- err |= __get_user(f->spec1, &uf->spec1);
+- err |= __get_user(f->fmt_gap, &uf->fmt_gap);
+- err |= __get_user(name, &uf->name);
+- f->name = compat_ptr(name);
+- if (err) {
+- err = -EFAULT;
+- goto out;
+- }
+- break;
+- }
+- case FDSETDRVPRM32:
+- case FDGETDRVPRM32:
+- {
+- struct compat_floppy_drive_params __user *uf;
+- struct floppy_drive_params *f;
+-
+- uf = compat_ptr(arg);
+- f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- if (cmd == FDGETDRVPRM32)
+- break;
+- err = __get_user(f->cmos, &uf->cmos);
+- err |= __get_user(f->max_dtr, &uf->max_dtr);
+- err |= __get_user(f->hlt, &uf->hlt);
+- err |= __get_user(f->hut, &uf->hut);
+- err |= __get_user(f->srt, &uf->srt);
+- err |= __get_user(f->spinup, &uf->spinup);
+- err |= __get_user(f->spindown, &uf->spindown);
+- err |= __get_user(f->spindown_offset, &uf->spindown_offset);
+- err |= __get_user(f->select_delay, &uf->select_delay);
+- err |= __get_user(f->rps, &uf->rps);
+- err |= __get_user(f->tracks, &uf->tracks);
+- err |= __get_user(f->timeout, &uf->timeout);
+- err |= __get_user(f->interleave_sect, &uf->interleave_sect);
+- err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors));
+- err |= __get_user(f->flags, &uf->flags);
+- err |= __get_user(f->read_track, &uf->read_track);
+- err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect));
+- err |= __get_user(f->checkfreq, &uf->checkfreq);
+- err |= __get_user(f->native_format, &uf->native_format);
+- if (err) {
+- err = -EFAULT;
+- goto out;
+- }
+- break;
+- }
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- case FDGETFDCSTAT32:
+- karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- case FDWERRORGET32:
+- karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL);
+- if (!karg)
+- return -ENOMEM;
+- break;
+- default:
+- return -EINVAL;
+- }
+- set_fs(KERNEL_DS);
+- err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
+- set_fs(old_fs);
+- if (err)
+- goto out;
+- switch (cmd) {
+- case FDGETPRM32:
+- {
+- struct floppy_struct *f = karg;
+- struct compat_floppy_struct __user *uf = compat_ptr(arg);
+-
+- err = __put_user(f->size, &uf->size);
+- err |= __put_user(f->sect, &uf->sect);
+- err |= __put_user(f->head, &uf->head);
+- err |= __put_user(f->track, &uf->track);
+- err |= __put_user(f->stretch, &uf->stretch);
+- err |= __put_user(f->gap, &uf->gap);
+- err |= __put_user(f->rate, &uf->rate);
+- err |= __put_user(f->spec1, &uf->spec1);
+- err |= __put_user(f->fmt_gap, &uf->fmt_gap);
+- err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name);
+- break;
+- }
+- case FDGETDRVPRM32:
+- {
+- struct compat_floppy_drive_params __user *uf;
+- struct floppy_drive_params *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->cmos, &uf->cmos);
+- err |= __put_user(f->max_dtr, &uf->max_dtr);
+- err |= __put_user(f->hlt, &uf->hlt);
+- err |= __put_user(f->hut, &uf->hut);
+- err |= __put_user(f->srt, &uf->srt);
+- err |= __put_user(f->spinup, &uf->spinup);
+- err |= __put_user(f->spindown, &uf->spindown);
+- err |= __put_user(f->spindown_offset, &uf->spindown_offset);
+- err |= __put_user(f->select_delay, &uf->select_delay);
+- err |= __put_user(f->rps, &uf->rps);
+- err |= __put_user(f->tracks, &uf->tracks);
+- err |= __put_user(f->timeout, &uf->timeout);
+- err |= __put_user(f->interleave_sect, &uf->interleave_sect);
+- err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors));
+- err |= __put_user(f->flags, &uf->flags);
+- err |= __put_user(f->read_track, &uf->read_track);
+- err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect));
+- err |= __put_user(f->checkfreq, &uf->checkfreq);
+- err |= __put_user(f->native_format, &uf->native_format);
+- break;
+- }
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- {
+- struct compat_floppy_drive_struct __user *uf;
+- struct floppy_drive_struct *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->flags, &uf->flags);
+- err |= __put_user(f->spinup_date, &uf->spinup_date);
+- err |= __put_user(f->select_date, &uf->select_date);
+- err |= __put_user(f->first_read_date, &uf->first_read_date);
+- err |= __put_user(f->probed_format, &uf->probed_format);
+- err |= __put_user(f->track, &uf->track);
+- err |= __put_user(f->maxblock, &uf->maxblock);
+- err |= __put_user(f->maxtrack, &uf->maxtrack);
+- err |= __put_user(f->generation, &uf->generation);
+- err |= __put_user(f->keep_data, &uf->keep_data);
+- err |= __put_user(f->fd_ref, &uf->fd_ref);
+- err |= __put_user(f->fd_device, &uf->fd_device);
+- err |= __put_user(f->last_checked, &uf->last_checked);
+- err |= __put_user((u64)f->dmabuf, &uf->dmabuf);
+- err |= __put_user((u64)f->bufblocks, &uf->bufblocks);
+- break;
+- }
+- case FDGETFDCSTAT32:
+- {
+- struct compat_floppy_fdc_state __user *uf;
+- struct floppy_fdc_state *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->spec1, &uf->spec1);
+- err |= __put_user(f->spec2, &uf->spec2);
+- err |= __put_user(f->dtr, &uf->dtr);
+- err |= __put_user(f->version, &uf->version);
+- err |= __put_user(f->dor, &uf->dor);
+- err |= __put_user(f->address, &uf->address);
+- err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address),
+- (char *)&f->address + sizeof(f->address), sizeof(int));
+- err |= __put_user(f->driver_version, &uf->driver_version);
+- err |= __copy_to_user(uf->track, f->track, sizeof(f->track));
+- break;
+- }
+- case FDWERRORGET32:
+- {
+- struct compat_floppy_write_errors __user *uf;
+- struct floppy_write_errors *f = karg;
+-
+- uf = compat_ptr(arg);
+- err = __put_user(f->write_errors, &uf->write_errors);
+- err |= __put_user(f->first_error_sector, &uf->first_error_sector);
+- err |= __put_user(f->first_error_generation, &uf->first_error_generation);
+- err |= __put_user(f->last_error_sector, &uf->last_error_sector);
+- err |= __put_user(f->last_error_generation, &uf->last_error_generation);
+- err |= __put_user(f->badness, &uf->badness);
+- break;
+- }
+- default:
+- break;
+- }
+- if (err)
+- err = -EFAULT;
+-
+-out:
+- kfree(karg);
+- return err;
+-}
+-
+ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
+ {
+@@ -537,16 +224,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ case HDIO_GET_ADDRESS:
+ case HDIO_GET_BUSSTATE:
+ return compat_hdio_ioctl(bdev, mode, cmd, arg);
+- case FDSETPRM32:
+- case FDDEFPRM32:
+- case FDGETPRM32:
+- case FDSETDRVPRM32:
+- case FDGETDRVPRM32:
+- case FDGETDRVSTAT32:
+- case FDPOLLDRVSTAT32:
+- case FDGETFDCSTAT32:
+- case FDWERRORGET32:
+- return compat_fd_ioctl(bdev, mode, cmd, arg);
+ case CDROMREADAUDIO:
+ return compat_cdrom_read_audio(bdev, mode, cmd, arg);
+ case CDROM_SEND_PACKET:
+@@ -566,23 +243,6 @@ static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ case HDIO_DRIVE_CMD:
+ /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
+ case 0x330:
+- /* 0x02 -- Floppy ioctls */
+- case FDMSGON:
+- case FDMSGOFF:
+- case FDSETEMSGTRESH:
+- case FDFLUSH:
+- case FDWERRORCLR:
+- case FDSETMAXERRS:
+- case FDGETMAXERRS:
+- case FDGETDRVTYP:
+- case FDEJECT:
+- case FDCLRPRM:
+- case FDFMTBEG:
+- case FDFMTEND:
+- case FDRESET:
+- case FDTWADDLE:
+- case FDFMTTRK:
+- case FDRAWCMD:
+ /* CDROM stuff */
+ case CDROMPAUSE:
+ case CDROMRESUME:
+diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
+index 6914c6e1e1a8..896dea296076 100644
+--- a/drivers/block/floppy.c
++++ b/drivers/block/floppy.c
+@@ -192,6 +192,7 @@ static int print_unex = 1;
+ #include <linux/io.h>
+ #include <linux/uaccess.h>
+ #include <linux/async.h>
++#include <linux/compat.h>
+
+ /*
+ * PS/2 floppies have much slower step rates than regular floppies.
+@@ -3569,6 +3570,330 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode,
+ return ret;
+ }
+
++#ifdef CONFIG_COMPAT
++
++struct compat_floppy_drive_params {
++ char cmos;
++ compat_ulong_t max_dtr;
++ compat_ulong_t hlt;
++ compat_ulong_t hut;
++ compat_ulong_t srt;
++ compat_ulong_t spinup;
++ compat_ulong_t spindown;
++ unsigned char spindown_offset;
++ unsigned char select_delay;
++ unsigned char rps;
++ unsigned char tracks;
++ compat_ulong_t timeout;
++ unsigned char interleave_sect;
++ struct floppy_max_errors max_errors;
++ char flags;
++ char read_track;
++ short autodetect[8];
++ compat_int_t checkfreq;
++ compat_int_t native_format;
++};
++
++struct compat_floppy_drive_struct {
++ signed char flags;
++ compat_ulong_t spinup_date;
++ compat_ulong_t select_date;
++ compat_ulong_t first_read_date;
++ short probed_format;
++ short track;
++ short maxblock;
++ short maxtrack;
++ compat_int_t generation;
++ compat_int_t keep_data;
++ compat_int_t fd_ref;
++ compat_int_t fd_device;
++ compat_int_t last_checked;
++ compat_caddr_t dmabuf;
++ compat_int_t bufblocks;
++};
++
++struct compat_floppy_fdc_state {
++ compat_int_t spec1;
++ compat_int_t spec2;
++ compat_int_t dtr;
++ unsigned char version;
++ unsigned char dor;
++ compat_ulong_t address;
++ unsigned int rawcmd:2;
++ unsigned int reset:1;
++ unsigned int need_configure:1;
++ unsigned int perp_mode:2;
++ unsigned int has_fifo:1;
++ unsigned int driver_version;
++ unsigned char track[4];
++};
++
++struct compat_floppy_write_errors {
++ unsigned int write_errors;
++ compat_ulong_t first_error_sector;
++ compat_int_t first_error_generation;
++ compat_ulong_t last_error_sector;
++ compat_int_t last_error_generation;
++ compat_uint_t badness;
++};
++
++#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
++#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
++#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
++#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
++#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
++#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
++#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
++#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
++
++static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
++ struct compat_floppy_struct __user *arg)
++{
++ struct floppy_struct v;
++ int drive, type;
++ int err;
++
++ BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
++ offsetof(struct compat_floppy_struct, name));
++
++ if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
++ return -EPERM;
++
++ memset(&v, 0, sizeof(struct floppy_struct));
++ if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
++ return -EFAULT;
++
++ mutex_lock(&floppy_mutex);
++ drive = (long)bdev->bd_disk->private_data;
++ type = ITYPE(UDRS->fd_device);
++ err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
++ &v, drive, type, bdev);
++ mutex_unlock(&floppy_mutex);
++ return err;
++}
++
++static int compat_get_prm(int drive,
++ struct compat_floppy_struct __user *arg)
++{
++ struct compat_floppy_struct v;
++ struct floppy_struct *p;
++ int err;
++
++ memset(&v, 0, sizeof(v));
++ mutex_lock(&floppy_mutex);
++ err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
++ if (err) {
++ mutex_unlock(&floppy_mutex);
++ return err;
++ }
++ memcpy(&v, p, offsetof(struct floppy_struct, name));
++ mutex_unlock(&floppy_mutex);
++ if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_setdrvprm(int drive,
++ struct compat_floppy_drive_params __user *arg)
++{
++ struct compat_floppy_drive_params v;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++ if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
++ return -EFAULT;
++ mutex_lock(&floppy_mutex);
++ UDP->cmos = v.cmos;
++ UDP->max_dtr = v.max_dtr;
++ UDP->hlt = v.hlt;
++ UDP->hut = v.hut;
++ UDP->srt = v.srt;
++ UDP->spinup = v.spinup;
++ UDP->spindown = v.spindown;
++ UDP->spindown_offset = v.spindown_offset;
++ UDP->select_delay = v.select_delay;
++ UDP->rps = v.rps;
++ UDP->tracks = v.tracks;
++ UDP->timeout = v.timeout;
++ UDP->interleave_sect = v.interleave_sect;
++ UDP->max_errors = v.max_errors;
++ UDP->flags = v.flags;
++ UDP->read_track = v.read_track;
++ memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
++ UDP->checkfreq = v.checkfreq;
++ UDP->native_format = v.native_format;
++ mutex_unlock(&floppy_mutex);
++ return 0;
++}
++
++static int compat_getdrvprm(int drive,
++ struct compat_floppy_drive_params __user *arg)
++{
++ struct compat_floppy_drive_params v;
++
++ memset(&v, 0, sizeof(struct compat_floppy_drive_params));
++ mutex_lock(&floppy_mutex);
++ v.cmos = UDP->cmos;
++ v.max_dtr = UDP->max_dtr;
++ v.hlt = UDP->hlt;
++ v.hut = UDP->hut;
++ v.srt = UDP->srt;
++ v.spinup = UDP->spinup;
++ v.spindown = UDP->spindown;
++ v.spindown_offset = UDP->spindown_offset;
++ v.select_delay = UDP->select_delay;
++ v.rps = UDP->rps;
++ v.tracks = UDP->tracks;
++ v.timeout = UDP->timeout;
++ v.interleave_sect = UDP->interleave_sect;
++ v.max_errors = UDP->max_errors;
++ v.flags = UDP->flags;
++ v.read_track = UDP->read_track;
++ memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
++ v.checkfreq = UDP->checkfreq;
++ v.native_format = UDP->native_format;
++ mutex_unlock(&floppy_mutex);
++
++ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_getdrvstat(int drive, bool poll,
++ struct compat_floppy_drive_struct __user *arg)
++{
++ struct compat_floppy_drive_struct v;
++
++ memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
++ mutex_lock(&floppy_mutex);
++
++ if (poll) {
++ if (lock_fdc(drive))
++ goto Eintr;
++ if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
++ goto Eintr;
++ process_fd_request();
++ }
++ v.spinup_date = UDRS->spinup_date;
++ v.select_date = UDRS->select_date;
++ v.first_read_date = UDRS->first_read_date;
++ v.probed_format = UDRS->probed_format;
++ v.track = UDRS->track;
++ v.maxblock = UDRS->maxblock;
++ v.maxtrack = UDRS->maxtrack;
++ v.generation = UDRS->generation;
++ v.keep_data = UDRS->keep_data;
++ v.fd_ref = UDRS->fd_ref;
++ v.fd_device = UDRS->fd_device;
++ v.last_checked = UDRS->last_checked;
++ v.dmabuf = (uintptr_t)UDRS->dmabuf;
++ v.bufblocks = UDRS->bufblocks;
++ mutex_unlock(&floppy_mutex);
++
++ if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
++ return -EFAULT;
++ return 0;
++Eintr:
++ mutex_unlock(&floppy_mutex);
++ return -EINTR;
++}
++
++static int compat_getfdcstat(int drive,
++ struct compat_floppy_fdc_state __user *arg)
++{
++ struct compat_floppy_fdc_state v32;
++ struct floppy_fdc_state v;
++
++ mutex_lock(&floppy_mutex);
++ v = *UFDCS;
++ mutex_unlock(&floppy_mutex);
++
++ memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
++ v32.spec1 = v.spec1;
++ v32.spec2 = v.spec2;
++ v32.dtr = v.dtr;
++ v32.version = v.version;
++ v32.dor = v.dor;
++ v32.address = v.address;
++ v32.rawcmd = v.rawcmd;
++ v32.reset = v.reset;
++ v32.need_configure = v.need_configure;
++ v32.perp_mode = v.perp_mode;
++ v32.has_fifo = v.has_fifo;
++ v32.driver_version = v.driver_version;
++ memcpy(v32.track, v.track, 4);
++ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
++ return -EFAULT;
++ return 0;
++}
++
++static int compat_werrorget(int drive,
++ struct compat_floppy_write_errors __user *arg)
++{
++ struct compat_floppy_write_errors v32;
++ struct floppy_write_errors v;
++
++ memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
++ mutex_lock(&floppy_mutex);
++ v = *UDRWE;
++ mutex_unlock(&floppy_mutex);
++ v32.write_errors = v.write_errors;
++ v32.first_error_sector = v.first_error_sector;
++ v32.first_error_generation = v.first_error_generation;
++ v32.last_error_sector = v.last_error_sector;
++ v32.last_error_generation = v.last_error_generation;
++ v32.badness = v.badness;
++ if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
++ return -EFAULT;
++ return 0;
++}
++
++static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
++ unsigned long param)
++{
++ int drive = (long)bdev->bd_disk->private_data;
++ switch (cmd) {
++ case FDMSGON:
++ case FDMSGOFF:
++ case FDSETEMSGTRESH:
++ case FDFLUSH:
++ case FDWERRORCLR:
++ case FDEJECT:
++ case FDCLRPRM:
++ case FDFMTBEG:
++ case FDRESET:
++ case FDTWADDLE:
++ return fd_ioctl(bdev, mode, cmd, param);
++ case FDSETMAXERRS:
++ case FDGETMAXERRS:
++ case FDGETDRVTYP:
++ case FDFMTEND:
++ case FDFMTTRK:
++ case FDRAWCMD:
++ return fd_ioctl(bdev, mode, cmd,
++ (unsigned long)compat_ptr(param));
++ case FDSETPRM32:
++ case FDDEFPRM32:
++ return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
++ case FDGETPRM32:
++ return compat_get_prm(drive, compat_ptr(param));
++ case FDSETDRVPRM32:
++ return compat_setdrvprm(drive, compat_ptr(param));
++ case FDGETDRVPRM32:
++ return compat_getdrvprm(drive, compat_ptr(param));
++ case FDPOLLDRVSTAT32:
++ return compat_getdrvstat(drive, true, compat_ptr(param));
++ case FDGETDRVSTAT32:
++ return compat_getdrvstat(drive, false, compat_ptr(param));
++ case FDGETFDCSTAT32:
++ return compat_getfdcstat(drive, compat_ptr(param));
++ case FDWERRORGET32:
++ return compat_werrorget(drive, compat_ptr(param));
++ }
++ return -EINVAL;
++}
++#endif
++
+ static void __init config_types(void)
+ {
+ bool has_drive = false;
+@@ -3891,6 +4216,9 @@ static const struct block_device_operations floppy_fops = {
+ .getgeo = fd_getgeo,
+ .check_events = floppy_check_events,
+ .revalidate_disk = floppy_revalidate,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = fd_compat_ioctl,
++#endif
+ };
+
+ /*
+--
+2.20.1
+