| .. | .. |
|---|
| 8 | 8 | #include <linux/syscalls.h> |
|---|
| 9 | 9 | #include <linux/mm.h> |
|---|
| 10 | 10 | #include <linux/capability.h> |
|---|
| 11 | +#include <linux/compat.h> |
|---|
| 11 | 12 | #include <linux/file.h> |
|---|
| 12 | 13 | #include <linux/fs.h> |
|---|
| 13 | 14 | #include <linux/security.h> |
|---|
| .. | .. |
|---|
| 17 | 18 | #include <linux/buffer_head.h> |
|---|
| 18 | 19 | #include <linux/falloc.h> |
|---|
| 19 | 20 | #include <linux/sched/signal.h> |
|---|
| 21 | +#include <linux/fiemap.h> |
|---|
| 20 | 22 | |
|---|
| 21 | 23 | #include "internal.h" |
|---|
| 22 | 24 | |
|---|
| .. | .. |
|---|
| 53 | 55 | |
|---|
| 54 | 56 | static int ioctl_fibmap(struct file *filp, int __user *p) |
|---|
| 55 | 57 | { |
|---|
| 56 | | - struct address_space *mapping = filp->f_mapping; |
|---|
| 57 | | - int res, block; |
|---|
| 58 | + struct inode *inode = file_inode(filp); |
|---|
| 59 | + struct super_block *sb = inode->i_sb; |
|---|
| 60 | + int error, ur_block; |
|---|
| 61 | + sector_t block; |
|---|
| 58 | 62 | |
|---|
| 59 | | - /* do we support this mess? */ |
|---|
| 60 | | - if (!mapping->a_ops->bmap) |
|---|
| 61 | | - return -EINVAL; |
|---|
| 62 | 63 | if (!capable(CAP_SYS_RAWIO)) |
|---|
| 63 | 64 | return -EPERM; |
|---|
| 64 | | - res = get_user(block, p); |
|---|
| 65 | | - if (res) |
|---|
| 66 | | - return res; |
|---|
| 67 | | - res = mapping->a_ops->bmap(mapping, block); |
|---|
| 68 | | - return put_user(res, p); |
|---|
| 65 | + |
|---|
| 66 | + error = get_user(ur_block, p); |
|---|
| 67 | + if (error) |
|---|
| 68 | + return error; |
|---|
| 69 | + |
|---|
| 70 | + if (ur_block < 0) |
|---|
| 71 | + return -EINVAL; |
|---|
| 72 | + |
|---|
| 73 | + block = ur_block; |
|---|
| 74 | + error = bmap(inode, &block); |
|---|
| 75 | + |
|---|
| 76 | + if (block > INT_MAX) { |
|---|
| 77 | + error = -ERANGE; |
|---|
| 78 | + pr_warn_ratelimited("[%s/%d] FS: %s File: %pD4 would truncate fibmap result\n", |
|---|
| 79 | + current->comm, task_pid_nr(current), |
|---|
| 80 | + sb->s_id, filp); |
|---|
| 81 | + } |
|---|
| 82 | + |
|---|
| 83 | + if (error) |
|---|
| 84 | + ur_block = 0; |
|---|
| 85 | + else |
|---|
| 86 | + ur_block = block; |
|---|
| 87 | + |
|---|
| 88 | + if (put_user(ur_block, p)) |
|---|
| 89 | + error = -EFAULT; |
|---|
| 90 | + |
|---|
| 91 | + return error; |
|---|
| 69 | 92 | } |
|---|
| 70 | 93 | |
|---|
| 71 | 94 | /** |
|---|
| .. | .. |
|---|
| 123 | 146 | return 1; |
|---|
| 124 | 147 | return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; |
|---|
| 125 | 148 | } |
|---|
| 126 | | -EXPORT_SYMBOL(fiemap_fill_next_extent); |
|---|
| 149 | +EXPORT_SYMBOL_NS(fiemap_fill_next_extent, ANDROID_GKI_VFS_EXPORT_ONLY); |
|---|
| 127 | 150 | |
|---|
| 128 | 151 | /** |
|---|
| 129 | | - * fiemap_check_flags - check validity of requested flags for fiemap |
|---|
| 152 | + * fiemap_prep - check validity of requested flags for fiemap |
|---|
| 153 | + * @inode: Inode to operate on |
|---|
| 130 | 154 | * @fieinfo: Fiemap context passed into ->fiemap |
|---|
| 131 | | - * @fs_flags: Set of fiemap flags that the file system understands |
|---|
| 155 | + * @start: Start of the mapped range |
|---|
| 156 | + * @len: Length of the mapped range, can be truncated by this function. |
|---|
| 157 | + * @supported_flags: Set of fiemap flags that the file system understands |
|---|
| 132 | 158 | * |
|---|
| 133 | | - * Called from file system ->fiemap callback. This will compute the |
|---|
| 134 | | - * intersection of valid fiemap flags and those that the fs supports. That |
|---|
| 135 | | - * value is then compared against the user supplied flags. In case of bad user |
|---|
| 136 | | - * flags, the invalid values will be written into the fieinfo structure, and |
|---|
| 137 | | - * -EBADR is returned, which tells ioctl_fiemap() to return those values to |
|---|
| 138 | | - * userspace. For this reason, a return code of -EBADR should be preserved. |
|---|
| 159 | + * This function must be called from each ->fiemap instance to validate the |
|---|
| 160 | + * fiemap request against the file system parameters. |
|---|
| 139 | 161 | * |
|---|
| 140 | | - * Returns 0 on success, -EBADR on bad flags. |
|---|
| 162 | + * Returns 0 on success, or a negative error on failure. |
|---|
| 141 | 163 | */ |
|---|
| 142 | | -int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags) |
|---|
| 164 | +int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, |
|---|
| 165 | + u64 start, u64 *len, u32 supported_flags) |
|---|
| 143 | 166 | { |
|---|
| 167 | + u64 maxbytes = inode->i_sb->s_maxbytes; |
|---|
| 144 | 168 | u32 incompat_flags; |
|---|
| 169 | + int ret = 0; |
|---|
| 145 | 170 | |
|---|
| 146 | | - incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags); |
|---|
| 147 | | - if (incompat_flags) { |
|---|
| 148 | | - fieinfo->fi_flags = incompat_flags; |
|---|
| 149 | | - return -EBADR; |
|---|
| 150 | | - } |
|---|
| 151 | | - return 0; |
|---|
| 152 | | -} |
|---|
| 153 | | -EXPORT_SYMBOL(fiemap_check_flags); |
|---|
| 154 | | - |
|---|
| 155 | | -static int fiemap_check_ranges(struct super_block *sb, |
|---|
| 156 | | - u64 start, u64 len, u64 *new_len) |
|---|
| 157 | | -{ |
|---|
| 158 | | - u64 maxbytes = (u64) sb->s_maxbytes; |
|---|
| 159 | | - |
|---|
| 160 | | - *new_len = len; |
|---|
| 161 | | - |
|---|
| 162 | | - if (len == 0) |
|---|
| 171 | + if (*len == 0) |
|---|
| 163 | 172 | return -EINVAL; |
|---|
| 164 | | - |
|---|
| 165 | | - if (start > maxbytes) |
|---|
| 173 | + if (start >= maxbytes) |
|---|
| 166 | 174 | return -EFBIG; |
|---|
| 167 | 175 | |
|---|
| 168 | 176 | /* |
|---|
| 169 | 177 | * Shrink request scope to what the fs can actually handle. |
|---|
| 170 | 178 | */ |
|---|
| 171 | | - if (len > maxbytes || (maxbytes - len) < start) |
|---|
| 172 | | - *new_len = maxbytes - start; |
|---|
| 179 | + if (*len > maxbytes || (maxbytes - *len) < start) |
|---|
| 180 | + *len = maxbytes - start; |
|---|
| 173 | 181 | |
|---|
| 174 | | - return 0; |
|---|
| 182 | + supported_flags |= FIEMAP_FLAG_SYNC; |
|---|
| 183 | + supported_flags &= FIEMAP_FLAGS_COMPAT; |
|---|
| 184 | + incompat_flags = fieinfo->fi_flags & ~supported_flags; |
|---|
| 185 | + if (incompat_flags) { |
|---|
| 186 | + fieinfo->fi_flags = incompat_flags; |
|---|
| 187 | + return -EBADR; |
|---|
| 188 | + } |
|---|
| 189 | + |
|---|
| 190 | + if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) |
|---|
| 191 | + ret = filemap_write_and_wait(inode->i_mapping); |
|---|
| 192 | + return ret; |
|---|
| 175 | 193 | } |
|---|
| 194 | +EXPORT_SYMBOL_NS(fiemap_prep, ANDROID_GKI_VFS_EXPORT_ONLY); |
|---|
| 176 | 195 | |
|---|
| 177 | | -static int ioctl_fiemap(struct file *filp, unsigned long arg) |
|---|
| 196 | +static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) |
|---|
| 178 | 197 | { |
|---|
| 179 | 198 | struct fiemap fiemap; |
|---|
| 180 | | - struct fiemap __user *ufiemap = (struct fiemap __user *) arg; |
|---|
| 181 | 199 | struct fiemap_extent_info fieinfo = { 0, }; |
|---|
| 182 | 200 | struct inode *inode = file_inode(filp); |
|---|
| 183 | | - struct super_block *sb = inode->i_sb; |
|---|
| 184 | | - u64 len; |
|---|
| 185 | 201 | int error; |
|---|
| 186 | 202 | |
|---|
| 187 | 203 | if (!inode->i_op->fiemap) |
|---|
| .. | .. |
|---|
| 193 | 209 | if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) |
|---|
| 194 | 210 | return -EINVAL; |
|---|
| 195 | 211 | |
|---|
| 196 | | - error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length, |
|---|
| 197 | | - &len); |
|---|
| 198 | | - if (error) |
|---|
| 199 | | - return error; |
|---|
| 200 | | - |
|---|
| 201 | 212 | fieinfo.fi_flags = fiemap.fm_flags; |
|---|
| 202 | 213 | fieinfo.fi_extents_max = fiemap.fm_extent_count; |
|---|
| 203 | 214 | fieinfo.fi_extents_start = ufiemap->fm_extents; |
|---|
| 204 | 215 | |
|---|
| 205 | | - if (fiemap.fm_extent_count != 0 && |
|---|
| 206 | | - !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start, |
|---|
| 207 | | - fieinfo.fi_extents_max * sizeof(struct fiemap_extent))) |
|---|
| 208 | | - return -EFAULT; |
|---|
| 216 | + error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, |
|---|
| 217 | + fiemap.fm_length); |
|---|
| 209 | 218 | |
|---|
| 210 | | - if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) |
|---|
| 211 | | - filemap_write_and_wait(inode->i_mapping); |
|---|
| 212 | | - |
|---|
| 213 | | - error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len); |
|---|
| 214 | 219 | fiemap.fm_flags = fieinfo.fi_flags; |
|---|
| 215 | 220 | fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; |
|---|
| 216 | 221 | if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap))) |
|---|
| .. | .. |
|---|
| 223 | 228 | u64 off, u64 olen, u64 destoff) |
|---|
| 224 | 229 | { |
|---|
| 225 | 230 | struct fd src_file = fdget(srcfd); |
|---|
| 231 | + loff_t cloned; |
|---|
| 226 | 232 | int ret; |
|---|
| 227 | 233 | |
|---|
| 228 | 234 | if (!src_file.file) |
|---|
| .. | .. |
|---|
| 230 | 236 | ret = -EXDEV; |
|---|
| 231 | 237 | if (src_file.file->f_path.mnt != dst_file->f_path.mnt) |
|---|
| 232 | 238 | goto fdput; |
|---|
| 233 | | - ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen); |
|---|
| 239 | + cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff, |
|---|
| 240 | + olen, 0); |
|---|
| 241 | + if (cloned < 0) |
|---|
| 242 | + ret = cloned; |
|---|
| 243 | + else if (olen && cloned != olen) |
|---|
| 244 | + ret = -EINVAL; |
|---|
| 245 | + else |
|---|
| 246 | + ret = 0; |
|---|
| 234 | 247 | fdput: |
|---|
| 235 | 248 | fdput(src_file); |
|---|
| 236 | 249 | return ret; |
|---|
| 237 | 250 | } |
|---|
| 238 | 251 | |
|---|
| 239 | | -static long ioctl_file_clone_range(struct file *file, void __user *argp) |
|---|
| 252 | +static long ioctl_file_clone_range(struct file *file, |
|---|
| 253 | + struct file_clone_range __user *argp) |
|---|
| 240 | 254 | { |
|---|
| 241 | 255 | struct file_clone_range args; |
|---|
| 242 | 256 | |
|---|
| .. | .. |
|---|
| 277 | 291 | * If you use this function directly, you need to do your own locking. Use |
|---|
| 278 | 292 | * generic_block_fiemap if you want the locking done for you. |
|---|
| 279 | 293 | */ |
|---|
| 280 | | - |
|---|
| 281 | | -int __generic_block_fiemap(struct inode *inode, |
|---|
| 294 | +static int __generic_block_fiemap(struct inode *inode, |
|---|
| 282 | 295 | struct fiemap_extent_info *fieinfo, loff_t start, |
|---|
| 283 | 296 | loff_t len, get_block_t *get_block) |
|---|
| 284 | 297 | { |
|---|
| .. | .. |
|---|
| 290 | 303 | bool past_eof = false, whole_file = false; |
|---|
| 291 | 304 | int ret = 0; |
|---|
| 292 | 305 | |
|---|
| 293 | | - ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); |
|---|
| 306 | + ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC); |
|---|
| 294 | 307 | if (ret) |
|---|
| 295 | 308 | return ret; |
|---|
| 296 | 309 | |
|---|
| .. | .. |
|---|
| 423 | 436 | |
|---|
| 424 | 437 | return ret; |
|---|
| 425 | 438 | } |
|---|
| 426 | | -EXPORT_SYMBOL(__generic_block_fiemap); |
|---|
| 427 | 439 | |
|---|
| 428 | 440 | /** |
|---|
| 429 | 441 | * generic_block_fiemap - FIEMAP for block based inodes |
|---|
| .. | .. |
|---|
| 458 | 470 | * Only the l_start, l_len and l_whence fields of the 'struct space_resv' |
|---|
| 459 | 471 | * are used here, rest are ignored. |
|---|
| 460 | 472 | */ |
|---|
| 461 | | -int ioctl_preallocate(struct file *filp, void __user *argp) |
|---|
| 473 | +static int ioctl_preallocate(struct file *filp, int mode, void __user *argp) |
|---|
| 462 | 474 | { |
|---|
| 463 | 475 | struct inode *inode = file_inode(filp); |
|---|
| 464 | 476 | struct space_resv sr; |
|---|
| .. | .. |
|---|
| 479 | 491 | return -EINVAL; |
|---|
| 480 | 492 | } |
|---|
| 481 | 493 | |
|---|
| 482 | | - return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); |
|---|
| 494 | + return vfs_fallocate(filp, mode | FALLOC_FL_KEEP_SIZE, sr.l_start, |
|---|
| 495 | + sr.l_len); |
|---|
| 483 | 496 | } |
|---|
| 484 | 497 | |
|---|
| 485 | | -static int file_ioctl(struct file *filp, unsigned int cmd, |
|---|
| 486 | | - unsigned long arg) |
|---|
| 498 | +/* on ia32 l_start is on a 32-bit boundary */ |
|---|
| 499 | +#if defined CONFIG_COMPAT && defined(CONFIG_X86_64) |
|---|
| 500 | +/* just account for different alignment */ |
|---|
| 501 | +static int compat_ioctl_preallocate(struct file *file, int mode, |
|---|
| 502 | + struct space_resv_32 __user *argp) |
|---|
| 487 | 503 | { |
|---|
| 488 | | - struct inode *inode = file_inode(filp); |
|---|
| 489 | | - int __user *p = (int __user *)arg; |
|---|
| 504 | + struct inode *inode = file_inode(file); |
|---|
| 505 | + struct space_resv_32 sr; |
|---|
| 490 | 506 | |
|---|
| 507 | + if (copy_from_user(&sr, argp, sizeof(sr))) |
|---|
| 508 | + return -EFAULT; |
|---|
| 509 | + |
|---|
| 510 | + switch (sr.l_whence) { |
|---|
| 511 | + case SEEK_SET: |
|---|
| 512 | + break; |
|---|
| 513 | + case SEEK_CUR: |
|---|
| 514 | + sr.l_start += file->f_pos; |
|---|
| 515 | + break; |
|---|
| 516 | + case SEEK_END: |
|---|
| 517 | + sr.l_start += i_size_read(inode); |
|---|
| 518 | + break; |
|---|
| 519 | + default: |
|---|
| 520 | + return -EINVAL; |
|---|
| 521 | + } |
|---|
| 522 | + |
|---|
| 523 | + return vfs_fallocate(file, mode | FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); |
|---|
| 524 | +} |
|---|
| 525 | +#endif |
|---|
| 526 | + |
|---|
| 527 | +static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p) |
|---|
| 528 | +{ |
|---|
| 491 | 529 | switch (cmd) { |
|---|
| 492 | 530 | case FIBMAP: |
|---|
| 493 | 531 | return ioctl_fibmap(filp, p); |
|---|
| 494 | | - case FIONREAD: |
|---|
| 495 | | - return put_user(i_size_read(inode) - filp->f_pos, p); |
|---|
| 496 | 532 | case FS_IOC_RESVSP: |
|---|
| 497 | 533 | case FS_IOC_RESVSP64: |
|---|
| 498 | | - return ioctl_preallocate(filp, p); |
|---|
| 534 | + return ioctl_preallocate(filp, 0, p); |
|---|
| 535 | + case FS_IOC_UNRESVSP: |
|---|
| 536 | + case FS_IOC_UNRESVSP64: |
|---|
| 537 | + return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, p); |
|---|
| 538 | + case FS_IOC_ZERO_RANGE: |
|---|
| 539 | + return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p); |
|---|
| 499 | 540 | } |
|---|
| 500 | 541 | |
|---|
| 501 | | - return vfs_ioctl(filp, cmd, arg); |
|---|
| 542 | + return -ENOIOCTLCMD; |
|---|
| 502 | 543 | } |
|---|
| 503 | 544 | |
|---|
| 504 | 545 | static int ioctl_fionbio(struct file *filp, int __user *argp) |
|---|
| .. | .. |
|---|
| 576 | 617 | return thaw_super(sb); |
|---|
| 577 | 618 | } |
|---|
| 578 | 619 | |
|---|
| 579 | | -static int ioctl_file_dedupe_range(struct file *file, void __user *arg) |
|---|
| 620 | +static int ioctl_file_dedupe_range(struct file *file, |
|---|
| 621 | + struct file_dedupe_range __user *argp) |
|---|
| 580 | 622 | { |
|---|
| 581 | | - struct file_dedupe_range __user *argp = arg; |
|---|
| 582 | 623 | struct file_dedupe_range *same = NULL; |
|---|
| 583 | 624 | int ret; |
|---|
| 584 | 625 | unsigned long size; |
|---|
| .. | .. |
|---|
| 617 | 658 | } |
|---|
| 618 | 659 | |
|---|
| 619 | 660 | /* |
|---|
| 620 | | - * When you add any new common ioctls to the switches above and below |
|---|
| 621 | | - * please update compat_sys_ioctl() too. |
|---|
| 622 | | - * |
|---|
| 623 | 661 | * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. |
|---|
| 624 | 662 | * It's just a simple helper for sys_ioctl and compat_sys_ioctl. |
|---|
| 663 | + * |
|---|
| 664 | + * When you add any new common ioctls to the switches above and below, |
|---|
| 665 | + * please ensure they have compatible arguments in compat mode. |
|---|
| 625 | 666 | */ |
|---|
| 626 | | -int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, |
|---|
| 627 | | - unsigned long arg) |
|---|
| 667 | +static int do_vfs_ioctl(struct file *filp, unsigned int fd, |
|---|
| 668 | + unsigned int cmd, unsigned long arg) |
|---|
| 628 | 669 | { |
|---|
| 629 | | - int error = 0; |
|---|
| 630 | | - int __user *argp = (int __user *)arg; |
|---|
| 670 | + void __user *argp = (void __user *)arg; |
|---|
| 631 | 671 | struct inode *inode = file_inode(filp); |
|---|
| 632 | 672 | |
|---|
| 633 | 673 | switch (cmd) { |
|---|
| 634 | 674 | case FIOCLEX: |
|---|
| 635 | 675 | set_close_on_exec(fd, 1); |
|---|
| 636 | | - break; |
|---|
| 676 | + return 0; |
|---|
| 637 | 677 | |
|---|
| 638 | 678 | case FIONCLEX: |
|---|
| 639 | 679 | set_close_on_exec(fd, 0); |
|---|
| 640 | | - break; |
|---|
| 680 | + return 0; |
|---|
| 641 | 681 | |
|---|
| 642 | 682 | case FIONBIO: |
|---|
| 643 | | - error = ioctl_fionbio(filp, argp); |
|---|
| 644 | | - break; |
|---|
| 683 | + return ioctl_fionbio(filp, argp); |
|---|
| 645 | 684 | |
|---|
| 646 | 685 | case FIOASYNC: |
|---|
| 647 | | - error = ioctl_fioasync(fd, filp, argp); |
|---|
| 648 | | - break; |
|---|
| 686 | + return ioctl_fioasync(fd, filp, argp); |
|---|
| 649 | 687 | |
|---|
| 650 | 688 | case FIOQSIZE: |
|---|
| 651 | 689 | if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) || |
|---|
| 652 | 690 | S_ISLNK(inode->i_mode)) { |
|---|
| 653 | 691 | loff_t res = inode_get_bytes(inode); |
|---|
| 654 | | - error = copy_to_user(argp, &res, sizeof(res)) ? |
|---|
| 655 | | - -EFAULT : 0; |
|---|
| 656 | | - } else |
|---|
| 657 | | - error = -ENOTTY; |
|---|
| 658 | | - break; |
|---|
| 692 | + return copy_to_user(argp, &res, sizeof(res)) ? |
|---|
| 693 | + -EFAULT : 0; |
|---|
| 694 | + } |
|---|
| 695 | + |
|---|
| 696 | + return -ENOTTY; |
|---|
| 659 | 697 | |
|---|
| 660 | 698 | case FIFREEZE: |
|---|
| 661 | | - error = ioctl_fsfreeze(filp); |
|---|
| 662 | | - break; |
|---|
| 699 | + return ioctl_fsfreeze(filp); |
|---|
| 663 | 700 | |
|---|
| 664 | 701 | case FITHAW: |
|---|
| 665 | | - error = ioctl_fsthaw(filp); |
|---|
| 666 | | - break; |
|---|
| 702 | + return ioctl_fsthaw(filp); |
|---|
| 667 | 703 | |
|---|
| 668 | 704 | case FS_IOC_FIEMAP: |
|---|
| 669 | | - return ioctl_fiemap(filp, arg); |
|---|
| 705 | + return ioctl_fiemap(filp, argp); |
|---|
| 670 | 706 | |
|---|
| 671 | 707 | case FIGETBSZ: |
|---|
| 672 | 708 | /* anon_bdev filesystems may not have a block size */ |
|---|
| 673 | 709 | if (!inode->i_sb->s_blocksize) |
|---|
| 674 | 710 | return -EINVAL; |
|---|
| 675 | | - return put_user(inode->i_sb->s_blocksize, argp); |
|---|
| 711 | + |
|---|
| 712 | + return put_user(inode->i_sb->s_blocksize, (int __user *)argp); |
|---|
| 676 | 713 | |
|---|
| 677 | 714 | case FICLONE: |
|---|
| 678 | 715 | return ioctl_file_clone(filp, arg, 0, 0, 0); |
|---|
| .. | .. |
|---|
| 683 | 720 | case FIDEDUPERANGE: |
|---|
| 684 | 721 | return ioctl_file_dedupe_range(filp, argp); |
|---|
| 685 | 722 | |
|---|
| 723 | + case FIONREAD: |
|---|
| 724 | + if (!S_ISREG(inode->i_mode)) |
|---|
| 725 | + return vfs_ioctl(filp, cmd, arg); |
|---|
| 726 | + |
|---|
| 727 | + return put_user(i_size_read(inode) - filp->f_pos, |
|---|
| 728 | + (int __user *)argp); |
|---|
| 729 | + |
|---|
| 686 | 730 | default: |
|---|
| 687 | 731 | if (S_ISREG(inode->i_mode)) |
|---|
| 688 | | - error = file_ioctl(filp, cmd, arg); |
|---|
| 689 | | - else |
|---|
| 690 | | - error = vfs_ioctl(filp, cmd, arg); |
|---|
| 732 | + return file_ioctl(filp, cmd, argp); |
|---|
| 691 | 733 | break; |
|---|
| 692 | 734 | } |
|---|
| 693 | | - return error; |
|---|
| 694 | | -} |
|---|
| 695 | 735 | |
|---|
| 696 | | -int ksys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
|---|
| 697 | | -{ |
|---|
| 698 | | - int error; |
|---|
| 699 | | - struct fd f = fdget(fd); |
|---|
| 700 | | - |
|---|
| 701 | | - if (!f.file) |
|---|
| 702 | | - return -EBADF; |
|---|
| 703 | | - error = security_file_ioctl(f.file, cmd, arg); |
|---|
| 704 | | - if (!error) |
|---|
| 705 | | - error = do_vfs_ioctl(f.file, fd, cmd, arg); |
|---|
| 706 | | - fdput(f); |
|---|
| 707 | | - return error; |
|---|
| 736 | + return -ENOIOCTLCMD; |
|---|
| 708 | 737 | } |
|---|
| 709 | 738 | |
|---|
| 710 | 739 | SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) |
|---|
| 711 | 740 | { |
|---|
| 712 | | - return ksys_ioctl(fd, cmd, arg); |
|---|
| 741 | + struct fd f = fdget(fd); |
|---|
| 742 | + int error; |
|---|
| 743 | + |
|---|
| 744 | + if (!f.file) |
|---|
| 745 | + return -EBADF; |
|---|
| 746 | + |
|---|
| 747 | + error = security_file_ioctl(f.file, cmd, arg); |
|---|
| 748 | + if (error) |
|---|
| 749 | + goto out; |
|---|
| 750 | + |
|---|
| 751 | + error = do_vfs_ioctl(f.file, fd, cmd, arg); |
|---|
| 752 | + if (error == -ENOIOCTLCMD) |
|---|
| 753 | + error = vfs_ioctl(f.file, cmd, arg); |
|---|
| 754 | + |
|---|
| 755 | +out: |
|---|
| 756 | + fdput(f); |
|---|
| 757 | + return error; |
|---|
| 713 | 758 | } |
|---|
| 759 | + |
|---|
| 760 | +#ifdef CONFIG_COMPAT |
|---|
| 761 | +/** |
|---|
| 762 | + * compat_ptr_ioctl - generic implementation of .compat_ioctl file operation |
|---|
| 763 | + * |
|---|
| 764 | + * This is not normally called as a function, but instead set in struct |
|---|
| 765 | + * file_operations as |
|---|
| 766 | + * |
|---|
| 767 | + * .compat_ioctl = compat_ptr_ioctl, |
|---|
| 768 | + * |
|---|
| 769 | + * On most architectures, the compat_ptr_ioctl() just passes all arguments |
|---|
| 770 | + * to the corresponding ->ioctl handler. The exception is arch/s390, where |
|---|
| 771 | + * compat_ptr() clears the top bit of a 32-bit pointer value, so user space |
|---|
| 772 | + * pointers to the second 2GB alias the first 2GB, as is the case for |
|---|
| 773 | + * native 32-bit s390 user space. |
|---|
| 774 | + * |
|---|
| 775 | + * The compat_ptr_ioctl() function must therefore be used only with ioctl |
|---|
| 776 | + * functions that either ignore the argument or pass a pointer to a |
|---|
| 777 | + * compatible data type. |
|---|
| 778 | + * |
|---|
| 779 | + * If any ioctl command handled by fops->unlocked_ioctl passes a plain |
|---|
| 780 | + * integer instead of a pointer, or any of the passed data types |
|---|
| 781 | + * is incompatible between 32-bit and 64-bit architectures, a proper |
|---|
| 782 | + * handler is required instead of compat_ptr_ioctl. |
|---|
| 783 | + */ |
|---|
| 784 | +long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
|---|
| 785 | +{ |
|---|
| 786 | + if (!file->f_op->unlocked_ioctl) |
|---|
| 787 | + return -ENOIOCTLCMD; |
|---|
| 788 | + |
|---|
| 789 | + return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
|---|
| 790 | +} |
|---|
| 791 | +EXPORT_SYMBOL(compat_ptr_ioctl); |
|---|
| 792 | + |
|---|
| 793 | +COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, |
|---|
| 794 | + compat_ulong_t, arg) |
|---|
| 795 | +{ |
|---|
| 796 | + struct fd f = fdget(fd); |
|---|
| 797 | + int error; |
|---|
| 798 | + |
|---|
| 799 | + if (!f.file) |
|---|
| 800 | + return -EBADF; |
|---|
| 801 | + |
|---|
| 802 | + /* RED-PEN how should LSM module know it's handling 32bit? */ |
|---|
| 803 | + error = security_file_ioctl(f.file, cmd, arg); |
|---|
| 804 | + if (error) |
|---|
| 805 | + goto out; |
|---|
| 806 | + |
|---|
| 807 | + switch (cmd) { |
|---|
| 808 | + /* FICLONE takes an int argument, so don't use compat_ptr() */ |
|---|
| 809 | + case FICLONE: |
|---|
| 810 | + error = ioctl_file_clone(f.file, arg, 0, 0, 0); |
|---|
| 811 | + break; |
|---|
| 812 | + |
|---|
| 813 | +#if defined(CONFIG_X86_64) |
|---|
| 814 | + /* these get messy on amd64 due to alignment differences */ |
|---|
| 815 | + case FS_IOC_RESVSP_32: |
|---|
| 816 | + case FS_IOC_RESVSP64_32: |
|---|
| 817 | + error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg)); |
|---|
| 818 | + break; |
|---|
| 819 | + case FS_IOC_UNRESVSP_32: |
|---|
| 820 | + case FS_IOC_UNRESVSP64_32: |
|---|
| 821 | + error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE, |
|---|
| 822 | + compat_ptr(arg)); |
|---|
| 823 | + break; |
|---|
| 824 | + case FS_IOC_ZERO_RANGE_32: |
|---|
| 825 | + error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE, |
|---|
| 826 | + compat_ptr(arg)); |
|---|
| 827 | + break; |
|---|
| 828 | +#endif |
|---|
| 829 | + |
|---|
| 830 | + /* |
|---|
| 831 | + * everything else in do_vfs_ioctl() takes either a compatible |
|---|
| 832 | + * pointer argument or no argument -- call it with a modified |
|---|
| 833 | + * argument. |
|---|
| 834 | + */ |
|---|
| 835 | + default: |
|---|
| 836 | + error = do_vfs_ioctl(f.file, fd, cmd, |
|---|
| 837 | + (unsigned long)compat_ptr(arg)); |
|---|
| 838 | + if (error != -ENOIOCTLCMD) |
|---|
| 839 | + break; |
|---|
| 840 | + |
|---|
| 841 | + if (f.file->f_op->compat_ioctl) |
|---|
| 842 | + error = f.file->f_op->compat_ioctl(f.file, cmd, arg); |
|---|
| 843 | + if (error == -ENOIOCTLCMD) |
|---|
| 844 | + error = -ENOTTY; |
|---|
| 845 | + break; |
|---|
| 846 | + } |
|---|
| 847 | + |
|---|
| 848 | + out: |
|---|
| 849 | + fdput(f); |
|---|
| 850 | + |
|---|
| 851 | + return error; |
|---|
| 852 | +} |
|---|
| 853 | +#endif |
|---|