2013-12-31 16:35:56

by Kinglong Mee

[permalink] [raw]
Subject: [PATCH] NFSD: Fix a memory leak in nfsd4_create_session

If failed after calling alloc_session but before init_session, nfsd will call __free_session to
free se_slots in session. But, session->se_fchannel.maxreqs is not initialized (value is zero).
So that, the memory malloced for slots will be lost in free_session_slots for maxreqs is zero.

This path sets the information for channel in alloc_session after mallocing slots succeed,
instead in init_session.

Signed-off-by: Kinglong Mee <[email protected]>
---
fs/nfsd/nfs4state.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9a6d088..7d613a7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -832,10 +832,11 @@ static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
spin_unlock(&nfsd_drc_lock);
}

-static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
+static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
+ struct nfsd4_channel_attrs *battrs)
{
- int numslots = attrs->maxreqs;
- int slotsize = slot_bytes(attrs);
+ int numslots = fattrs->maxreqs;
+ int slotsize = slot_bytes(fattrs);
struct nfsd4_session *new;
int mem, i;

@@ -852,6 +853,10 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
if (!new->se_slots[i])
goto out_free;
}
+
+ memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
+ memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
+
return new;
out_free:
while (i--)
@@ -997,10 +1002,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
list_add(&new->se_perclnt, &clp->cl_sessions);
spin_unlock(&clp->cl_lock);
spin_unlock(&nn->client_lock);
- memcpy(&new->se_fchannel, &cses->fore_channel,
- sizeof(struct nfsd4_channel_attrs));
- memcpy(&new->se_bchannel, &cses->back_channel,
- sizeof(struct nfsd4_channel_attrs));
+
if (cses->flags & SESSION4_BACK_CHAN) {
struct sockaddr *sa = svc_addr(rqstp);
/*
@@ -1917,7 +1919,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
if (status)
goto out_release_drc_mem;
status = nfserr_jukebox;
- new = alloc_session(&cr_ses->fore_channel);
+ new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
if (!new)
goto out_release_drc_mem;
conn = alloc_conn_from_crses(rqstp, cr_ses);
--
1.8.4.2



2014-01-06 20:34:26

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH] NFSD: Fix a memory leak in nfsd4_create_session

On Wed, Jan 01, 2014 at 12:35:47AM +0800, Kinglong Mee wrote:
> If failed after calling alloc_session but before init_session, nfsd will call __free_session to
> free se_slots in session. But, session->se_fchannel.maxreqs is not initialized (value is zero).
> So that, the memory malloced for slots will be lost in free_session_slots for maxreqs is zero.
>
> This path sets the information for channel in alloc_session after mallocing slots succeed,
> instead in init_session.

Thanks, applying.--b.

>
> Signed-off-by: Kinglong Mee <[email protected]>
> ---
> fs/nfsd/nfs4state.c | 18 ++++++++++--------
> 1 file changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 9a6d088..7d613a7 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -832,10 +832,11 @@ static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
> spin_unlock(&nfsd_drc_lock);
> }
>
> -static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
> +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
> + struct nfsd4_channel_attrs *battrs)
> {
> - int numslots = attrs->maxreqs;
> - int slotsize = slot_bytes(attrs);
> + int numslots = fattrs->maxreqs;
> + int slotsize = slot_bytes(fattrs);
> struct nfsd4_session *new;
> int mem, i;
>
> @@ -852,6 +853,10 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
> if (!new->se_slots[i])
> goto out_free;
> }
> +
> + memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
> + memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
> +
> return new;
> out_free:
> while (i--)
> @@ -997,10 +1002,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
> list_add(&new->se_perclnt, &clp->cl_sessions);
> spin_unlock(&clp->cl_lock);
> spin_unlock(&nn->client_lock);
> - memcpy(&new->se_fchannel, &cses->fore_channel,
> - sizeof(struct nfsd4_channel_attrs));
> - memcpy(&new->se_bchannel, &cses->back_channel,
> - sizeof(struct nfsd4_channel_attrs));
> +
> if (cses->flags & SESSION4_BACK_CHAN) {
> struct sockaddr *sa = svc_addr(rqstp);
> /*
> @@ -1917,7 +1919,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
> if (status)
> goto out_release_drc_mem;
> status = nfserr_jukebox;
> - new = alloc_session(&cr_ses->fore_channel);
> + new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
> if (!new)
> goto out_release_drc_mem;
> conn = alloc_conn_from_crses(rqstp, cr_ses);
> --
> 1.8.4.2
>