Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Christoph Hellwig and committed by
Rafael J. Wysocki
0f5c4c6e 88a77559

+22 -32
+22 -32
kernel/power/user.c
··· 196 196 return res; 197 197 } 198 198 199 + struct compat_resume_swap_area { 200 + compat_loff_t offset; 201 + u32 dev; 202 + } __packed; 203 + 199 204 static int snapshot_set_swap_area(struct snapshot_data *data, 200 205 void __user *argp) 201 206 { 202 - struct resume_swap_area swap_area; 203 207 sector_t offset; 204 208 dev_t swdev; 205 209 206 210 if (swsusp_swap_in_use()) 207 211 return -EPERM; 208 - if (copy_from_user(&swap_area, argp, sizeof(swap_area))) 209 - return -EFAULT; 212 + 213 + if (in_compat_syscall()) { 214 + struct compat_resume_swap_area swap_area; 215 + 216 + if (copy_from_user(&swap_area, argp, sizeof(swap_area))) 217 + return -EFAULT; 218 + swdev = new_decode_dev(swap_area.dev); 219 + offset = swap_area.offset; 220 + } else { 221 + struct resume_swap_area swap_area; 222 + 223 + if (copy_from_user(&swap_area, argp, sizeof(swap_area))) 224 + return -EFAULT; 225 + swdev = new_decode_dev(swap_area.dev); 226 + offset = swap_area.offset; 227 + } 210 228 211 229 /* 212 230 * User space encodes device types as two-byte values, 213 231 * so we need to recode them 214 232 */ 215 - swdev = new_decode_dev(swap_area.dev); 216 233 if (!swdev) { 217 234 data->swap = -1; 218 235 return -EINVAL; 219 236 } 220 - offset = swap_area.offset; 221 237 data->swap = swap_type_of(swdev, offset, NULL); 222 238 if (data->swap < 0) 223 239 return -ENODEV; ··· 410 394 } 411 395 412 396 #ifdef CONFIG_COMPAT 413 - 414 - struct compat_resume_swap_area { 415 - compat_loff_t offset; 416 - u32 dev; 417 - } __packed; 418 - 419 397 static long 420 398 snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 421 399 { ··· 420 410 case SNAPSHOT_AVAIL_SWAP_SIZE: 421 411 case SNAPSHOT_ALLOC_SWAP_PAGE: 422 412 case SNAPSHOT_CREATE_IMAGE: 413 + case SNAPSHOT_SET_SWAP_AREA: 423 414 return snapshot_ioctl(file, cmd, 424 415 (unsigned long) compat_ptr(arg)); 425 - 426 - case SNAPSHOT_SET_SWAP_AREA: { 427 - struct compat_resume_swap_area __user *u_swap_area = 428 - compat_ptr(arg); 429 - struct resume_swap_area swap_area; 430 - mm_segment_t old_fs; 431 - int err; 432 - 433 - err = get_user(swap_area.offset, &u_swap_area->offset); 434 - err |= get_user(swap_area.dev, &u_swap_area->dev); 435 - if (err) 436 - return -EFAULT; 437 - old_fs = get_fs(); 438 - set_fs(KERNEL_DS); 439 - err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA, 440 - (unsigned long) &swap_area); 441 - set_fs(old_fs); 442 - return err; 443 - } 444 - 445 416 default: 446 417 return snapshot_ioctl(file, cmd, arg); 447 418 } 448 419 } 449 - 450 420 #endif /* CONFIG_COMPAT */ 451 421 452 422 static const struct file_operations snapshot_fops = {