All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: Eric Biggers <ebiggers3@gmail.com>
Cc: dhowells@redhat.com, Alexander Viro <viro@zeniv.linux.org.uk>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	Eric Biggers <ebiggers@google.com>
Subject: Re: [PATCH 07/18] fs_context: fix double free of legacy_fs_context data
Date: Mon, 09 Jul 2018 13:31:09 +0100	[thread overview]
Message-ID: <3014.1531139469@warthog.procyon.org.uk> (raw)
In-Reply-To: <20180708210154.10423-8-ebiggers3@gmail.com>

Eric Biggers <ebiggers3@gmail.com> wrote:

> sys_fsmount() calls fc->ops->free() to free the data, zeroes
> ->fs_private, then proceeds to reuse the context.  But legacy_fs_context
> doesn't use ->fs_private, so we need to handle zeroing it too; otherwise
> there's a double free of legacy_fs_context::{legacy_data,secdata}.

I think the attached is better.  I stopped embedding the fs_context in the
xxx_fs_context to make certain things simpler, but I missed the legacy
wrapper.

David
---
diff --git a/fs/fs_context.c b/fs/fs_context.c
index f91facc769f7..ab93a0b73dc6 100644
--- a/fs/fs_context.c
+++ b/fs/fs_context.c
@@ -34,7 +34,6 @@ enum legacy_fs_param {
 };
 
 struct legacy_fs_context {
-	struct fs_context	fc;
 	char			*legacy_data;	/* Data page for legacy filesystems */
 	char			*secdata;
 	size_t			data_size;
@@ -239,12 +238,21 @@ struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
 				      enum fs_context_purpose purpose)
 {
 	struct fs_context *fc;
-	int ret;
+	int ret = -ENOMEM;
 
-	fc = kzalloc(sizeof(struct legacy_fs_context), GFP_KERNEL);
+	fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL);
 	if (!fc)
 		return ERR_PTR(-ENOMEM);
 
+	if (!fs_type->init_fs_context) {
+		fc->fs_private = kzalloc(sizeof(struct legacy_fs_context),
+					 GFP_KERNEL);
+		if (!fc->fs_private)
+			goto err_fc;
+
+		fc->ops = &legacy_fs_context_ops;
+	}
+
 	fc->purpose	= purpose;
 	fc->sb_flags	= sb_flags;
 	fc->fs_type	= get_filesystem(fs_type);
@@ -277,8 +285,6 @@ struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type,
 		ret = fc->fs_type->init_fs_context(fc, reference);
 		if (ret < 0)
 			goto err_fc;
-	} else {
-		fc->ops = &legacy_fs_context_ops;
 	}
 
 	/* Do the security check last because ->init_fs_context may change the
@@ -395,7 +401,7 @@ EXPORT_SYMBOL(put_fs_context);
  */
 static void legacy_fs_context_free(struct fs_context *fc)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx = fc->fs_private;
 
 	free_secdata(ctx->secdata);
 	switch (ctx->param_type) {
@@ -408,6 +414,8 @@ static void legacy_fs_context_free(struct fs_context *fc)
 		kfree(ctx->legacy_data);
 		break;
 	}
+
+	kfree(ctx);
 }
 
 /*
@@ -415,20 +423,28 @@ static void legacy_fs_context_free(struct fs_context *fc)
  */
 static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
-	struct legacy_fs_context *src_ctx = container_of(src_fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx;
+	struct legacy_fs_context *src_ctx = src_fc->fs_private;
+
+	ctx = kmemdup(src_ctx, sizeof(*src_ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
 
 	switch (ctx->param_type) {
 	case LEGACY_FS_MONOLITHIC_PARAMS:
 	case LEGACY_FS_INDIVIDUAL_PARAMS:
 		ctx->legacy_data = kmemdup(src_ctx->legacy_data,
 					   src_ctx->data_size, GFP_KERNEL);
-		if (!ctx->legacy_data)
+		if (!ctx->legacy_data) {
+			kfree(ctx);
 			return -ENOMEM;
+		}
 		/* Fall through */
 	default:
 		break;
 	}
+
+	fc->fs_private = ctx;
 	return 0;
 }
 
@@ -438,7 +454,7 @@ static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_f
  */
 static int legacy_parse_option(struct fs_context *fc, char *opt, size_t len)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx = fc->fs_private;
 	unsigned int size = ctx->data_size;
 
 	if (ctx->param_type != LEGACY_FS_UNSET_PARAMS &&
@@ -471,7 +487,7 @@ static int legacy_parse_option(struct fs_context *fc, char *opt, size_t len)
  */
 static int legacy_parse_monolithic(struct fs_context *fc, void *data, size_t data_size)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx = fc->fs_private;
 
 	if (ctx->param_type != LEGACY_FS_UNSET_PARAMS) {
 		pr_warn("VFS: Can't mix monolithic and individual options\n");
@@ -507,7 +523,7 @@ static int legacy_parse_monolithic(struct fs_context *fc, void *data, size_t dat
  */
 static int legacy_validate(struct fs_context *fc)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx = fc->fs_private;
 
 	switch (ctx->param_type) {
 	case LEGACY_FS_UNSET_PARAMS:
@@ -520,7 +536,7 @@ static int legacy_validate(struct fs_context *fc)
 		break;
 	}
 
-	if (ctx->fc.fs_type->fs_flags & FS_BINARY_MOUNTDATA)
+	if (fc->fs_type->fs_flags & FS_BINARY_MOUNTDATA)
 		return 0;
 
 	ctx->secdata = alloc_secdata();
@@ -557,13 +573,13 @@ static int legacy_set_subtype(struct fs_context *fc)
  */
 static int legacy_get_tree(struct fs_context *fc)
 {
-	struct legacy_fs_context *ctx = container_of(fc, struct legacy_fs_context, fc);
+	struct legacy_fs_context *ctx = fc->fs_private;
 	struct super_block *sb;
 	struct dentry *root;
 	int ret;
 
-	root = ctx->fc.fs_type->mount(ctx->fc.fs_type, ctx->fc.sb_flags,
-				      ctx->fc.source, ctx->legacy_data,
+	root = fc->fs_type->mount(fc->fs_type, fc->sb_flags,
+				      fc->source, ctx->legacy_data,
 				      ctx->data_size);
 	if (IS_ERR(root))
 		return PTR_ERR(root);
@@ -571,14 +587,14 @@ static int legacy_get_tree(struct fs_context *fc)
 	sb = root->d_sb;
 	BUG_ON(!sb);
 
-	if ((ctx->fc.fs_type->fs_flags & FS_HAS_SUBTYPE) &&
+	if ((fc->fs_type->fs_flags & FS_HAS_SUBTYPE) &&
 	    !fc->subtype) {
 		ret = legacy_set_subtype(fc);
 		if (ret < 0)
 			goto err_sb;
 	}
 
-	ctx->fc.root = root;
+	fc->root = root;
 	return 0;
 
 err_sb:

  parent reply	other threads:[~2018-07-09 12:31 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-08 21:01 [PATCH vfs/for-next 00/18] fs_context fixes Eric Biggers
2018-07-08 21:01 ` [PATCH 01/18] sysfs: check return value of kernfs_get_tree() Eric Biggers
2018-07-08 21:01 ` [PATCH 02/18] fs_context: fix shrinker leak in sget_fc() Eric Biggers
2018-07-08 21:01 ` [PATCH 03/18] fs_context: fix detecting full log buffer Eric Biggers
2018-07-08 21:01 ` [PATCH 04/18] fs_context: fix fs_context leak in simple_pin_fs() Eric Biggers
2018-07-08 21:01 ` [PATCH 05/18] fs_context: fix mount option blacklist Eric Biggers
2018-07-08 21:01 ` [PATCH 06/18] fs_context: fix memory leak with 's' (source) command Eric Biggers
2018-07-08 21:01 ` [PATCH 07/18] fs_context: fix double free of legacy_fs_context data Eric Biggers
2018-07-08 21:01 ` [PATCH 08/18] fsmount: pass up error code from dentry_open() Eric Biggers
2018-07-08 21:01 ` [PATCH 09/18] fsmount: fix handling FSMOUNT_CLOEXEC Eric Biggers
2018-07-08 21:01 ` [PATCH 10/18] fsmount: fix bypassing SB_MANDLOCK permission check Eric Biggers
2018-07-08 21:01 ` [PATCH 11/18] fspick: fix path leak Eric Biggers
2018-07-08 21:01 ` [PATCH 12/18] fspick: add missing permission check Eric Biggers
2018-07-08 21:01 ` [PATCH 13/18] fsmount: removed unused variable 'inode' Eric Biggers
2018-07-08 21:01 ` [PATCH 14/18] fsopen,fspick: factor out log allocation Eric Biggers
2018-07-08 21:01 ` [PATCH 15/18] fsopen,fspick: rename fsopen_create_fd() to fscontext_create_fd() Eric Biggers
2018-07-08 21:01 ` [PATCH 16/18] fs_context: de-obfuscate control flow in fscontext_read() Eric Biggers
2018-07-08 21:01 ` [PATCH 17/18] fs_context: de-obfuscate command validation Eric Biggers
2018-07-08 21:01 ` [PATCH 18/18] fs_context: fix fscontext_write() comment Eric Biggers
2018-07-08 23:46 ` [PATCH vfs/for-next 00/18] fs_context fixes Eric Biggers
2018-07-09  9:32 ` [PATCH 03/18] fs_context: fix detecting full log buffer David Howells
2018-07-09  9:35 ` David Howells
2018-07-09 12:31 ` David Howells [this message]
2018-07-10  1:17   ` [PATCH 07/18] fs_context: fix double free of legacy_fs_context data Eric Biggers
2018-07-10  1:25     ` Eric Biggers
2018-07-10  8:02   ` David Howells
2018-07-09 15:31 ` [PATCH vfs/for-next 00/18] fs_context fixes David Howells
2018-07-09 15:56   ` Al Viro
2018-07-09 16:28   ` David Howells
2018-07-09 21:57   ` David Howells

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=3014.1531139469@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=ebiggers3@gmail.com \
    --cc=ebiggers@google.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@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.