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
3 changed files with 30 additions and 19 deletions
|
@ -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);
|
||||
|
@ -268,24 +266,27 @@ 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);
|
||||
}
|
||||
}
|
||||
|
@ -293,9 +294,10 @@ static void put_pipe_version(void)
|
|||
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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -770,7 +778,7 @@ gss_pipe_release(struct inode *inode)
|
|||
}
|
||||
spin_unlock(&pipe->lock);
|
||||
|
||||
put_pipe_version();
|
||||
put_pipe_version(net);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue