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

Commit 126e216a authored by Trond Myklebust's avatar Trond Myklebust
Browse files

SUNRPC: Don't spam gssd with upcall requests when the kerberos key expired



Now that the rpc.gssd daemon can explicitly tell us that the key expired,
we should cache that information to avoid spamming gssd.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 9bb0b813
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ struct rpc_cred {
#define RPCAUTH_CRED_NEW	0
#define RPCAUTH_CRED_UPTODATE	1
#define RPCAUTH_CRED_HASHED	2
#define RPCAUTH_CRED_NEGATIVE	3

#define RPCAUTH_CRED_MAGIC	0x0f4aa4f0

+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ struct gss_cred {
	enum rpc_gss_svc	gc_service;
	struct gss_cl_ctx	*gc_ctx;
	struct gss_upcall_msg	*gc_upcall;
	unsigned long		gc_upcall_timestamp;
	unsigned char		gc_machine_cred : 1;
};

+53 −12
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@ static const struct rpc_authops authgss_ops;
static const struct rpc_credops gss_credops;
static const struct rpc_credops gss_nullops;

#define GSS_RETRY_EXPIRED 5
static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;

#ifdef RPC_DEBUG
# define RPCDBG_FACILITY	RPCDBG_AUTH
#endif
@@ -349,6 +352,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
	spin_unlock(&inode->i_lock);
}

static void
gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg)
{
	switch (gss_msg->msg.errno) {
	case 0:
		if (gss_msg->ctx == NULL)
			break;
		clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
		gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx);
		break;
	case -EKEYEXPIRED:
		set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
	}
	gss_cred->gc_upcall_timestamp = jiffies;
	gss_cred->gc_upcall = NULL;
	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
}

static void
gss_upcall_callback(struct rpc_task *task)
{
@@ -358,13 +379,9 @@ gss_upcall_callback(struct rpc_task *task)
	struct inode *inode = &gss_msg->inode->vfs_inode;

	spin_lock(&inode->i_lock);
	if (gss_msg->ctx)
		gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
	else
		task->tk_status = gss_msg->msg.errno;
	gss_cred->gc_upcall = NULL;
	rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
	gss_handle_downcall_result(gss_cred, gss_msg);
	spin_unlock(&inode->i_lock);
	task->tk_status = gss_msg->msg.errno;
	gss_release_msg(gss_msg);
}

@@ -513,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task)
	spin_lock(&inode->i_lock);
	if (gss_cred->gc_upcall != NULL)
		rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
	else if (gss_msg->ctx != NULL) {
		gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
		gss_cred->gc_upcall = NULL;
		rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
	} else if (gss_msg->msg.errno >= 0) {
	else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
		task->tk_timeout = 0;
		gss_cred->gc_upcall = gss_msg;
		/* gss_upcall_callback will release the reference to gss_upcall_msg */
		atomic_inc(&gss_msg->count);
		rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
	} else
	} else {
		gss_handle_downcall_result(gss_cred, gss_msg);
		err = gss_msg->msg.errno;
	}
	spin_unlock(&inode->i_lock);
	gss_release_msg(gss_msg);
out:
@@ -1123,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task)
	return 0;
}

static int gss_cred_is_negative_entry(struct rpc_cred *cred)
{
	if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) {
		unsigned long now = jiffies;
		unsigned long begin, expire;
		struct gss_cred *gss_cred; 

		gss_cred = container_of(cred, struct gss_cred, gc_base);
		begin = gss_cred->gc_upcall_timestamp;
		expire = begin + gss_expired_cred_retry_delay * HZ;

		if (time_in_range_open(now, begin, expire))
			return 1;
	}
	return 0;
}

/*
* Refresh credentials. XXX - finish
*/
@@ -1132,6 +1164,9 @@ gss_refresh(struct rpc_task *task)
	struct rpc_cred *cred = task->tk_msg.rpc_cred;
	int ret = 0;

	if (gss_cred_is_negative_entry(cred))
		return -EKEYEXPIRED;

	if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
			!test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
		ret = gss_renew_cred(task);
@@ -1585,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void)
}

MODULE_LICENSE("GPL");
module_param_named(expired_cred_retry_delay,
		   gss_expired_cred_retry_delay,
		   uint, 0644);
MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until "
		"the RPC engine retries an expired credential");

module_init(init_rpcsec_gss)
module_exit(exit_rpcsec_gss)