diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2008-02-23 04:53:53 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-19 06:42:18 -0400 |
| commit | f382d6e631fe424200ee0d8bb16539f5b7bef7be (patch) | |
| tree | 03692bc57fa9cce5d12ace0b57fc03c11b6fa72f | |
| parent | 1dd0dd111f1b7591f2848fffdb06044053f66c40 (diff) | |
[PATCH] sanitize hppfs
* hppfs_iget() and its users are racy; there's no need to pollute icache
anyway, new_inode() works fine and is safe, unlike the current kludges
(these relied on overwriting ->i_ino before another iget_locked() gets
to that one - and did it after unlocking).
* merge hppfs_iget()/init_inode()/hppfs_read_inode(), while we are
at it.
* to pass proper vfsmount to dentry_open() store the reference
in hppfs superblock.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
--
| -rw-r--r-- | fs/hppfs/hppfs_kern.c | 113 |
1 files changed, 34 insertions, 79 deletions
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index 0c0f62f5164f..8601d8ef3b55 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c | |||
| @@ -18,8 +18,7 @@ | |||
| 18 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
| 19 | #include "os.h" | 19 | #include "os.h" |
| 20 | 20 | ||
| 21 | static int init_inode(struct inode *inode, struct dentry *dentry, | 21 | static struct inode *get_inode(struct super_block *, struct dentry *); |
| 22 | struct vfsmount *mnt); | ||
| 23 | 22 | ||
| 24 | struct hppfs_data { | 23 | struct hppfs_data { |
| 25 | struct list_head list; | 24 | struct list_head list; |
| @@ -35,7 +34,6 @@ struct hppfs_private { | |||
| 35 | 34 | ||
| 36 | struct hppfs_inode_info { | 35 | struct hppfs_inode_info { |
| 37 | struct dentry *proc_dentry; | 36 | struct dentry *proc_dentry; |
| 38 | struct vfsmount *proc_mnt; | ||
| 39 | struct inode vfs_inode; | 37 | struct inode vfs_inode; |
| 40 | }; | 38 | }; |
| 41 | 39 | ||
| @@ -137,40 +135,6 @@ static int file_removed(struct dentry *dentry, const char *file) | |||
| 137 | return 0; | 135 | return 0; |
| 138 | } | 136 | } |
| 139 | 137 | ||
| 140 | static void hppfs_read_inode(struct inode *ino) | ||
| 141 | { | ||
| 142 | struct inode *proc_ino; | ||
| 143 | |||
| 144 | if (HPPFS_I(ino)->proc_dentry == NULL) | ||
| 145 | return; | ||
| 146 | |||
| 147 | proc_ino = HPPFS_I(ino)->proc_dentry->d_inode; | ||
| 148 | ino->i_uid = proc_ino->i_uid; | ||
| 149 | ino->i_gid = proc_ino->i_gid; | ||
| 150 | ino->i_atime = proc_ino->i_atime; | ||
| 151 | ino->i_mtime = proc_ino->i_mtime; | ||
| 152 | ino->i_ctime = proc_ino->i_ctime; | ||
| 153 | ino->i_ino = proc_ino->i_ino; | ||
| 154 | ino->i_mode = proc_ino->i_mode; | ||
| 155 | ino->i_nlink = proc_ino->i_nlink; | ||
| 156 | ino->i_size = proc_ino->i_size; | ||
| 157 | ino->i_blocks = proc_ino->i_blocks; | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct inode *hppfs_iget(struct super_block *sb) | ||
| 161 | { | ||
| 162 | struct inode *inode; | ||
| 163 | |||
| 164 | inode = iget_locked(sb, 0); | ||
| 165 | if (!inode) | ||
| 166 | return ERR_PTR(-ENOMEM); | ||
| 167 | if (inode->i_state & I_NEW) { | ||
| 168 | hppfs_read_inode(inode); | ||
| 169 | unlock_new_inode(inode); | ||
| 170 | } | ||
| 171 | return inode; | ||
| 172 | } | ||
| 173 | |||
| 174 | static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, | 138 | static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, |
| 175 | struct nameidata *nd) | 139 | struct nameidata *nd) |
| 176 | { | 140 | { |
| @@ -206,23 +170,14 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, | |||
| 206 | if (IS_ERR(proc_dentry)) | 170 | if (IS_ERR(proc_dentry)) |
| 207 | return proc_dentry; | 171 | return proc_dentry; |
| 208 | 172 | ||
| 209 | inode = hppfs_iget(ino->i_sb); | 173 | err = -ENOMEM; |
| 210 | if (IS_ERR(inode)) { | 174 | inode = get_inode(ino->i_sb, proc_dentry); |
| 211 | err = PTR_ERR(inode); | 175 | if (!inode) |
| 212 | goto out_dput; | 176 | goto out_dput; |
| 213 | } | ||
| 214 | |||
| 215 | err = init_inode(inode, proc_dentry, HPPFS_I(ino)->proc_mnt); | ||
| 216 | if (err) | ||
| 217 | goto out_put; | ||
| 218 | |||
| 219 | hppfs_read_inode(inode); | ||
| 220 | 177 | ||
| 221 | d_add(dentry, inode); | 178 | d_add(dentry, inode); |
| 222 | return NULL; | 179 | return NULL; |
| 223 | 180 | ||
| 224 | out_put: | ||
| 225 | iput(inode); | ||
| 226 | out_dput: | 181 | out_dput: |
| 227 | dput(proc_dentry); | 182 | dput(proc_dentry); |
| 228 | out: | 183 | out: |
| @@ -489,7 +444,7 @@ static int hppfs_open(struct inode *inode, struct file *file) | |||
| 489 | goto out_free2; | 444 | goto out_free2; |
| 490 | 445 | ||
| 491 | proc_dentry = HPPFS_I(inode)->proc_dentry; | 446 | proc_dentry = HPPFS_I(inode)->proc_dentry; |
| 492 | proc_mnt = HPPFS_I(inode)->proc_mnt; | 447 | proc_mnt = inode->i_sb->s_fs_info; |
| 493 | 448 | ||
| 494 | /* XXX This isn't closed anywhere */ | 449 | /* XXX This isn't closed anywhere */ |
| 495 | data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), | 450 | data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), |
| @@ -547,7 +502,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file) | |||
| 547 | goto out; | 502 | goto out; |
| 548 | 503 | ||
| 549 | proc_dentry = HPPFS_I(inode)->proc_dentry; | 504 | proc_dentry = HPPFS_I(inode)->proc_dentry; |
| 550 | proc_mnt = HPPFS_I(inode)->proc_mnt; | 505 | proc_mnt = inode->i_sb->s_fs_info; |
| 551 | data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), | 506 | data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), |
| 552 | file_mode(file->f_mode)); | 507 | file_mode(file->f_mode)); |
| 553 | err = PTR_ERR(data->proc_file); | 508 | err = PTR_ERR(data->proc_file); |
| @@ -659,7 +614,6 @@ static struct inode *hppfs_alloc_inode(struct super_block *sb) | |||
| 659 | return NULL; | 614 | return NULL; |
| 660 | 615 | ||
| 661 | hi->proc_dentry = NULL; | 616 | hi->proc_dentry = NULL; |
| 662 | hi->proc_mnt = NULL; | ||
| 663 | inode_init_once(&hi->vfs_inode); | 617 | inode_init_once(&hi->vfs_inode); |
| 664 | return &hi->vfs_inode; | 618 | return &hi->vfs_inode; |
| 665 | } | 619 | } |
| @@ -676,7 +630,7 @@ static void hppfs_destroy_inode(struct inode *inode) | |||
| 676 | 630 | ||
| 677 | static void hppfs_put_super(struct super_block *sb) | 631 | static void hppfs_put_super(struct super_block *sb) |
| 678 | { | 632 | { |
| 679 | mntput(HPPFS_I(sb->s_root->d_inode)->proc_mnt); | 633 | mntput(sb->s_fs_info); |
| 680 | } | 634 | } |
| 681 | 635 | ||
| 682 | static const struct super_operations hppfs_sbops = { | 636 | static const struct super_operations hppfs_sbops = { |
| @@ -696,7 +650,7 @@ static int hppfs_readlink(struct dentry *dentry, char __user *buffer, | |||
| 696 | int ret; | 650 | int ret; |
| 697 | 651 | ||
| 698 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; | 652 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; |
| 699 | proc_mnt = HPPFS_I(dentry->d_inode)->proc_mnt; | 653 | proc_mnt = dentry->d_sb->s_fs_info; |
| 700 | 654 | ||
| 701 | proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); | 655 | proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); |
| 702 | if (IS_ERR(proc_file)) | 656 | if (IS_ERR(proc_file)) |
| @@ -717,7 +671,7 @@ static void* hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 717 | void *ret; | 671 | void *ret; |
| 718 | 672 | ||
| 719 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; | 673 | proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; |
| 720 | proc_mnt = HPPFS_I(dentry->d_inode)->proc_mnt; | 674 | proc_mnt = dentry->d_sb->s_fs_info; |
| 721 | 675 | ||
| 722 | proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); | 676 | proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt), O_RDONLY); |
| 723 | if (IS_ERR(proc_file)) | 677 | if (IS_ERR(proc_file)) |
| @@ -739,9 +693,14 @@ static const struct inode_operations hppfs_link_iops = { | |||
| 739 | .follow_link = hppfs_follow_link, | 693 | .follow_link = hppfs_follow_link, |
| 740 | }; | 694 | }; |
| 741 | 695 | ||
| 742 | static int init_inode(struct inode *inode, struct dentry *dentry, | 696 | static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) |
| 743 | struct vfsmount *mnt) | ||
| 744 | { | 697 | { |
| 698 | struct inode *proc_ino = dentry->d_inode; | ||
| 699 | struct inode *inode = new_inode(sb); | ||
| 700 | |||
| 701 | if (!inode) | ||
| 702 | return ERR_PTR(-ENOMEM); | ||
| 703 | |||
| 745 | if (S_ISDIR(dentry->d_inode->i_mode)) { | 704 | if (S_ISDIR(dentry->d_inode->i_mode)) { |
| 746 | inode->i_op = &hppfs_dir_iops; | 705 | inode->i_op = &hppfs_dir_iops; |
| 747 | inode->i_fop = &hppfs_dir_fops; | 706 | inode->i_fop = &hppfs_dir_fops; |
| @@ -754,7 +713,17 @@ static int init_inode(struct inode *inode, struct dentry *dentry, | |||
| 754 | } | 713 | } |
| 755 | 714 | ||
| 756 | HPPFS_I(inode)->proc_dentry = dentry; | 715 | HPPFS_I(inode)->proc_dentry = dentry; |
| 757 | HPPFS_I(inode)->proc_mnt = mnt; | 716 | |
| 717 | inode->i_uid = proc_ino->i_uid; | ||
| 718 | inode->i_gid = proc_ino->i_gid; | ||
| 719 | inode->i_atime = proc_ino->i_atime; | ||
| 720 | inode->i_mtime = proc_ino->i_mtime; | ||
| 721 | inode->i_ctime = proc_ino->i_ctime; | ||
| 722 | inode->i_ino = proc_ino->i_ino; | ||
| 723 | inode->i_mode = proc_ino->i_mode; | ||
| 724 | inode->i_nlink = proc_ino->i_nlink; | ||
| 725 | inode->i_size = proc_ino->i_size; | ||
| 726 | inode->i_blocks = proc_ino->i_blocks; | ||
| 758 | 727 | ||
| 759 | return 0; | 728 | return 0; |
| 760 | } | 729 | } |
| @@ -762,17 +731,10 @@ static int init_inode(struct inode *inode, struct dentry *dentry, | |||
| 762 | static int hppfs_fill_super(struct super_block *sb, void *d, int silent) | 731 | static int hppfs_fill_super(struct super_block *sb, void *d, int silent) |
| 763 | { | 732 | { |
| 764 | struct inode *root_inode; | 733 | struct inode *root_inode; |
| 765 | struct file_system_type *procfs; | ||
| 766 | struct vfsmount *proc_mnt; | 734 | struct vfsmount *proc_mnt; |
| 767 | int err; | 735 | int err = -ENOENT; |
| 768 | 736 | ||
| 769 | err = -ENOENT; | 737 | proc_mnt = do_kern_mount("proc", 0, "proc", NULL); |
| 770 | procfs = get_fs_type("proc"); | ||
| 771 | if (!procfs) | ||
| 772 | goto out; | ||
| 773 | |||
| 774 | proc_mnt = vfs_kern_mount(procfs, 0, procfs->name, NULL); | ||
| 775 | put_filesystem(procfs); | ||
| 776 | if (IS_ERR(proc_mnt)) | 738 | if (IS_ERR(proc_mnt)) |
| 777 | goto out; | 739 | goto out; |
| 778 | 740 | ||
| @@ -780,24 +742,17 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) | |||
| 780 | sb->s_blocksize_bits = 10; | 742 | sb->s_blocksize_bits = 10; |
| 781 | sb->s_magic = HPPFS_SUPER_MAGIC; | 743 | sb->s_magic = HPPFS_SUPER_MAGIC; |
| 782 | sb->s_op = &hppfs_sbops; | 744 | sb->s_op = &hppfs_sbops; |
| 783 | 745 | sb->s_fs_info = proc_mnt; | |
| 784 | root_inode = hppfs_iget(sb); | ||
| 785 | if (IS_ERR(root_inode)) { | ||
| 786 | err = PTR_ERR(root_inode); | ||
| 787 | goto out; | ||
| 788 | } | ||
| 789 | |||
| 790 | err = init_inode(root_inode, proc_mnt->mnt_sb->s_root, proc_mnt); | ||
| 791 | if (err) | ||
| 792 | goto out_iput; | ||
| 793 | 746 | ||
| 794 | err = -ENOMEM; | 747 | err = -ENOMEM; |
| 748 | root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); | ||
| 749 | if (!root_inode) | ||
| 750 | goto out_mntput; | ||
| 751 | |||
| 795 | sb->s_root = d_alloc_root(root_inode); | 752 | sb->s_root = d_alloc_root(root_inode); |
| 796 | if (!sb->s_root) | 753 | if (!sb->s_root) |
| 797 | goto out_iput; | 754 | goto out_iput; |
| 798 | 755 | ||
| 799 | hppfs_read_inode(root_inode); | ||
| 800 | |||
| 801 | return 0; | 756 | return 0; |
| 802 | 757 | ||
| 803 | out_iput: | 758 | out_iput: |
