| From f965b5c3b2cab8a71f3fa4efe6fa9c24d0f2ff11 Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Thu, 16 Jan 2020 11:29:20 +0000 |
| Subject: [PATCH] Btrfs: always copy scrub arguments back to user space |
| |
| commit 5afe6ce748c1ea99e0d648153c05075e1ab93afb upstream. |
| |
| If scrub returns an error we are not copying back the scrub arguments |
| structure to user space. This prevents user space to know how much |
| progress scrub has done if an error happened - this includes -ECANCELED |
| which is returned when users ask for scrub to stop. A particular use |
| case, which is used in btrfs-progs, is to resume scrub after it is |
| canceled, in that case it relies on checking the progress from the scrub |
| arguments structure and then use that progress in a call to resume |
| scrub. |
| |
| So fix this by always copying the scrub arguments structure to user |
| space, overwriting the value returned to user space with -EFAULT only if |
| copying the structure failed to let user space know that either that |
| copying did not happen, and therefore the structure is stale, or it |
| happened partially and the structure is probably not valid and corrupt |
| due to the partial copy. |
| |
| Reported-by: Graham Cobb <g.btrfs@cobb.uk.net> |
| Link: https://lore.kernel.org/linux-btrfs/d0a97688-78be-08de-ca7d-bcb4c7fb397e@cobb.uk.net/ |
| Fixes: 06fe39ab15a6a4 ("Btrfs: do not overwrite scrub error with fault error in scrub ioctl") |
| CC: stable@vger.kernel.org # 5.1+ |
| Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> |
| Reviewed-by: Qu Wenruo <wqu@suse.com> |
| Tested-by: Graham Cobb <g.btrfs@cobb.uk.net> |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c |
| index 69f969d849c0..1357a9397982 100644 |
| --- a/fs/btrfs/ioctl.c |
| +++ b/fs/btrfs/ioctl.c |
| @@ -4380,7 +4380,19 @@ static long btrfs_ioctl_scrub(struct file *file, void __user *arg) |
| &sa->progress, sa->flags & BTRFS_SCRUB_READONLY, |
| 0); |
| |
| - if (ret == 0 && copy_to_user(arg, sa, sizeof(*sa))) |
| + /* |
| + * Copy scrub args to user space even if btrfs_scrub_dev() returned an |
| + * error. This is important as it allows user space to know how much |
| + * progress scrub has done. For example, if scrub is canceled we get |
| + * -ECANCELED from btrfs_scrub_dev() and return that error back to user |
| + * space. Later user space can inspect the progress from the structure |
| + * btrfs_ioctl_scrub_args and resume scrub from where it left off |
| + * previously (btrfs-progs does this). |
| + * If we fail to copy the btrfs_ioctl_scrub_args structure to user space |
| + * then return -EFAULT to signal the structure was not copied or it may |
| + * be corrupt and unreliable due to a partial copy. |
| + */ |
| + if (copy_to_user(arg, sa, sizeof(*sa))) |
| ret = -EFAULT; |
| |
| if (!(sa->flags & BTRFS_SCRUB_READONLY)) |
| -- |
| 2.7.4 |
| |