diff options
author | Christoph Hellwig <hch@lst.de> | 2020-04-06 13:58:35 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2020-04-06 21:42:36 +0200 |
commit | 0f5c4c6e0e9874952e2950465a8859782437b465 (patch) | |
tree | f78a3b5bf538b08ec16c562a6fa00fd2bccef4b8 /kernel | |
parent | PM / sleep: move SNAPSHOT_SET_SWAP_AREA handling into a helper (diff) | |
download | linux-0f5c4c6e0e9874952e2950465a8859782437b465.tar.xz linux-0f5c4c6e0e9874952e2950465a8859782437b465.zip |
PM / sleep: handle the compat case in snapshot_set_swap_area()
Use in_compat_syscall to copy directly from the 32-bit ABI structure.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/user.c | 54 |
1 files changed, 22 insertions, 32 deletions
diff --git a/kernel/power/user.c b/kernel/power/user.c index 0cb555f526e4..7959449765d9 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -196,28 +196,44 @@ unlock: return res; } +struct compat_resume_swap_area { + compat_loff_t offset; + u32 dev; +} __packed; + static int snapshot_set_swap_area(struct snapshot_data *data, void __user *argp) { - struct resume_swap_area swap_area; sector_t offset; dev_t swdev; if (swsusp_swap_in_use()) return -EPERM; - if (copy_from_user(&swap_area, argp, sizeof(swap_area))) - return -EFAULT; + + if (in_compat_syscall()) { + struct compat_resume_swap_area swap_area; + + if (copy_from_user(&swap_area, argp, sizeof(swap_area))) + return -EFAULT; + swdev = new_decode_dev(swap_area.dev); + offset = swap_area.offset; + } else { + struct resume_swap_area swap_area; + + if (copy_from_user(&swap_area, argp, sizeof(swap_area))) + return -EFAULT; + swdev = new_decode_dev(swap_area.dev); + offset = swap_area.offset; + } /* * User space encodes device types as two-byte values, * so we need to recode them */ - swdev = new_decode_dev(swap_area.dev); if (!swdev) { data->swap = -1; return -EINVAL; } - offset = swap_area.offset; data->swap = swap_type_of(swdev, offset, NULL); if (data->swap < 0) return -ENODEV; @@ -394,12 +410,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, } #ifdef CONFIG_COMPAT - -struct compat_resume_swap_area { - compat_loff_t offset; - u32 dev; -} __packed; - static long snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -410,33 +420,13 @@ snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case SNAPSHOT_AVAIL_SWAP_SIZE: case SNAPSHOT_ALLOC_SWAP_PAGE: case SNAPSHOT_CREATE_IMAGE: + case SNAPSHOT_SET_SWAP_AREA: return snapshot_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); - - case SNAPSHOT_SET_SWAP_AREA: { - struct compat_resume_swap_area __user *u_swap_area = - compat_ptr(arg); - struct resume_swap_area swap_area; - mm_segment_t old_fs; - int err; - - err = get_user(swap_area.offset, &u_swap_area->offset); - err |= get_user(swap_area.dev, &u_swap_area->dev); - if (err) - return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA, - (unsigned long) &swap_area); - set_fs(old_fs); - return err; - } - default: return snapshot_ioctl(file, cmd, arg); } } - #endif /* CONFIG_COMPAT */ static const struct file_operations snapshot_fops = { |