SUNRPC: Ensure that gss_auth isn't freed before its upcall messages
Fix a race in which the RPC client is shutting down while the gss daemon is processing a downcall. If the RPC client manages to shut down before the gss daemon is done, then the struct gss_auth used in gss_release_msg() may have already been freed. Link: http://lkml.kernel.org/r/1392494917.71728.YahooMailNeo@web140002.mail.bf1.yahoo.com Reported-by: John <da_audiophile@yahoo.com> Reported-by: Borislav Petkov <bp@alien8.de> Cc: stable@vger.kernel.org # 3.12+ Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
@@ -108,6 +108,7 @@ struct gss_auth {
|
|||||||
static DEFINE_SPINLOCK(pipe_version_lock);
|
static DEFINE_SPINLOCK(pipe_version_lock);
|
||||||
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
|
static struct rpc_wait_queue pipe_version_rpc_waitqueue;
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
|
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
|
||||||
|
static void gss_put_auth(struct gss_auth *gss_auth);
|
||||||
|
|
||||||
static void gss_free_ctx(struct gss_cl_ctx *);
|
static void gss_free_ctx(struct gss_cl_ctx *);
|
||||||
static const struct rpc_pipe_ops gss_upcall_ops_v0;
|
static const struct rpc_pipe_ops gss_upcall_ops_v0;
|
||||||
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
|
|||||||
if (gss_msg->ctx != NULL)
|
if (gss_msg->ctx != NULL)
|
||||||
gss_put_ctx(gss_msg->ctx);
|
gss_put_ctx(gss_msg->ctx);
|
||||||
rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
|
rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
|
||||||
|
gss_put_auth(gss_msg->auth);
|
||||||
kfree(gss_msg);
|
kfree(gss_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,6 +502,7 @@ gss_alloc_msg(struct gss_auth *gss_auth,
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_free_msg;
|
goto err_free_msg;
|
||||||
};
|
};
|
||||||
|
kref_get(&gss_auth->kref);
|
||||||
return gss_msg;
|
return gss_msg;
|
||||||
err_free_msg:
|
err_free_msg:
|
||||||
kfree(gss_msg);
|
kfree(gss_msg);
|
||||||
@@ -1063,6 +1066,12 @@ gss_free_callback(struct kref *kref)
|
|||||||
gss_free(gss_auth);
|
gss_free(gss_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gss_put_auth(struct gss_auth *gss_auth)
|
||||||
|
{
|
||||||
|
kref_put(&gss_auth->kref, gss_free_callback);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gss_destroy(struct rpc_auth *auth)
|
gss_destroy(struct rpc_auth *auth)
|
||||||
{
|
{
|
||||||
@@ -1084,7 +1093,7 @@ gss_destroy(struct rpc_auth *auth)
|
|||||||
gss_auth->gss_pipe[1] = NULL;
|
gss_auth->gss_pipe[1] = NULL;
|
||||||
rpcauth_destroy_credcache(auth);
|
rpcauth_destroy_credcache(auth);
|
||||||
|
|
||||||
kref_put(&gss_auth->kref, gss_free_callback);
|
gss_put_auth(gss_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1255,7 +1264,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
|
|||||||
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
|
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
|
||||||
if (ctx)
|
if (ctx)
|
||||||
gss_put_ctx(ctx);
|
gss_put_ctx(ctx);
|
||||||
kref_put(&gss_auth->kref, gss_free_callback);
|
gss_put_auth(gss_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Reference in New Issue
Block a user