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:
parent
abfdbd53a4
commit
2aed8b476f
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue