.. | .. |
---|
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 |
---|