Skip to content

Commit

Permalink
SUNRPC: Convert auth_gss pipe detection to work in namespaces
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed May 16, 2013
1 parent abfdbd5 commit 2aed8b4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 19 deletions.
46 changes: 27 additions & 19 deletions net/sunrpc/auth_gss/auth_gss.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ struct gss_auth {
};

/* 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 struct rpc_wait_queue pipe_version_rpc_waitqueue;
static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
Expand Down Expand Up @@ -268,34 +266,38 @@ struct gss_upcall_msg {
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;

spin_lock(&pipe_version_lock);
if (pipe_version >= 0) {
atomic_inc(&pipe_users);
ret = pipe_version;
if (sn->pipe_version >= 0) {
atomic_inc(&sn->pipe_users);
ret = sn->pipe_version;
} else
ret = -EAGAIN;
spin_unlock(&pipe_version_lock);
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)) {
pipe_version = -1;
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);

if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) {
sn->pipe_version = -1;
spin_unlock(&pipe_version_lock);
}
}

static void
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))
return;
put_pipe_version();
put_pipe_version(net);
BUG_ON(!list_empty(&gss_msg->list));
if (gss_msg->ctx != NULL)
gss_put_ctx(gss_msg->ctx);
Expand Down Expand Up @@ -441,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg,
struct rpc_clnt *clnt,
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);
else /* pipe_version == 1 */
gss_encode_v1_msg(gss_msg, clnt, service_name);
Expand All @@ -457,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
if (gss_msg == NULL)
return ERR_PTR(-ENOMEM);
vers = get_pipe_version();
vers = get_pipe_version(rpc_net_ns(clnt));
if (vers < 0) {
kfree(gss_msg);
return ERR_PTR(vers);
Expand Down Expand Up @@ -581,8 +586,8 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
if (PTR_ERR(gss_msg) == -EAGAIN) {
err = wait_event_interruptible_timeout(pipe_version_waitqueue,
pipe_version >= 0, timeout);
if (pipe_version < 0) {
sn->pipe_version >= 0, timeout);
if (sn->pipe_version < 0) {
if (err == 0)
sn->gssd_running = 0;
warn_gssd();
Expand Down Expand Up @@ -719,20 +724,22 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)

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;

spin_lock(&pipe_version_lock);
if (pipe_version < 0) {
if (sn->pipe_version < 0) {
/* 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);
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 */
ret = -EBUSY;
goto out;
}
atomic_inc(&pipe_users);
atomic_inc(&sn->pipe_users);
out:
spin_unlock(&pipe_version_lock);
return ret;
Expand All @@ -752,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode)
static void
gss_pipe_release(struct inode *inode)
{
struct net *net = inode->i_sb->s_fs_info;
struct rpc_pipe *pipe = RPC_I(inode)->pipe;
struct gss_upcall_msg *gss_msg;

Expand All @@ -770,7 +778,7 @@ gss_pipe_release(struct inode *inode)
}
spin_unlock(&pipe->lock);

put_pipe_version();
put_pipe_version(net);
}

static void
Expand Down
2 changes: 2 additions & 0 deletions net/sunrpc/netns.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ struct sunrpc_net {
wait_queue_head_t gssp_wq;
struct rpc_clnt *gssp_clnt;
int use_gss_proxy;
int pipe_version;
atomic_t pipe_users;
struct proc_dir_entry *use_gssp_proc;

unsigned int gssd_running;
Expand Down
1 change: 1 addition & 0 deletions net/sunrpc/rpc_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ void rpc_pipefs_init_net(struct net *net)

mutex_init(&sn->pipefs_sb_lock);
sn->gssd_running = 1;
sn->pipe_version = -1;
}

/*
Expand Down

0 comments on commit 2aed8b4

Please sign in to comment.