diff options
author | Christoph Hellwig <hch@lst.de> | 2007-05-08 03:29:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:15:09 -0400 |
commit | 6272e2667965dfb5b59199f462cd0f001fb304a6 (patch) | |
tree | a14a4537dcd7af09863cc3a1c19a3efe386d67ab /fs | |
parent | 039b6b3ed84e45a6f8316358dd2bfdc83d59fc45 (diff) |
cleanup compat ioctl handling
Merge all compat ioctl handling into compat_ioctl.c instead of splitting it
over compat.c and compat_ioctl.c. This also allows to get rid of ioctl32.h
Signed-off-by: Christoph Hellwig <hch@lst.de>
Looks-good-to: Andi Kleen <ak@suse.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat.c | 162 | ||||
-rw-r--r-- | fs/compat_ioctl.c | 170 | ||||
-rw-r--r-- | fs/internal.h | 10 |
3 files changed, 166 insertions, 176 deletions
diff --git a/fs/compat.c b/fs/compat.c index a32e2ae737fb..9f6248dfd9d9 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -25,10 +25,8 @@ | |||
25 | #include <linux/namei.h> | 25 | #include <linux/namei.h> |
26 | #include <linux/file.h> | 26 | #include <linux/file.h> |
27 | #include <linux/vfs.h> | 27 | #include <linux/vfs.h> |
28 | #include <linux/ioctl32.h> | ||
29 | #include <linux/ioctl.h> | 28 | #include <linux/ioctl.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
31 | #include <linux/sockios.h> /* for SIOCDEVPRIVATE */ | ||
32 | #include <linux/smb.h> | 30 | #include <linux/smb.h> |
33 | #include <linux/smb_mount.h> | 31 | #include <linux/smb_mount.h> |
34 | #include <linux/ncp_mount.h> | 32 | #include <linux/ncp_mount.h> |
@@ -46,13 +44,12 @@ | |||
46 | #include <linux/personality.h> | 44 | #include <linux/personality.h> |
47 | #include <linux/rwsem.h> | 45 | #include <linux/rwsem.h> |
48 | #include <linux/tsacct_kern.h> | 46 | #include <linux/tsacct_kern.h> |
47 | #include <linux/security.h> | ||
49 | #include <linux/highmem.h> | 48 | #include <linux/highmem.h> |
50 | #include <linux/poll.h> | 49 | #include <linux/poll.h> |
51 | #include <linux/mm.h> | 50 | #include <linux/mm.h> |
52 | #include <linux/eventpoll.h> | 51 | #include <linux/eventpoll.h> |
53 | 52 | ||
54 | #include <net/sock.h> /* siocdevprivate_ioctl */ | ||
55 | |||
56 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
57 | #include <asm/mmu_context.h> | 54 | #include <asm/mmu_context.h> |
58 | #include <asm/ioctls.h> | 55 | #include <asm/ioctls.h> |
@@ -313,163 +310,6 @@ out: | |||
313 | return error; | 310 | return error; |
314 | } | 311 | } |
315 | 312 | ||
316 | /* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */ | ||
317 | |||
318 | #define IOCTL_HASHSIZE 256 | ||
319 | static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; | ||
320 | |||
321 | static inline unsigned long ioctl32_hash(unsigned long cmd) | ||
322 | { | ||
323 | return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE; | ||
324 | } | ||
325 | |||
326 | static void ioctl32_insert_translation(struct ioctl_trans *trans) | ||
327 | { | ||
328 | unsigned long hash; | ||
329 | struct ioctl_trans *t; | ||
330 | |||
331 | hash = ioctl32_hash (trans->cmd); | ||
332 | if (!ioctl32_hash_table[hash]) | ||
333 | ioctl32_hash_table[hash] = trans; | ||
334 | else { | ||
335 | t = ioctl32_hash_table[hash]; | ||
336 | while (t->next) | ||
337 | t = t->next; | ||
338 | trans->next = NULL; | ||
339 | t->next = trans; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static int __init init_sys32_ioctl(void) | ||
344 | { | ||
345 | int i; | ||
346 | |||
347 | for (i = 0; i < ioctl_table_size; i++) { | ||
348 | if (ioctl_start[i].next != 0) { | ||
349 | printk("ioctl translation %d bad\n",i); | ||
350 | return -1; | ||
351 | } | ||
352 | |||
353 | ioctl32_insert_translation(&ioctl_start[i]); | ||
354 | } | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | __initcall(init_sys32_ioctl); | ||
359 | |||
360 | static void compat_ioctl_error(struct file *filp, unsigned int fd, | ||
361 | unsigned int cmd, unsigned long arg) | ||
362 | { | ||
363 | char buf[10]; | ||
364 | char *fn = "?"; | ||
365 | char *path; | ||
366 | |||
367 | /* find the name of the device. */ | ||
368 | path = (char *)__get_free_page(GFP_KERNEL); | ||
369 | if (path) { | ||
370 | fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE); | ||
371 | if (IS_ERR(fn)) | ||
372 | fn = "?"; | ||
373 | } | ||
374 | |||
375 | sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK); | ||
376 | if (!isprint(buf[1])) | ||
377 | sprintf(buf, "%02x", buf[1]); | ||
378 | compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) " | ||
379 | "cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n", | ||
380 | current->comm, current->pid, | ||
381 | (int)fd, (unsigned int)cmd, buf, | ||
382 | (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK, | ||
383 | (unsigned int)arg, fn); | ||
384 | |||
385 | if (path) | ||
386 | free_page((unsigned long)path); | ||
387 | } | ||
388 | |||
389 | asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | ||
390 | unsigned long arg) | ||
391 | { | ||
392 | struct file *filp; | ||
393 | int error = -EBADF; | ||
394 | struct ioctl_trans *t; | ||
395 | int fput_needed; | ||
396 | |||
397 | filp = fget_light(fd, &fput_needed); | ||
398 | if (!filp) | ||
399 | goto out; | ||
400 | |||
401 | /* RED-PEN how should LSM module know it's handling 32bit? */ | ||
402 | error = security_file_ioctl(filp, cmd, arg); | ||
403 | if (error) | ||
404 | goto out_fput; | ||
405 | |||
406 | /* | ||
407 | * To allow the compat_ioctl handlers to be self contained | ||
408 | * we need to check the common ioctls here first. | ||
409 | * Just handle them with the standard handlers below. | ||
410 | */ | ||
411 | switch (cmd) { | ||
412 | case FIOCLEX: | ||
413 | case FIONCLEX: | ||
414 | case FIONBIO: | ||
415 | case FIOASYNC: | ||
416 | case FIOQSIZE: | ||
417 | break; | ||
418 | |||
419 | case FIBMAP: | ||
420 | case FIGETBSZ: | ||
421 | case FIONREAD: | ||
422 | if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) | ||
423 | break; | ||
424 | /*FALL THROUGH*/ | ||
425 | |||
426 | default: | ||
427 | if (filp->f_op && filp->f_op->compat_ioctl) { | ||
428 | error = filp->f_op->compat_ioctl(filp, cmd, arg); | ||
429 | if (error != -ENOIOCTLCMD) | ||
430 | goto out_fput; | ||
431 | } | ||
432 | |||
433 | if (!filp->f_op || | ||
434 | (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) | ||
435 | goto do_ioctl; | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { | ||
440 | if (t->cmd == cmd) | ||
441 | goto found_handler; | ||
442 | } | ||
443 | |||
444 | if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && | ||
445 | cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { | ||
446 | error = siocdevprivate_ioctl(fd, cmd, arg); | ||
447 | } else { | ||
448 | static int count; | ||
449 | |||
450 | if (++count <= 50) | ||
451 | compat_ioctl_error(filp, fd, cmd, arg); | ||
452 | error = -EINVAL; | ||
453 | } | ||
454 | |||
455 | goto out_fput; | ||
456 | |||
457 | found_handler: | ||
458 | if (t->handler) { | ||
459 | lock_kernel(); | ||
460 | error = t->handler(fd, cmd, arg, filp); | ||
461 | unlock_kernel(); | ||
462 | goto out_fput; | ||
463 | } | ||
464 | |||
465 | do_ioctl: | ||
466 | error = vfs_ioctl(filp, fd, cmd, arg); | ||
467 | out_fput: | ||
468 | fput_light(filp, fput_needed); | ||
469 | out: | ||
470 | return error; | ||
471 | } | ||
472 | |||
473 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | 313 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) |
474 | { | 314 | { |
475 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | 315 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a0c3d2044e84..6972d242fbdf 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -57,7 +57,6 @@ | |||
57 | #include <linux/serial.h> | 57 | #include <linux/serial.h> |
58 | #include <linux/if_tun.h> | 58 | #include <linux/if_tun.h> |
59 | #include <linux/ctype.h> | 59 | #include <linux/ctype.h> |
60 | #include <linux/ioctl32.h> | ||
61 | #include <linux/syscalls.h> | 60 | #include <linux/syscalls.h> |
62 | #include <linux/i2c.h> | 61 | #include <linux/i2c.h> |
63 | #include <linux/i2c-dev.h> | 62 | #include <linux/i2c-dev.h> |
@@ -65,7 +64,6 @@ | |||
65 | #include <linux/atalk.h> | 64 | #include <linux/atalk.h> |
66 | #include <linux/blktrace_api.h> | 65 | #include <linux/blktrace_api.h> |
67 | 66 | ||
68 | #include <net/sock.h> /* siocdevprivate_ioctl */ | ||
69 | #include <net/bluetooth/bluetooth.h> | 67 | #include <net/bluetooth/bluetooth.h> |
70 | #include <net/bluetooth/hci.h> | 68 | #include <net/bluetooth/hci.h> |
71 | #include <net/bluetooth/rfcomm.h> | 69 | #include <net/bluetooth/rfcomm.h> |
@@ -474,7 +472,7 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
474 | }; | 472 | }; |
475 | } | 473 | } |
476 | 474 | ||
477 | int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | 475 | static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
478 | { | 476 | { |
479 | struct ifreq __user *u_ifreq64; | 477 | struct ifreq __user *u_ifreq64; |
480 | struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); | 478 | struct ifreq32 __user *u_ifreq32 = compat_ptr(arg); |
@@ -2384,6 +2382,16 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
2384 | return sys_ioctl(fd, cmd, (unsigned long)tn); | 2382 | return sys_ioctl(fd, cmd, (unsigned long)tn); |
2385 | } | 2383 | } |
2386 | 2384 | ||
2385 | |||
2386 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, | ||
2387 | unsigned long, struct file *); | ||
2388 | |||
2389 | struct ioctl_trans { | ||
2390 | unsigned long cmd; | ||
2391 | ioctl_trans_handler_t handler; | ||
2392 | struct ioctl_trans *next; | ||
2393 | }; | ||
2394 | |||
2387 | #define HANDLE_IOCTL(cmd,handler) \ | 2395 | #define HANDLE_IOCTL(cmd,handler) \ |
2388 | { (cmd), (ioctl_trans_handler_t)(handler) }, | 2396 | { (cmd), (ioctl_trans_handler_t)(handler) }, |
2389 | 2397 | ||
@@ -2404,7 +2412,7 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
2404 | Most other reasons are not valid. */ | 2412 | Most other reasons are not valid. */ |
2405 | #define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd) | 2413 | #define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd) |
2406 | 2414 | ||
2407 | struct ioctl_trans ioctl_start[] = { | 2415 | static struct ioctl_trans ioctl_start[] = { |
2408 | /* compatible ioctls first */ | 2416 | /* compatible ioctls first */ |
2409 | COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ | 2417 | COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */ |
2410 | COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ | 2418 | COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */ |
@@ -3464,4 +3472,156 @@ IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32) | |||
3464 | IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) | 3472 | IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) |
3465 | }; | 3473 | }; |
3466 | 3474 | ||
3467 | int ioctl_table_size = ARRAY_SIZE(ioctl_start); | 3475 | #define IOCTL_HASHSIZE 256 |
3476 | static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; | ||
3477 | |||
3478 | static inline unsigned long ioctl32_hash(unsigned long cmd) | ||
3479 | { | ||
3480 | return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE; | ||
3481 | } | ||
3482 | |||
3483 | static void compat_ioctl_error(struct file *filp, unsigned int fd, | ||
3484 | unsigned int cmd, unsigned long arg) | ||
3485 | { | ||
3486 | char buf[10]; | ||
3487 | char *fn = "?"; | ||
3488 | char *path; | ||
3489 | |||
3490 | /* find the name of the device. */ | ||
3491 | path = (char *)__get_free_page(GFP_KERNEL); | ||
3492 | if (path) { | ||
3493 | fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE); | ||
3494 | if (IS_ERR(fn)) | ||
3495 | fn = "?"; | ||
3496 | } | ||
3497 | |||
3498 | sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK); | ||
3499 | if (!isprint(buf[1])) | ||
3500 | sprintf(buf, "%02x", buf[1]); | ||
3501 | compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) " | ||
3502 | "cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n", | ||
3503 | current->comm, current->pid, | ||
3504 | (int)fd, (unsigned int)cmd, buf, | ||
3505 | (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK, | ||
3506 | (unsigned int)arg, fn); | ||
3507 | |||
3508 | if (path) | ||
3509 | free_page((unsigned long)path); | ||
3510 | } | ||
3511 | |||
3512 | asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | ||
3513 | unsigned long arg) | ||
3514 | { | ||
3515 | struct file *filp; | ||
3516 | int error = -EBADF; | ||
3517 | struct ioctl_trans *t; | ||
3518 | int fput_needed; | ||
3519 | |||
3520 | filp = fget_light(fd, &fput_needed); | ||
3521 | if (!filp) | ||
3522 | goto out; | ||
3523 | |||
3524 | /* RED-PEN how should LSM module know it's handling 32bit? */ | ||
3525 | error = security_file_ioctl(filp, cmd, arg); | ||
3526 | if (error) | ||
3527 | goto out_fput; | ||
3528 | |||
3529 | /* | ||
3530 | * To allow the compat_ioctl handlers to be self contained | ||
3531 | * we need to check the common ioctls here first. | ||
3532 | * Just handle them with the standard handlers below. | ||
3533 | */ | ||
3534 | switch (cmd) { | ||
3535 | case FIOCLEX: | ||
3536 | case FIONCLEX: | ||
3537 | case FIONBIO: | ||
3538 | case FIOASYNC: | ||
3539 | case FIOQSIZE: | ||
3540 | break; | ||
3541 | |||
3542 | case FIBMAP: | ||
3543 | case FIGETBSZ: | ||
3544 | case FIONREAD: | ||
3545 | if (S_ISREG(filp->f_path.dentry->d_inode->i_mode)) | ||
3546 | break; | ||
3547 | /*FALL THROUGH*/ | ||
3548 | |||
3549 | default: | ||
3550 | if (filp->f_op && filp->f_op->compat_ioctl) { | ||
3551 | error = filp->f_op->compat_ioctl(filp, cmd, arg); | ||
3552 | if (error != -ENOIOCTLCMD) | ||
3553 | goto out_fput; | ||
3554 | } | ||
3555 | |||
3556 | if (!filp->f_op || | ||
3557 | (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) | ||
3558 | goto do_ioctl; | ||
3559 | break; | ||
3560 | } | ||
3561 | |||
3562 | for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { | ||
3563 | if (t->cmd == cmd) | ||
3564 | goto found_handler; | ||
3565 | } | ||
3566 | |||
3567 | if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) && | ||
3568 | cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { | ||
3569 | error = siocdevprivate_ioctl(fd, cmd, arg); | ||
3570 | } else { | ||
3571 | static int count; | ||
3572 | |||
3573 | if (++count <= 50) | ||
3574 | compat_ioctl_error(filp, fd, cmd, arg); | ||
3575 | error = -EINVAL; | ||
3576 | } | ||
3577 | |||
3578 | goto out_fput; | ||
3579 | |||
3580 | found_handler: | ||
3581 | if (t->handler) { | ||
3582 | lock_kernel(); | ||
3583 | error = t->handler(fd, cmd, arg, filp); | ||
3584 | unlock_kernel(); | ||
3585 | goto out_fput; | ||
3586 | } | ||
3587 | |||
3588 | do_ioctl: | ||
3589 | error = vfs_ioctl(filp, fd, cmd, arg); | ||
3590 | out_fput: | ||
3591 | fput_light(filp, fput_needed); | ||
3592 | out: | ||
3593 | return error; | ||
3594 | } | ||
3595 | |||
3596 | static void ioctl32_insert_translation(struct ioctl_trans *trans) | ||
3597 | { | ||
3598 | unsigned long hash; | ||
3599 | struct ioctl_trans *t; | ||
3600 | |||
3601 | hash = ioctl32_hash (trans->cmd); | ||
3602 | if (!ioctl32_hash_table[hash]) | ||
3603 | ioctl32_hash_table[hash] = trans; | ||
3604 | else { | ||
3605 | t = ioctl32_hash_table[hash]; | ||
3606 | while (t->next) | ||
3607 | t = t->next; | ||
3608 | trans->next = NULL; | ||
3609 | t->next = trans; | ||
3610 | } | ||
3611 | } | ||
3612 | |||
3613 | static int __init init_sys32_ioctl(void) | ||
3614 | { | ||
3615 | int i; | ||
3616 | |||
3617 | for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) { | ||
3618 | if (ioctl_start[i].next != 0) { | ||
3619 | printk("ioctl translation %d bad\n",i); | ||
3620 | return -1; | ||
3621 | } | ||
3622 | |||
3623 | ioctl32_insert_translation(&ioctl_start[i]); | ||
3624 | } | ||
3625 | return 0; | ||
3626 | } | ||
3627 | __initcall(init_sys32_ioctl); | ||
diff --git a/fs/internal.h b/fs/internal.h index ea00126c9a59..392e8ccd6fc4 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -9,8 +9,6 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/ioctl32.h> | ||
13 | |||
14 | struct super_block; | 12 | struct super_block; |
15 | 13 | ||
16 | /* | 14 | /* |
@@ -42,14 +40,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb) | |||
42 | extern void __init chrdev_init(void); | 40 | extern void __init chrdev_init(void); |
43 | 41 | ||
44 | /* | 42 | /* |
45 | * compat_ioctl.c | ||
46 | */ | ||
47 | #ifdef CONFIG_COMPAT | ||
48 | extern struct ioctl_trans ioctl_start[]; | ||
49 | extern int ioctl_table_size; | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | * namespace.c | 43 | * namespace.c |
54 | */ | 44 | */ |
55 | extern int copy_mount_options(const void __user *, unsigned long *); | 45 | extern int copy_mount_options(const void __user *, unsigned long *); |