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

ubifs: fix sget races

* allocate ubifs_info in ->mount(), fill it enough for sb_test() and
set ->s_fs_info to it in set() callback passed to sget().
* do *not* free it in ->put_super(); do that in ->kill_sb() after we'd
done kill_anon_super().
* don't free it in ubifs_fill_super() either - deactivate_locked_super()
done by caller when ubifs_fill_super() returns an error will take care
of that sucker.
* get rid of kludge with passing ubi to ubifs_fill_super() in ->s_fs_info;
we only need it in alloc_ubifs_info(), so ubifs_fill_super() will need
only ubifs_info. Which it will find in ->s_fs_info just fine, no need to
reassign anything...

As the result, sb_test() becomes safe to apply to all superblocks that
can be found by sget() (and a kludge with temporary use of ->s_fs_info
to store a pointer to very different structure goes away).

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro d251ed27 b1c27ab3

+30 -24
+30 -24
fs/ubifs/super.c
··· 1848 1848 bdi_destroy(&c->bdi); 1849 1849 ubi_close_volume(c->ubi); 1850 1850 mutex_unlock(&c->umount_mutex); 1851 - kfree(c); 1852 1851 } 1853 1852 1854 1853 static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) ··· 2019 2020 2020 2021 static int ubifs_fill_super(struct super_block *sb, void *data, int silent) 2021 2022 { 2022 - struct ubi_volume_desc *ubi = sb->s_fs_info; 2023 - struct ubifs_info *c; 2023 + struct ubifs_info *c = sb->s_fs_info; 2024 2024 struct inode *root; 2025 2025 int err; 2026 - 2027 - c = alloc_ubifs_info(ubi); 2028 - if (!c) 2029 - return -ENOMEM; 2030 2026 2031 2027 c->vfs_sb = sb; 2032 2028 /* Re-open the UBI device in read-write mode */ 2033 2029 c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); 2034 2030 if (IS_ERR(c->ubi)) { 2035 2031 err = PTR_ERR(c->ubi); 2036 - goto out_free; 2032 + goto out; 2037 2033 } 2038 2034 2039 2035 /* ··· 2094 2100 bdi_destroy(&c->bdi); 2095 2101 out_close: 2096 2102 ubi_close_volume(c->ubi); 2097 - out_free: 2098 - kfree(c); 2103 + out: 2099 2104 return err; 2100 2105 } 2101 2106 2102 2107 static int sb_test(struct super_block *sb, void *data) 2103 2108 { 2104 - dev_t *dev = data; 2109 + struct ubifs_info *c1 = data; 2105 2110 struct ubifs_info *c = sb->s_fs_info; 2106 2111 2107 - return c->vi.cdev == *dev; 2112 + return c->vi.cdev == c1->vi.cdev; 2113 + } 2114 + 2115 + static int sb_set(struct super_block *sb, void *data) 2116 + { 2117 + sb->s_fs_info = data; 2118 + return set_anon_super(sb, NULL); 2108 2119 } 2109 2120 2110 2121 static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, 2111 2122 const char *name, void *data) 2112 2123 { 2113 2124 struct ubi_volume_desc *ubi; 2114 - struct ubi_volume_info vi; 2125 + struct ubifs_info *c; 2115 2126 struct super_block *sb; 2116 2127 int err; 2117 2128 ··· 2133 2134 name, (int)PTR_ERR(ubi)); 2134 2135 return ERR_CAST(ubi); 2135 2136 } 2136 - ubi_get_volume_info(ubi, &vi); 2137 2137 2138 - dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); 2138 + c = alloc_ubifs_info(ubi); 2139 + if (!c) { 2140 + err = -ENOMEM; 2141 + goto out_close; 2142 + } 2139 2143 2140 - sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); 2144 + dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); 2145 + 2146 + sb = sget(fs_type, sb_test, sb_set, c); 2141 2147 if (IS_ERR(sb)) { 2142 2148 err = PTR_ERR(sb); 2143 - goto out_close; 2149 + kfree(c); 2144 2150 } 2145 2151 2146 2152 if (sb->s_root) { 2147 2153 struct ubifs_info *c1 = sb->s_fs_info; 2148 - 2154 + kfree(c); 2149 2155 /* A new mount point for already mounted UBIFS */ 2150 2156 dbg_gen("this ubi volume is already mounted"); 2151 2157 if (!!(flags & MS_RDONLY) != c1->ro_mount) { ··· 2159 2155 } 2160 2156 } else { 2161 2157 sb->s_flags = flags; 2162 - /* 2163 - * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is 2164 - * replaced by 'c'. 2165 - */ 2166 - sb->s_fs_info = ubi; 2167 2158 err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); 2168 2159 if (err) 2169 2160 goto out_deact; ··· 2178 2179 return ERR_PTR(err); 2179 2180 } 2180 2181 2182 + static void kill_ubifs_super(struct super_block *s) 2183 + { 2184 + struct ubifs_info *c = s->s_fs_info; 2185 + kill_anon_super(s); 2186 + kfree(c); 2187 + } 2188 + 2181 2189 static struct file_system_type ubifs_fs_type = { 2182 2190 .name = "ubifs", 2183 2191 .owner = THIS_MODULE, 2184 2192 .mount = ubifs_mount, 2185 - .kill_sb = kill_anon_super, 2193 + .kill_sb = kill_ubifs_super, 2186 2194 }; 2187 2195 2188 2196 /*