Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2aed8b47 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent abfdbd53
Loading
Loading
Loading
Loading
+27 −19
Original line number Original line Diff line number Diff line
@@ -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
+2 −0
Original line number Original line Diff line number Diff line
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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;
}
}


/*
/*