[PATCH v3] 9p: client_create/destroy: only call trans_mod->close after create

Dominique Martinet posted 1 patch 1 year, 6 months ago
net/9p/client.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
[PATCH v3] 9p: client_create/destroy: only call trans_mod->close after create
Posted by Dominique Martinet 1 year, 6 months ago
destroy code would incorrectly call close() if trans_mod exists after some
hasty code cleanup: we need to make sure we only call close after create

Link: https://lkml.kernel.org/r/20220928214417.1749609-1-asmadeus@codewreck.org
Link: https://lkml.kernel.org/r/00000000000015ac7905e97ebaed@google.com
Reported-by: syzbot+67d13108d855f451cafc@syzkaller.appspotmail.com
Reported-by: Leon Romanovsky <leon@kernel.org>
Fixes: 3ff51294a055 ("9p: p9_client_create: use p9_client_destroy on failure")
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
---
v1->v2: also reset trans on create error
v2->v3: fix silly compile errors

Sorry for the multiple mails, that's what I get for not even doing basic
tests before talking...

 net/9p/client.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/9p/client.c b/net/9p/client.c
index bfa80f01992e..41e825a8da7c 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -971,6 +971,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 	spin_lock_init(&clnt->lock);
 	idr_init(&clnt->fids);
 	idr_init(&clnt->reqs);
+	clnt->trans = ERR_PTR(-EINVAL);
 
 	err = parse_opts(options, clnt);
 	if (err < 0)
@@ -990,8 +991,14 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 		 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
 
 	err = clnt->trans_mod->create(clnt, dev_name, options);
-	if (err)
+	// ensure clnt->trans is initialized to call close() on destroy
+	// if and only if create succeeded
+	if (err < 0) {
+		clnt->trans = ERR_PTR(err);
 		goto out;
+	}
+	if (IS_ERR(clnt->trans))
+		clnt->trans = NULL;
 
 	if (clnt->msize > clnt->trans_mod->maxsize) {
 		clnt->msize = clnt->trans_mod->maxsize;
@@ -1036,7 +1043,7 @@ void p9_client_destroy(struct p9_client *clnt)
 
 	p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
 
-	if (clnt->trans_mod)
+	if (clnt->trans_mod && !IS_ERR(clnt->trans))
 		clnt->trans_mod->close(clnt);
 
 	v9fs_put_trans(clnt->trans_mod);
-- 
2.35.1
Re: [PATCH v3] 9p: client_create/destroy: only call trans_mod->close after create
Posted by Leon Romanovsky 1 year, 6 months ago
On Thu, Sep 29, 2022 at 07:19:23AM +0900, Dominique Martinet wrote:
> destroy code would incorrectly call close() if trans_mod exists after some
> hasty code cleanup: we need to make sure we only call close after create
> 
> Link: https://lkml.kernel.org/r/20220928214417.1749609-1-asmadeus@codewreck.org
> Link: https://lkml.kernel.org/r/00000000000015ac7905e97ebaed@google.com
> Reported-by: syzbot+67d13108d855f451cafc@syzkaller.appspotmail.com
> Reported-by: Leon Romanovsky <leon@kernel.org>
> Fixes: 3ff51294a055 ("9p: p9_client_create: use p9_client_destroy on failure")
> Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
> ---
> v1->v2: also reset trans on create error
> v2->v3: fix silly compile errors
> 
> Sorry for the multiple mails, that's what I get for not even doing basic
> tests before talking...

Please always submit new patch versions as new one and don't reply-to.
It breaks flows of everyone who relies on proper email threading.

> 
>  net/9p/client.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/net/9p/client.c b/net/9p/client.c
> index bfa80f01992e..41e825a8da7c 100644
> --- a/net/9p/client.c
> +++ b/net/9p/client.c
> @@ -971,6 +971,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
>  	spin_lock_init(&clnt->lock);
>  	idr_init(&clnt->fids);
>  	idr_init(&clnt->reqs);
> +	clnt->trans = ERR_PTR(-EINVAL);
>  
>  	err = parse_opts(options, clnt);
>  	if (err < 0)
> @@ -990,8 +991,14 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
>  		 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
>  
>  	err = clnt->trans_mod->create(clnt, dev_name, options);
> -	if (err)
> +	// ensure clnt->trans is initialized to call close() on destroy
> +	// if and only if create succeeded

Please use /* */ comment style.

> +	if (err < 0) {
> +		clnt->trans = ERR_PTR(err);
>  		goto out;
> +	}
> +	if (IS_ERR(clnt->trans))
> +		clnt->trans = NULL;
>  
>  	if (clnt->msize > clnt->trans_mod->maxsize) {
>  		clnt->msize = clnt->trans_mod->maxsize;
> @@ -1036,7 +1043,7 @@ void p9_client_destroy(struct p9_client *clnt)
>  
>  	p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
>  
> -	if (clnt->trans_mod)
> +	if (clnt->trans_mod && !IS_ERR(clnt->trans))

It is completely no-go to rely on internal value inside of structure after
failure in ->create() callback.

>  		clnt->trans_mod->close(clnt);
>  
>  	v9fs_put_trans(clnt->trans_mod);
> -- 
> 2.35.1
>
Re: [PATCH v3] 9p: client_create/destroy: only call trans_mod->close after create
Posted by Dominique Martinet 1 year, 6 months ago
Leon Romanovsky wrote on Thu, Sep 29, 2022 at 08:54:10AM +0300:
> > +	// ensure clnt->trans is initialized to call close() on destroy
> > +	// if and only if create succeeded
> > +	if (err < 0) {
> > +		clnt->trans = ERR_PTR(err);
> >  		goto out;
> > +	}
> > +	if (IS_ERR(clnt->trans))
> > +		clnt->trans = NULL;
> >  
> >  	if (clnt->msize > clnt->trans_mod->maxsize) {
> >  		clnt->msize = clnt->trans_mod->maxsize;
> > @@ -1036,7 +1043,7 @@ void p9_client_destroy(struct p9_client *clnt)
> >  
> >  	p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
> >  
> > -	if (clnt->trans_mod)
> > +	if (clnt->trans_mod && !IS_ERR(clnt->trans))
> 
> It is completely no-go to rely on internal value inside of structure after
> failure in ->create() callback.

We're overriding the value after ->create(), in both cases that might
pose problem (success without setting trans/failure); I can't see how
that would possibly fail.

But as you've seen in the other commit I am in no shape to write any
decent code and consider the implications of what I'm changing in this
untangled mess, so you know what: I'll just leave this broken.

Please send me a patch if you care, I'm done here.
-- 
Dominique