From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>,
Michal Nazarewicz <mina86@mina86.com>
Subject: [ 32/52] USB: Fix breakage in ffs_fs_mount()
Date: Wed, 2 Oct 2013 21:05:50 -0700 [thread overview]
Message-ID: <20131003040524.365367001@linuxfoundation.org> (raw)
In-Reply-To: <20131003040522.190209641@linuxfoundation.org>
3.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <viro@ZenIV.linux.org.uk>
commit 2606b28aabd7dea1766c23a105e1124c95409c96 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/usb/gadget/f_fs.c | 60 +++++++++++++++++++---------------------------
1 file changed, 26 insertions(+), 34 deletions(-)
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1034,37 +1034,19 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
- union {
- /* set by ffs_fs_mount(), read by ffs_sb_fill() */
- void *private_data;
- /* set by ffs_sb_fill(), read by ffs_fs_mount */
- struct ffs_data *ffs_data;
- };
+ struct ffs_data *ffs_data;
};
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
{
struct ffs_sb_fill_data *data = _data;
struct inode *inode;
- struct ffs_data *ffs;
+ struct ffs_data *ffs = data->ffs_data;
ENTER();
- /* Initialise data */
- ffs = ffs_data_new();
- if (unlikely(!ffs))
- goto Enomem;
-
ffs->sb = sb;
- ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL);
- if (unlikely(!ffs->dev_name))
- goto Enomem;
- ffs->file_perms = data->perms;
- ffs->private_data = data->private_data;
-
- /* used by the caller of this function */
- data->ffs_data = ffs;
-
+ data->ffs_data = NULL;
sb->s_fs_info = ffs;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1080,17 +1062,14 @@ static int ffs_sb_fill(struct super_bloc
&data->perms);
sb->s_root = d_make_root(inode);
if (unlikely(!sb->s_root))
- goto Enomem;
+ return -ENOMEM;
/* EP0 file */
if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
&ffs_ep0_operations, NULL)))
- goto Enomem;
+ return -ENOMEM;
return 0;
-
-Enomem:
- return -ENOMEM;
}
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
@@ -1193,6 +1172,7 @@ ffs_fs_mount(struct file_system_type *t,
struct dentry *rv;
int ret;
void *ffs_dev;
+ struct ffs_data *ffs;
ENTER();
@@ -1200,18 +1180,30 @@ ffs_fs_mount(struct file_system_type *t,
if (unlikely(ret < 0))
return ERR_PTR(ret);
+ ffs = ffs_data_new();
+ if (unlikely(!ffs))
+ return ERR_PTR(-ENOMEM);
+ ffs->file_perms = data.perms;
+
+ ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
+ if (unlikely(!ffs->dev_name)) {
+ ffs_data_put(ffs);
+ return ERR_PTR(-ENOMEM);
+ }
+
ffs_dev = functionfs_acquire_dev_callback(dev_name);
- if (IS_ERR(ffs_dev))
- return ffs_dev;
+ if (IS_ERR(ffs_dev)) {
+ ffs_data_put(ffs);
+ return ERR_CAST(ffs_dev);
+ }
+ ffs->private_data = ffs_dev;
+ data.ffs_data = ffs;
- data.dev_name = dev_name;
- data.private_data = ffs_dev;
rv = mount_nodev(t, flags, &data, ffs_sb_fill);
-
- /* data.ffs_data is set by ffs_sb_fill */
- if (IS_ERR(rv))
+ if (IS_ERR(rv) && data.ffs_data) {
functionfs_release_dev_callback(data.ffs_data);
-
+ ffs_data_put(data.ffs_data);
+ }
return rv;
}
next prev parent reply other threads:[~2013-10-03 4:16 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-03 4:05 [ 00/52] 3.10.15-stable review Greg Kroah-Hartman
2013-10-03 4:05 ` [ 01/52] block: Fix bio_copy_data() Greg Kroah-Hartman
2013-10-03 4:05 ` [ 02/52] sysv: Add forgotten superblock lock init for v7 fs Greg Kroah-Hartman
2013-10-03 4:05 ` [ 03/52] bcache: Fix a dumb journal discard bug Greg Kroah-Hartman
2013-10-03 4:05 ` [ 04/52] bcache: Strip endline when writing the label through sysfs Greg Kroah-Hartman
2013-10-03 4:05 ` [ 05/52] bcache: Fix for when no journal entries are found Greg Kroah-Hartman
2013-10-03 4:05 ` [ 06/52] bcache: Fix a writeback performance regression Greg Kroah-Hartman
2013-10-03 4:05 ` [ 07/52] bcache: Fix a flush/fua performance bug Greg Kroah-Hartman
2013-10-03 4:05 ` [ 08/52] bcache: Fix a dumb CPU spinning bug in writeback Greg Kroah-Hartman
2013-10-03 4:05 ` [ 09/52] bcache: Fix a shrinker deadlock Greg Kroah-Hartman
2013-10-03 4:05 ` [ 10/52] bcache: Fix for handling overlapping extents when reading in a btree node Greg Kroah-Hartman
2013-10-03 4:05 ` [ 11/52] bcache: Fix flushes in writeback mode Greg Kroah-Hartman
2013-10-03 4:05 ` [ 12/52] x86/reboot: Add quirk to make Dell C6100 use reboot=pci automatically Greg Kroah-Hartman
2013-10-03 4:05 ` [ 13/52] tools lib lk: Uninclude linux/magic.h in debugfs.c Greg Kroah-Hartman
2013-10-03 4:05 ` [ 14/52] x86, efi: Dont map Boot Services on i386 Greg Kroah-Hartman
2013-10-03 4:05 ` [ 15/52] mei: make me client counters less error prone Greg Kroah-Hartman
2013-10-03 4:05 ` [ 16/52] mei: bus: stop wait for read during cl state transition Greg Kroah-Hartman
2013-10-03 4:05 ` [ 17/52] mei: cancel stall timers in mei_reset Greg Kroah-Hartman
2013-10-03 4:05 ` [ 18/52] tty: Fix SIGTTOU not sent with tcflush() Greg Kroah-Hartman
2013-10-03 4:05 ` [ 19/52] serial: tegra: fix tty-kref leak Greg Kroah-Hartman
2013-10-03 4:05 ` [ 20/52] serial: pch_uart: fix tty-kref leak in rx-error path Greg Kroah-Hartman
2013-10-03 4:05 ` [ 21/52] serial: pch_uart: fix tty-kref leak in dma-rx path Greg Kroah-Hartman
2013-10-03 4:05 ` [ 22/52] ARM: 7837/3: fix Thumb-2 bug in AES assembler code Greg Kroah-Hartman
2013-10-03 4:05 ` [ 23/52] staging: vt6656: [BUG] main_usb.c oops on device_close move flag earlier Greg Kroah-Hartman
2013-10-03 4:05 ` [ 24/52] staging: vt6656: [BUG] iwctl_siwencodeext return if device not open Greg Kroah-Hartman
2013-10-03 4:05 ` [ 25/52] drm/i915/tv: clear adjusted_mode.flags Greg Kroah-Hartman
2013-10-03 4:05 ` [ 26/52] xhci: Ensure a command structure points to the correct trb on the command ring Greg Kroah-Hartman
2013-10-03 4:05 ` [ 27/52] xhci: Fix oops happening after address device timeout Greg Kroah-Hartman
2013-10-03 4:05 ` [ 28/52] USB: fix PM config symbol in uhci-hcd, ehci-hcd, and xhci-hcd Greg Kroah-Hartman
2013-10-03 4:05 ` [ 29/52] xhci: Fix race between ep halt and URB cancellation Greg Kroah-Hartman
2013-10-03 4:05 ` [ 30/52] USB: OHCI: accept very late isochronous URBs Greg Kroah-Hartman
2013-10-03 4:05 ` [ 31/52] USB: UHCI: " Greg Kroah-Hartman
2013-10-03 4:05 ` Greg Kroah-Hartman [this message]
2013-10-03 4:05 ` [ 33/52] fsl/usb: Resolve PHY_CLK_VLD instability issue for ULPI phy Greg Kroah-Hartman
2013-10-03 4:05 ` [ 34/52] usb: dwc3: pci: add support for BayTrail Greg Kroah-Hartman
2013-10-03 4:05 ` [ 35/52] usb: dwc3: add support for Merrifield Greg Kroah-Hartman
2013-10-03 4:05 ` [ 36/52] usb/core/devio.c: Dont reject control message to endpoint with wrong direction bit Greg Kroah-Hartman
2013-10-03 4:05 ` [ 37/52] driver core : Fix use after free of dev->parent in device_shutdown Greg Kroah-Hartman
2013-10-03 4:05 ` [ 38/52] dm snapshot: workaround for a false positive lockdep warning Greg Kroah-Hartman
2013-10-03 4:05 ` [ 39/52] dm-snapshot: fix performance degradation due to small hash size Greg Kroah-Hartman
2013-10-03 4:05 ` [ 40/52] dm mpath: disable WRITE SAME if it fails Greg Kroah-Hartman
2013-10-03 4:05 ` [ 41/52] dm-raid: silence compiler warning on rebuilds_per_group Greg Kroah-Hartman
2013-10-03 4:06 ` [ 42/52] drm/i915: preserve pipe A quirk in i9xx_set_pipeconf Greg Kroah-Hartman
2013-10-03 4:06 ` [ 43/52] drm/i915/dp: increase i2c-over-aux retry interval on AUX DEFER Greg Kroah-Hartman
2013-10-03 4:06 ` [ 44/52] drm/radeon: avoid UVD corruption on AGP cards using GPU gart Greg Kroah-Hartman
2013-10-03 4:06 ` [ 45/52] drm/radeon: Make r100_cp_ring_info() and radeon_ring_gfx() safe (v2) Greg Kroah-Hartman
2013-10-03 4:06 ` [ 46/52] drm/radeon: disable tests/benchmarks if accel is disabled Greg Kroah-Hartman
2013-10-03 4:06 ` [ 47/52] drm/radeon: add missing hdmi callbacks for rv6xx Greg Kroah-Hartman
2013-10-03 4:06 ` [ 48/52] drm/radeon: fix hdmi audio on DCE3.0/3.1 asics Greg Kroah-Hartman
2013-10-03 4:06 ` [ 49/52] ARM: mxs: stub out mxs_pm_init for !CONFIG_PM Greg Kroah-Hartman
2013-10-03 4:06 ` [ 50/52] hwmon: (applesmc) Check key count before proceeding Greg Kroah-Hartman
2013-10-03 4:06 ` [ 51/52] ALSA: compress: Fix compress device unregister Greg Kroah-Hartman
2013-10-03 4:06 ` [ 52/52] drm/i915: fix gen4 digital port hotplug definitions Greg Kroah-Hartman
2013-10-03 13:32 ` [ 00/52] 3.10.15-stable review Guenter Roeck
2013-10-03 18:41 ` Greg Kroah-Hartman
2013-10-03 22:54 ` Shuah Khan
2013-10-03 23:04 ` Greg Kroah-Hartman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20131003040524.365367001@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mina86@mina86.com \
--cc=stable@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.