diff mbox series

[3/5] binderfs: rework binderfs_fill_super()

Message ID 20190118145344.11532-4-christian@brauner.io (mailing list archive)
State New, archived
Headers show
Series binderfs: debug galore | expand

Commit Message

Christian Brauner Jan. 18, 2019, 2:53 p.m. UTC
Al pointed out that on binderfs_fill_super() error
deactivate_locked_super() will call binderfs_kill_super() so all of the
freeing and putting we currently do in binderfs_fill_super() is unnecessary
and buggy. Let's simply return errors and let binderfs_fill_super() take
care of cleaning up on error.

Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Christian Brauner <christian@brauner.io>
---
 drivers/android/binderfs.c | 35 +++++++++--------------------------
 1 file changed, 9 insertions(+), 26 deletions(-)

Comments

Al Viro Jan. 18, 2019, 11:03 p.m. UTC | #1
On Fri, Jan 18, 2019 at 03:53:42PM +0100, Christian Brauner wrote:
>  static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
>  {
> +	int ret;
>  	struct binderfs_info *info;
> -	int ret = -ENOMEM;
>  	struct inode *inode = NULL;
>  	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
>  
> @@ -495,13 +495,14 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
>  	sb->s_op = &binderfs_super_ops;
>  	sb->s_time_gran = 1;
>  
> -	info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
> -	if (!info)
> -		goto err_without_dentry;
> +	sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
> +	if (!sb->s_fs_info)
> +		return -ENOMEM;
> +	info = sb->s_fs_info;

... and that's when you should grab ipcns reference and stick it into
info->ipc_ns, to match the logics in binderfs_kill_super().

Otherwise the failure above

>  	ret = binderfs_parse_mount_opts(data, &info->mount_opts);
>  	if (ret)
> -		goto err_without_dentry;
> +		return ret;

... or here leaves you with an ipcns leak.

Destructor does
	if ->s_fs_info is non-NULL
		release ->s_fs_info->ipc_ns
		free ->s_fs_info
so constructor should not leave object in a state when ipcns is already
grabbed, but not stored in ->s_fs_info->ipc_ns (including the case of
allocation failure leaving it with NULL ->s_fs_info).
Christian Brauner Jan. 19, 2019, 3:12 p.m. UTC | #2
On Fri, Jan 18, 2019 at 11:03:54PM +0000, Al Viro wrote:
> On Fri, Jan 18, 2019 at 03:53:42PM +0100, Christian Brauner wrote:
> >  static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
> >  {
> > +	int ret;
> >  	struct binderfs_info *info;
> > -	int ret = -ENOMEM;
> >  	struct inode *inode = NULL;
> >  	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
> >  
> > @@ -495,13 +495,14 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
> >  	sb->s_op = &binderfs_super_ops;
> >  	sb->s_time_gran = 1;
> >  
> > -	info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
> > -	if (!info)
> > -		goto err_without_dentry;
> > +	sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
> > +	if (!sb->s_fs_info)
> > +		return -ENOMEM;
> > +	info = sb->s_fs_info;
> 
> ... and that's when you should grab ipcns reference and stick it into
> info->ipc_ns, to match the logics in binderfs_kill_super().
> 
> Otherwise the failure above
> 
> >  	ret = binderfs_parse_mount_opts(data, &info->mount_opts);
> >  	if (ret)
> > -		goto err_without_dentry;
> > +		return ret;
> 
> ... or here leaves you with an ipcns leak.
> 
> Destructor does
> 	if ->s_fs_info is non-NULL
> 		release ->s_fs_info->ipc_ns
> 		free ->s_fs_info
> so constructor should not leave object in a state when ipcns is already
> grabbed, but not stored in ->s_fs_info->ipc_ns (including the case of
> allocation failure leaving it with NULL ->s_fs_info).

Yeah, total brainfart on my side. I shouldn't code in airports
apparently... Fixed.
diff mbox series

Patch

diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 02c96b5edfa9..c0fa495ee994 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -468,8 +468,8 @@  static const struct inode_operations binderfs_dir_inode_operations = {
 
 static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
 {
+	int ret;
 	struct binderfs_info *info;
-	int ret = -ENOMEM;
 	struct inode *inode = NULL;
 	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
 
@@ -495,13 +495,14 @@  static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_op = &binderfs_super_ops;
 	sb->s_time_gran = 1;
 
-	info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
-	if (!info)
-		goto err_without_dentry;
+	sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL);
+	if (!sb->s_fs_info)
+		return -ENOMEM;
+	info = sb->s_fs_info;
 
 	ret = binderfs_parse_mount_opts(data, &info->mount_opts);
 	if (ret)
-		goto err_without_dentry;
+		return ret;
 
 	info->ipc_ns = ipc_ns;
 	info->root_gid = make_kgid(sb->s_user_ns, 0);
@@ -511,12 +512,9 @@  static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
 	if (!uid_valid(info->root_uid))
 		info->root_uid = GLOBAL_ROOT_UID;
 
-	sb->s_fs_info = info;
-
-	ret = -ENOMEM;
 	inode = new_inode(sb);
 	if (!inode)
-		goto err_without_dentry;
+		return -ENOMEM;
 
 	inode->i_ino = FIRST_INODE;
 	inode->i_fop = &simple_dir_operations;
@@ -527,24 +525,9 @@  static int binderfs_fill_super(struct super_block *sb, void *data, int silent)
 
 	sb->s_root = d_make_root(inode);
 	if (!sb->s_root)
-		goto err_without_dentry;
-
-	ret = binderfs_binder_ctl_create(sb);
-	if (ret)
-		goto err_with_dentry;
-
-	return 0;
-
-err_with_dentry:
-	dput(sb->s_root);
-	sb->s_root = NULL;
-
-err_without_dentry:
-	put_ipc_ns(ipc_ns);
-	iput(inode);
-	kfree(info);
+		return -ENOMEM;
 
-	return ret;
+	return binderfs_binder_ctl_create(sb);
 }
 
 static struct dentry *binderfs_mount(struct file_system_type *fs_type,