mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
![]() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Michal Nazarewicz <mina86@mina86.com> Cc: stable <stable@vger.kernel.org> # 3.3+ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
||
---|---|---|
.. | ||
acm_ms.c | ||
amd5536udc.c | ||
amd5536udc.h | ||
at91_udc.c | ||
at91_udc.h | ||
atmel_usba_udc.c | ||
atmel_usba_udc.h | ||
audio.c | ||
bcm63xx_udc.c | ||
cdc2.c | ||
composite.c | ||
config.c | ||
configfs.c | ||
dbgp.c | ||
dummy_hcd.c | ||
epautoconf.c | ||
ether.c | ||
f_acm.c | ||
f_ecm.c | ||
f_eem.c | ||
f_fs.c | ||
f_hid.c | ||
f_loopback.c | ||
f_mass_storage.c | ||
f_midi.c | ||
f_ncm.c | ||
f_obex.c | ||
f_phonet.c | ||
f_rndis.c | ||
f_serial.c | ||
f_sourcesink.c | ||
f_subset.c | ||
f_uac1.c | ||
f_uac2.c | ||
f_uvc.c | ||
f_uvc.h | ||
fotg210-udc.c | ||
fotg210.h | ||
fsl_mxc_udc.c | ||
fsl_qe_udc.c | ||
fsl_qe_udc.h | ||
fsl_udc_core.c | ||
fsl_usb2_udc.h | ||
functions.c | ||
fusb300_udc.c | ||
fusb300_udc.h | ||
g_ffs.c | ||
g_zero.h | ||
gadget_chips.h | ||
gmidi.c | ||
goku_udc.c | ||
goku_udc.h | ||
hid.c | ||
inode.c | ||
Kconfig | ||
lpc32xx_udc.c | ||
m66592-udc.c | ||
m66592-udc.h | ||
Makefile | ||
mass_storage.c | ||
multi.c | ||
mv_u3d.h | ||
mv_u3d_core.c | ||
mv_udc.h | ||
mv_udc_core.c | ||
ncm.c | ||
ndis.h | ||
net2272.c | ||
net2272.h | ||
net2280.c | ||
net2280.h | ||
nokia.c | ||
omap_udc.c | ||
omap_udc.h | ||
pch_udc.c | ||
printer.c | ||
pxa25x_udc.c | ||
pxa25x_udc.h | ||
pxa27x_udc.c | ||
pxa27x_udc.h | ||
r8a66597-udc.c | ||
r8a66597-udc.h | ||
rndis.c | ||
rndis.h | ||
s3c-hsotg.c | ||
s3c-hsotg.h | ||
s3c-hsudc.c | ||
s3c2410_udc.c | ||
s3c2410_udc.h | ||
serial.c | ||
storage_common.c | ||
tcm_usb_gadget.c | ||
tcm_usb_gadget.h | ||
u_ecm.h | ||
u_eem.h | ||
u_ether.c | ||
u_ether.h | ||
u_ether_configfs.h | ||
u_gether.h | ||
u_ncm.h | ||
u_phonet.h | ||
u_rndis.h | ||
u_serial.c | ||
u_serial.h | ||
u_uac1.c | ||
u_uac1.h | ||
udc-core.c | ||
usbstring.c | ||
uvc.h | ||
uvc_queue.c | ||
uvc_queue.h | ||
uvc_v4l2.c | ||
uvc_video.c | ||
webcam.c | ||
zero.c |