stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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;
 }
 



  parent reply	other threads:[~2013-10-03  4:05 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).