SUNRPC: Convert auth_gss pipe detection to work in namespaces

This seems to have been overlooked when we did the namespace
conversion. If a container is running a legacy version of rpc.gssd
then it will be disrupted if the global 'pipe_version' is set by a
container running the new version of rpc.gssd.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Trond Myklebust 2013-05-15 10:27:32 -07:00
parent abfdbd53a4
commit 2aed8b476f
3 changed files with 30 additions and 19 deletions

View File

@ -87,8 +87,6 @@ struct gss_auth {
}; };
/* pipe_version >= 0 if and only if someone has a pipe open. */ /* pipe_version >= 0 if and only if someone has a pipe open. */
static int pipe_version = -1;
static atomic_t pipe_users = ATOMIC_INIT(0);
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);
@ -268,24 +266,27 @@ struct gss_upcall_msg {
char databuf[UPCALL_BUF_LEN]; char databuf[UPCALL_BUF_LEN];
}; };
static int get_pipe_version(void) static int get_pipe_version(struct net *net)
{ {
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
int ret; int ret;
spin_lock(&pipe_version_lock); spin_lock(&pipe_version_lock);
if (pipe_version >= 0) { if (sn->pipe_version >= 0) {
atomic_inc(&pipe_users); atomic_inc(&sn->pipe_users);
ret = pipe_version; ret = sn->pipe_version;
} else } else
ret = -EAGAIN; ret = -EAGAIN;
spin_unlock(&pipe_version_lock); spin_unlock(&pipe_version_lock);
return ret; return ret;
} }
static void put_pipe_version(void) static void put_pipe_version(struct net *net)
{ {
if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
pipe_version = -1;
if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) {
sn->pipe_version = -1;
spin_unlock(&pipe_version_lock); spin_unlock(&pipe_version_lock);
} }
} }
@ -293,9 +294,10 @@ static void put_pipe_version(void)
static void static void
gss_release_msg(struct gss_upcall_msg *gss_msg) gss_release_msg(struct gss_upcall_msg *gss_msg)
{ {
struct net *net = rpc_net_ns(gss_msg->auth->client);
if (!atomic_dec_and_test(&gss_msg->count)) if (!atomic_dec_and_test(&gss_msg->count))
return; return;
put_pipe_version(); put_pipe_version(net);
BUG_ON(!list_empty(&gss_msg->list)); BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL) if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx); gss_put_ctx(gss_msg->ctx);
@ -441,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg,
struct rpc_clnt *clnt, struct rpc_clnt *clnt,
const char *service_name) const char *service_name)
{ {
if (pipe_version == 0) struct net *net = rpc_net_ns(clnt);
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
if (sn->pipe_version == 0)
gss_encode_v0_msg(gss_msg); gss_encode_v0_msg(gss_msg);
else /* pipe_version == 1 */ else /* pipe_version == 1 */
gss_encode_v1_msg(gss_msg, clnt, service_name); gss_encode_v1_msg(gss_msg, clnt, service_name);
@ -457,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg == NULL) if (gss_msg == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
vers = get_pipe_version(); vers = get_pipe_version(rpc_net_ns(clnt));
if (vers < 0) { if (vers < 0) {
kfree(gss_msg); kfree(gss_msg);
return ERR_PTR(vers); return ERR_PTR(vers);
@ -581,8 +586,8 @@ retry:
gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
if (PTR_ERR(gss_msg) == -EAGAIN) { if (PTR_ERR(gss_msg) == -EAGAIN) {
err = wait_event_interruptible_timeout(pipe_version_waitqueue, err = wait_event_interruptible_timeout(pipe_version_waitqueue,
pipe_version >= 0, timeout); sn->pipe_version >= 0, timeout);
if (pipe_version < 0) { if (sn->pipe_version < 0) {
if (err == 0) if (err == 0)
sn->gssd_running = 0; sn->gssd_running = 0;
warn_gssd(); warn_gssd();
@ -719,20 +724,22 @@ out:
static int gss_pipe_open(struct inode *inode, int new_version) static int gss_pipe_open(struct inode *inode, int new_version)
{ {
struct net *net = inode->i_sb->s_fs_info;
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
int ret = 0; int ret = 0;
spin_lock(&pipe_version_lock); spin_lock(&pipe_version_lock);
if (pipe_version < 0) { if (sn->pipe_version < 0) {
/* First open of any gss pipe determines the version: */ /* First open of any gss pipe determines the version: */
pipe_version = new_version; sn->pipe_version = new_version;
rpc_wake_up(&pipe_version_rpc_waitqueue); rpc_wake_up(&pipe_version_rpc_waitqueue);
wake_up(&pipe_version_waitqueue); wake_up(&pipe_version_waitqueue);
} else if (pipe_version != new_version) { } else if (sn->pipe_version != new_version) {
/* Trying to open a pipe of a different version */ /* Trying to open a pipe of a different version */
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
atomic_inc(&pipe_users); atomic_inc(&sn->pipe_users);
out: out:
spin_unlock(&pipe_version_lock); spin_unlock(&pipe_version_lock);
return ret; return ret;
@ -752,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode)
static void static void
gss_pipe_release(struct inode *inode) gss_pipe_release(struct inode *inode)
{ {
struct net *net = inode->i_sb->s_fs_info;
struct rpc_pipe *pipe = RPC_I(inode)->pipe; struct rpc_pipe *pipe = RPC_I(inode)->pipe;
struct gss_upcall_msg *gss_msg; struct gss_upcall_msg *gss_msg;
@ -770,7 +778,7 @@ restart:
} }
spin_unlock(&pipe->lock); spin_unlock(&pipe->lock);
put_pipe_version(); put_pipe_version(net);
} }
static void static void

View File

@ -28,6 +28,8 @@ struct sunrpc_net {
wait_queue_head_t gssp_wq; wait_queue_head_t gssp_wq;
struct rpc_clnt *gssp_clnt; struct rpc_clnt *gssp_clnt;
int use_gss_proxy; int use_gss_proxy;
int pipe_version;
atomic_t pipe_users;
struct proc_dir_entry *use_gssp_proc; struct proc_dir_entry *use_gssp_proc;
unsigned int gssd_running; unsigned int gssd_running;

View File

@ -1073,6 +1073,7 @@ void rpc_pipefs_init_net(struct net *net)
mutex_init(&sn->pipefs_sb_lock); mutex_init(&sn->pipefs_sb_lock);
sn->gssd_running = 1; sn->gssd_running = 1;
sn->pipe_version = -1;
} }
/* /*