From: Sasha Levin Date: Wed, 24 Jul 2019 03:09:11 +0000 (-0400) Subject: Fix up floppy backports for 4.9 and 4.4 X-Git-Tag: v5.2.3~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=985520262159dd3097374474244bdb8cf47cf43c;p=thirdparty%2Fkernel%2Fstable-queue.git Fix up floppy backports for 4.9 and 4.4 Signed-off-by: Sasha Levin --- diff --git a/queue-4.4/floppy-fix-div-by-zero-in-setup_format_params.patch b/queue-4.4/floppy-fix-div-by-zero-in-setup_format_params.patch index 9c2efe5eb10..ead84fa29a1 100644 --- a/queue-4.4/floppy-fix-div-by-zero-in-setup_format_params.patch +++ b/queue-4.4/floppy-fix-div-by-zero-in-setup_format_params.patch @@ -1,4 +1,4 @@ -From 33b5b1783bcff0ca134b4d7b2b1e3da3d83b5f43 Mon Sep 17 00:00:00 2001 +From 26cf267767b46f0ea5c6312838085fa01c7a1b9c Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:20 +0300 Subject: floppy: fix div-by-zero in setup_format_params @@ -29,14 +29,15 @@ Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman --- - 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; @@ -46,7 +47,7 @@ Signed-off-by: Greg Kroah-Hartman /* 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 || @@ -55,3 +56,6 @@ Signed-off-by: Greg Kroah-Hartman 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 + diff --git a/queue-4.4/floppy-fix-invalid-pointer-dereference-in-drive_name.patch b/queue-4.4/floppy-fix-invalid-pointer-dereference-in-drive_name.patch index ae36d7e6a40..0e24af40baf 100644 --- a/queue-4.4/floppy-fix-invalid-pointer-dereference-in-drive_name.patch +++ b/queue-4.4/floppy-fix-invalid-pointer-dereference-in-drive_name.patch @@ -1,11 +1,9 @@ -From 9b04609b784027968348796a18f601aed9db3789 Mon Sep 17 00:00:00 2001 +From 2e8dfc077179a0a9886c94e2467a392024d16f3a Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:22 +0300 Subject: floppy: fix invalid pointer dereference in drive_name -From: Denis Efremov - -commit 9b04609b784027968348796a18f601aed9db3789 upstream. +[ Upstream commit 9b04609b784027968348796a18f601aed9db3789 ] This fixes the invalid pointer dereference in the drive_name function of the floppy driver. @@ -30,15 +28,16 @@ The bug was found by syzkaller. Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - +Signed-off-by: Sasha Levin --- - 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; } @@ -48,7 +47,7 @@ Signed-off-by: Greg Kroah-Hartman { 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; } @@ -58,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman 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: @@ -68,3 +67,15 @@ Signed-off-by: Greg Kroah-Hartman 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 + diff --git a/queue-4.4/floppy-fix-out-of-bounds-read-in-copy_buffer.patch b/queue-4.4/floppy-fix-out-of-bounds-read-in-copy_buffer.patch index 5bf0eaa9a21..45a81f32716 100644 --- a/queue-4.4/floppy-fix-out-of-bounds-read-in-copy_buffer.patch +++ b/queue-4.4/floppy-fix-out-of-bounds-read-in-copy_buffer.patch @@ -1,4 +1,4 @@ -From ab1e593f24d8a821cb8b37e8c3562e72c4fb1cd0 Mon Sep 17 00:00:00 2001 +From 7f25f4a37e8351cf70762583aa024bd229466db5 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:23 +0300 Subject: floppy: fix out-of-bounds read in copy_buffer @@ -26,14 +26,15 @@ Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman --- - 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. */ @@ -46,3 +47,6 @@ Signed-off-by: Greg Kroah-Hartman /* 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 + diff --git a/queue-4.4/floppy-fix-out-of-bounds-read-in-next_valid_format.patch b/queue-4.4/floppy-fix-out-of-bounds-read-in-next_valid_format.patch index 860a525b1f0..a85de5de3d4 100644 --- a/queue-4.4/floppy-fix-out-of-bounds-read-in-next_valid_format.patch +++ b/queue-4.4/floppy-fix-out-of-bounds-read-in-next_valid_format.patch @@ -1,11 +1,9 @@ -From 5635f897ed83fd539df78e98ba69ee91592f9bb8 Mon Sep 17 00:00:00 2001 +From 57927747a6b775b792d184a51a53c6bf101e92c1 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:21 +0300 Subject: floppy: fix out-of-bounds read in next_valid_format -From: Denis Efremov - -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. @@ -28,15 +26,16 @@ The bug was found by syzkaller. Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - +Signed-off-by: Sasha Levin --- - 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; } @@ -57,7 +56,7 @@ Signed-off-by: Greg Kroah-Hartman 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: @@ -66,3 +65,15 @@ Signed-off-by: Greg Kroah-Hartman *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 + diff --git a/queue-4.4/series b/queue-4.4/series index 842c43ad7a1..72363cf909a 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -53,10 +53,6 @@ bluetooth-hci_bcsp-fix-memory-leak-in-rx_skb.patch 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 @@ -73,3 +69,8 @@ drm-nouveau-i2c-enable-i2c-pads-busses-during-preinit.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 diff --git a/queue-4.4/take-floppy-compat-ioctls-to-sodding-floppy.c.patch b/queue-4.4/take-floppy-compat-ioctls-to-sodding-floppy.c.patch new file mode 100644 index 00000000000..39cce75b6bc --- /dev/null +++ b/queue-4.4/take-floppy-compat-ioctls-to-sodding-floppy.c.patch @@ -0,0 +1,745 @@ +From b56b2384505e0d7032b45a5f4edbc3e451271c84 Mon Sep 17 00:00:00 2001 +From: Al Viro +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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + #include + #include ++#include + + /* + * 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 + diff --git a/queue-4.9/floppy-fix-div-by-zero-in-setup_format_params.patch b/queue-4.9/floppy-fix-div-by-zero-in-setup_format_params.patch index 9f2b1486497..c30faadfd51 100644 --- a/queue-4.9/floppy-fix-div-by-zero-in-setup_format_params.patch +++ b/queue-4.9/floppy-fix-div-by-zero-in-setup_format_params.patch @@ -1,4 +1,4 @@ -From 77163150bdc22c8ec7a3564d95b02bbbe0392bda Mon Sep 17 00:00:00 2001 +From 5544bb65ad6f4a74df98c5d428f96539a1f939bd Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:20 +0300 Subject: floppy: fix div-by-zero in setup_format_params @@ -29,14 +29,15 @@ Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman --- - 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; @@ -46,7 +47,7 @@ Signed-off-by: Greg Kroah-Hartman /* 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 || @@ -55,3 +56,6 @@ Signed-off-by: Greg Kroah-Hartman 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 + diff --git a/queue-4.9/floppy-fix-invalid-pointer-dereference-in-drive_name.patch b/queue-4.9/floppy-fix-invalid-pointer-dereference-in-drive_name.patch index ae36d7e6a40..b9e7e981ceb 100644 --- a/queue-4.9/floppy-fix-invalid-pointer-dereference-in-drive_name.patch +++ b/queue-4.9/floppy-fix-invalid-pointer-dereference-in-drive_name.patch @@ -1,11 +1,9 @@ -From 9b04609b784027968348796a18f601aed9db3789 Mon Sep 17 00:00:00 2001 +From fcd20f29d0471fddfb010a536fa25ceeb9744615 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:22 +0300 Subject: floppy: fix invalid pointer dereference in drive_name -From: Denis Efremov - -commit 9b04609b784027968348796a18f601aed9db3789 upstream. +[ Upstream commit 9b04609b784027968348796a18f601aed9db3789 ] This fixes the invalid pointer dereference in the drive_name function of the floppy driver. @@ -30,15 +28,16 @@ The bug was found by syzkaller. Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - +Signed-off-by: Sasha Levin --- - 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; } @@ -48,7 +47,7 @@ Signed-off-by: Greg Kroah-Hartman { 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; } @@ -58,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman 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: @@ -68,3 +67,15 @@ Signed-off-by: Greg Kroah-Hartman 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 + diff --git a/queue-4.9/floppy-fix-out-of-bounds-read-in-copy_buffer.patch b/queue-4.9/floppy-fix-out-of-bounds-read-in-copy_buffer.patch index 390abb6d15c..aac07d7df1d 100644 --- a/queue-4.9/floppy-fix-out-of-bounds-read-in-copy_buffer.patch +++ b/queue-4.9/floppy-fix-out-of-bounds-read-in-copy_buffer.patch @@ -1,4 +1,4 @@ -From f08ab6458e0c83d14ac4e9856018fbb79b583feb Mon Sep 17 00:00:00 2001 +From 7022683a256b641c683d236b65beb59e2630f9e8 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:23 +0300 Subject: floppy: fix out-of-bounds read in copy_buffer @@ -26,14 +26,15 @@ Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin -Signed-off-by: Greg Kroah-Hartman --- - 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. */ @@ -46,3 +47,6 @@ Signed-off-by: Greg Kroah-Hartman /* 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 + diff --git a/queue-4.9/floppy-fix-out-of-bounds-read-in-next_valid_format.patch b/queue-4.9/floppy-fix-out-of-bounds-read-in-next_valid_format.patch index 860a525b1f0..d9680a431ad 100644 --- a/queue-4.9/floppy-fix-out-of-bounds-read-in-next_valid_format.patch +++ b/queue-4.9/floppy-fix-out-of-bounds-read-in-next_valid_format.patch @@ -1,11 +1,9 @@ -From 5635f897ed83fd539df78e98ba69ee91592f9bb8 Mon Sep 17 00:00:00 2001 +From 5d927beed36f215ae2443e260480880a5e1452a5 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 12 Jul 2019 21:55:21 +0300 Subject: floppy: fix out-of-bounds read in next_valid_format -From: Denis Efremov - -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. @@ -28,15 +26,16 @@ The bug was found by syzkaller. Signed-off-by: Denis Efremov Tested-by: Willy Tarreau Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - +Signed-off-by: Sasha Levin --- - 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; } @@ -57,7 +56,7 @@ Signed-off-by: Greg Kroah-Hartman 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: @@ -66,3 +65,15 @@ Signed-off-by: Greg Kroah-Hartman *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 + diff --git a/queue-4.9/series b/queue-4.9/series index bbdcf87d2ec..678d1708225 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -72,10 +72,6 @@ bluetooth-check-state-in-l2cap_disconnect_rsp.patch 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 @@ -105,3 +101,8 @@ padata-use-smp_mb-in-padata_reorder-to-avoid-orphaned-padata-jobs.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 diff --git a/queue-4.9/take-floppy-compat-ioctls-to-sodding-floppy.c.patch b/queue-4.9/take-floppy-compat-ioctls-to-sodding-floppy.c.patch new file mode 100644 index 00000000000..19d64711a3d --- /dev/null +++ b/queue-4.9/take-floppy-compat-ioctls-to-sodding-floppy.c.patch @@ -0,0 +1,745 @@ +From 3850e02efae9bd24e29eae9e6c289e4d8a0b637c Mon Sep 17 00:00:00 2001 +From: Al Viro +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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + #include + #include ++#include + + /* + * 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 +