Commit 0c77668d authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker
Browse files

SUNRPC: Introduce trace points in rpc_auth_gss.ko



Add infrastructure for trace points in the RPC_AUTH_GSS kernel
module, and add a few sample trace points. These report exceptional
or unexpected events, and observe the assignment of GSS sequence
numbers.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent a0584ee9
Loading
Loading
Loading
Loading
+361 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2018 Oracle.  All rights reserved.
 *
 * Trace point definitions for the "rpcgss" subsystem.
 */

#undef TRACE_SYSTEM
#define TRACE_SYSTEM rpcgss

#if !defined(_TRACE_RPCRDMA_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_RPCGSS_H

#include <linux/tracepoint.h>

/**
 ** GSS-API related trace events
 **/

TRACE_DEFINE_ENUM(GSS_S_BAD_MECH);
TRACE_DEFINE_ENUM(GSS_S_BAD_NAME);
TRACE_DEFINE_ENUM(GSS_S_BAD_NAMETYPE);
TRACE_DEFINE_ENUM(GSS_S_BAD_BINDINGS);
TRACE_DEFINE_ENUM(GSS_S_BAD_STATUS);
TRACE_DEFINE_ENUM(GSS_S_BAD_SIG);
TRACE_DEFINE_ENUM(GSS_S_NO_CRED);
TRACE_DEFINE_ENUM(GSS_S_NO_CONTEXT);
TRACE_DEFINE_ENUM(GSS_S_DEFECTIVE_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_DEFECTIVE_CREDENTIAL);
TRACE_DEFINE_ENUM(GSS_S_CREDENTIALS_EXPIRED);
TRACE_DEFINE_ENUM(GSS_S_CONTEXT_EXPIRED);
TRACE_DEFINE_ENUM(GSS_S_FAILURE);
TRACE_DEFINE_ENUM(GSS_S_BAD_QOP);
TRACE_DEFINE_ENUM(GSS_S_UNAUTHORIZED);
TRACE_DEFINE_ENUM(GSS_S_UNAVAILABLE);
TRACE_DEFINE_ENUM(GSS_S_DUPLICATE_ELEMENT);
TRACE_DEFINE_ENUM(GSS_S_NAME_NOT_MN);
TRACE_DEFINE_ENUM(GSS_S_CONTINUE_NEEDED);
TRACE_DEFINE_ENUM(GSS_S_DUPLICATE_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_OLD_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_UNSEQ_TOKEN);
TRACE_DEFINE_ENUM(GSS_S_GAP_TOKEN);

#define show_gss_status(x)						\
	__print_flags(x, "|",						\
		{ GSS_S_BAD_MECH, "GSS_S_BAD_MECH" },			\
		{ GSS_S_BAD_NAME, "GSS_S_BAD_NAME" },			\
		{ GSS_S_BAD_NAMETYPE, "GSS_S_BAD_NAMETYPE" },		\
		{ GSS_S_BAD_BINDINGS, "GSS_S_BAD_BINDINGS" },		\
		{ GSS_S_BAD_STATUS, "GSS_S_BAD_STATUS" },		\
		{ GSS_S_BAD_SIG, "GSS_S_BAD_SIG" },			\
		{ GSS_S_NO_CRED, "GSS_S_NO_CRED" },			\
		{ GSS_S_NO_CONTEXT, "GSS_S_NO_CONTEXT" },		\
		{ GSS_S_DEFECTIVE_TOKEN, "GSS_S_DEFECTIVE_TOKEN" },	\
		{ GSS_S_DEFECTIVE_CREDENTIAL, "GSS_S_DEFECTIVE_CREDENTIAL" }, \
		{ GSS_S_CREDENTIALS_EXPIRED, "GSS_S_CREDENTIALS_EXPIRED" }, \
		{ GSS_S_CONTEXT_EXPIRED, "GSS_S_CONTEXT_EXPIRED" },	\
		{ GSS_S_FAILURE, "GSS_S_FAILURE" },			\
		{ GSS_S_BAD_QOP, "GSS_S_BAD_QOP" },			\
		{ GSS_S_UNAUTHORIZED, "GSS_S_UNAUTHORIZED" },		\
		{ GSS_S_UNAVAILABLE, "GSS_S_UNAVAILABLE" },		\
		{ GSS_S_DUPLICATE_ELEMENT, "GSS_S_DUPLICATE_ELEMENT" },	\
		{ GSS_S_NAME_NOT_MN, "GSS_S_NAME_NOT_MN" },		\
		{ GSS_S_CONTINUE_NEEDED, "GSS_S_CONTINUE_NEEDED" },	\
		{ GSS_S_DUPLICATE_TOKEN, "GSS_S_DUPLICATE_TOKEN" },	\
		{ GSS_S_OLD_TOKEN, "GSS_S_OLD_TOKEN" },			\
		{ GSS_S_UNSEQ_TOKEN, "GSS_S_UNSEQ_TOKEN" },		\
		{ GSS_S_GAP_TOKEN, "GSS_S_GAP_TOKEN" })


DECLARE_EVENT_CLASS(rpcgss_gssapi_event,
	TP_PROTO(
		const struct rpc_task *task,
		u32 maj_stat
	),

	TP_ARGS(task, maj_stat),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, maj_stat)

	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->maj_stat = maj_stat;
	),

	TP_printk("task:%u@%u maj_stat=%s",
		__entry->task_id, __entry->client_id,
		__entry->maj_stat == 0 ?
		"GSS_S_COMPLETE" : show_gss_status(__entry->maj_stat))
);

#define DEFINE_GSSAPI_EVENT(name)					\
	DEFINE_EVENT(rpcgss_gssapi_event, rpcgss_##name,		\
			TP_PROTO(					\
				const struct rpc_task *task,		\
				u32 maj_stat				\
			),						\
			TP_ARGS(task, maj_stat))

TRACE_EVENT(rpcgss_import_ctx,
	TP_PROTO(
		int status
	),

	TP_ARGS(status),

	TP_STRUCT__entry(
		__field(int, status)
	),

	TP_fast_assign(
		__entry->status = status;
	),

	TP_printk("status=%d", __entry->status)
);

DEFINE_GSSAPI_EVENT(get_mic);
DEFINE_GSSAPI_EVENT(verify_mic);
DEFINE_GSSAPI_EVENT(wrap);
DEFINE_GSSAPI_EVENT(unwrap);


/**
 ** GSS auth unwrap failures
 **/

TRACE_EVENT(rpcgss_unwrap_failed,
	TP_PROTO(
		const struct rpc_task *task
	),

	TP_ARGS(task),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
	),

	TP_printk("task:%u@%u", __entry->task_id, __entry->client_id)
);

TRACE_EVENT(rpcgss_bad_seqno,
	TP_PROTO(
		const struct rpc_task *task,
		u32 expected,
		u32 received
	),

	TP_ARGS(task, expected, received),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, expected)
		__field(u32, received)
	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->expected = expected;
		__entry->received = received;
	),

	TP_printk("task:%u@%u expected seqno %u, received seqno %u",
		__entry->task_id, __entry->client_id,
		__entry->expected, __entry->received)
);

TRACE_EVENT(rpcgss_seqno,
	TP_PROTO(
		const struct rpc_task *task
	),

	TP_ARGS(task),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, xid)
		__field(u32, seqno)
	),

	TP_fast_assign(
		const struct rpc_rqst *rqst = task->tk_rqstp;

		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->xid = be32_to_cpu(rqst->rq_xid);
		__entry->seqno = rqst->rq_seqno;
	),

	TP_printk("task:%u@%u xid=0x%08x seqno=%u",
		__entry->task_id, __entry->client_id,
		__entry->xid, __entry->seqno)
);

TRACE_EVENT(rpcgss_need_reencode,
	TP_PROTO(
		const struct rpc_task *task,
		u32 seq_xmit,
		bool ret
	),

	TP_ARGS(task, seq_xmit, ret),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, xid)
		__field(u32, seq_xmit)
		__field(u32, seqno)
		__field(bool, ret)
	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid);
		__entry->seq_xmit = seq_xmit;
		__entry->seqno = task->tk_rqstp->rq_seqno;
		__entry->ret = ret;
	),

	TP_printk("task:%u@%u xid=0x%08x rq_seqno=%u seq_xmit=%u reencode %sneeded",
		__entry->task_id, __entry->client_id,
		__entry->xid, __entry->seqno, __entry->seq_xmit,
		__entry->ret ? "" : "un")
);

/**
 ** gssd upcall related trace events
 **/

TRACE_EVENT(rpcgss_upcall_msg,
	TP_PROTO(
		const char *buf
	),

	TP_ARGS(buf),

	TP_STRUCT__entry(
		__string(msg, buf)
	),

	TP_fast_assign(
		__assign_str(msg, buf)
	),

	TP_printk("msg='%s'", __get_str(msg))
);

TRACE_EVENT(rpcgss_upcall_result,
	TP_PROTO(
		u32 uid,
		int result
	),

	TP_ARGS(uid, result),

	TP_STRUCT__entry(
		__field(u32, uid)
		__field(int, result)

	),

	TP_fast_assign(
		__entry->uid = uid;
		__entry->result = result;
	),

	TP_printk("for uid %u, result=%d", __entry->uid, __entry->result)
);

TRACE_EVENT(rpcgss_context,
	TP_PROTO(
		unsigned long expiry,
		unsigned long now,
		unsigned int timeout,
		unsigned int len,
		const u8 *data
	),

	TP_ARGS(expiry, now, timeout, len, data),

	TP_STRUCT__entry(
		__field(unsigned long, expiry)
		__field(unsigned long, now)
		__field(unsigned int, timeout)
		__field(int, len)
		__string(acceptor, data)
	),

	TP_fast_assign(
		__entry->expiry = expiry;
		__entry->now = now;
		__entry->timeout = timeout;
		__entry->len = len;
		strncpy(__get_str(acceptor), data, len);
	),

	TP_printk("gc_expiry=%lu now=%lu timeout=%u acceptor=%.*s",
		__entry->expiry, __entry->now, __entry->timeout,
		__entry->len, __get_str(acceptor))
);


/**
 ** Miscellaneous events
 */

TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5);
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I);
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P);

#define show_pseudoflavor(x)						\
	__print_symbolic(x,						\
		{ RPC_AUTH_GSS_KRB5, "RPC_AUTH_GSS_KRB5" },		\
		{ RPC_AUTH_GSS_KRB5I, "RPC_AUTH_GSS_KRB5I" },		\
		{ RPC_AUTH_GSS_KRB5P, "RPC_AUTH_GSS_KRB5P" })


TRACE_EVENT(rpcgss_createauth,
	TP_PROTO(
		unsigned int flavor,
		int error
	),

	TP_ARGS(flavor, error),

	TP_STRUCT__entry(
		__field(unsigned int, flavor)
		__field(int, error)

	),

	TP_fast_assign(
		__entry->flavor = flavor;
		__entry->error = error;
	),

	TP_printk("flavor=%s error=%d",
		show_pseudoflavor(__entry->flavor), __entry->error)
);


#endif	/* _TRACE_RPCGSS_H */

#include <trace/define_trace.h>
+10 −2
Original line number Diff line number Diff line
@@ -521,12 +521,18 @@ TRACE_EVENT(xprtrdma_post_send,

	TP_STRUCT__entry(
		__field(const void *, req)
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(int, num_sge)
		__field(int, signaled)
		__field(int, status)
	),

	TP_fast_assign(
		const struct rpc_rqst *rqst = &req->rl_slot;

		__entry->task_id = rqst->rq_task->tk_pid;
		__entry->client_id = rqst->rq_task->tk_client->cl_clid;
		__entry->req = req;
		__entry->num_sge = req->rl_sendctx->sc_wr.num_sge;
		__entry->signaled = req->rl_sendctx->sc_wr.send_flags &
@@ -534,9 +540,11 @@ TRACE_EVENT(xprtrdma_post_send,
		__entry->status = status;
	),

	TP_printk("req=%p, %d SGEs%s, status=%d",
	TP_printk("task:%u@%u req=%p (%d SGE%s) %sstatus=%d",
		__entry->task_id, __entry->client_id,
		__entry->req, __entry->num_sge,
		(__entry->signaled ? ", signaled" : ""),
		(__entry->num_sge == 1 ? "" : "s"),
		(__entry->signaled ? "signaled " : ""),
		__entry->status
	)
);
+60 −1
Original line number Diff line number Diff line
@@ -655,9 +655,68 @@ DECLARE_EVENT_CLASS(rpc_xprt_event,

DEFINE_RPC_XPRT_EVENT(timer);
DEFINE_RPC_XPRT_EVENT(lookup_rqst);
DEFINE_RPC_XPRT_EVENT(transmit);
DEFINE_RPC_XPRT_EVENT(complete_rqst);

TRACE_EVENT(xprt_transmit,
	TP_PROTO(
		const struct rpc_rqst *rqst,
		int status
	),

	TP_ARGS(rqst, status),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, xid)
		__field(u32, seqno)
		__field(int, status)
	),

	TP_fast_assign(
		__entry->task_id = rqst->rq_task->tk_pid;
		__entry->client_id = rqst->rq_task->tk_client->cl_clid;
		__entry->xid = be32_to_cpu(rqst->rq_xid);
		__entry->seqno = rqst->rq_seqno;
		__entry->status = status;
	),

	TP_printk(
		"task:%u@%u xid=0x%08x seqno=%u status=%d",
		__entry->task_id, __entry->client_id, __entry->xid,
		__entry->seqno, __entry->status)
);

TRACE_EVENT(xprt_enq_xmit,
	TP_PROTO(
		const struct rpc_task *task,
		int stage
	),

	TP_ARGS(task, stage),

	TP_STRUCT__entry(
		__field(unsigned int, task_id)
		__field(unsigned int, client_id)
		__field(u32, xid)
		__field(u32, seqno)
		__field(int, stage)
	),

	TP_fast_assign(
		__entry->task_id = task->tk_pid;
		__entry->client_id = task->tk_client->cl_clid;
		__entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid);
		__entry->seqno = task->tk_rqstp->rq_seqno;
		__entry->stage = stage;
	),

	TP_printk(
		"task:%u@%u xid=0x%08x seqno=%u stage=%d",
		__entry->task_id, __entry->client_id, __entry->xid,
		__entry->seqno, __entry->stage)
);

TRACE_EVENT(xprt_ping,
	TP_PROTO(const struct rpc_xprt *xprt, int status),

+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o

auth_rpcgss-y := auth_gss.o gss_generic_token.o \
	gss_mech_switch.o svcauth_gss.o \
	gss_rpc_upcall.o gss_rpc_xdr.o
	gss_rpc_upcall.o gss_rpc_xdr.o trace.o

obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o

+81 −84
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@

#include "../netns.h"

#include <trace/events/rpcgss.h>

static const struct rpc_authops authgss_ops;

static const struct rpc_credops gss_credops;
@@ -260,6 +262,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
	}
	ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS);
	if (ret < 0) {
		trace_rpcgss_import_ctx(ret);
		p = ERR_PTR(ret);
		goto err;
	}
@@ -275,12 +278,9 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
	if (IS_ERR(p))
		goto err;
done:
	dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n",
		__func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len,
		ctx->gc_acceptor.data);
	return p;
	trace_rpcgss_context(ctx->gc_expiry, now, timeout,
			     ctx->gc_acceptor.len, ctx->gc_acceptor.data);
err:
	dprintk("RPC:       %s returns error %ld\n", __func__, -PTR_ERR(p));
	return p;
}

@@ -354,10 +354,8 @@ __gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth
		if (auth && pos->auth->service != auth->service)
			continue;
		refcount_inc(&pos->count);
		dprintk("RPC:       %s found msg %p\n", __func__, pos);
		return pos;
	}
	dprintk("RPC:       %s found nothing\n", __func__);
	return NULL;
}

@@ -506,11 +504,11 @@ static int gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
		p += len;
		gss_msg->msg.len += len;
	}
	trace_rpcgss_upcall_msg(gss_msg->databuf);
	len = scnprintf(p, buflen, "\n");
	if (len == 0)
		goto out_overflow;
	gss_msg->msg.len += len;

	gss_msg->msg.data = gss_msg->databuf;
	return 0;
out_overflow:
@@ -603,8 +601,6 @@ gss_refresh_upcall(struct rpc_task *task)
	struct rpc_pipe *pipe;
	int err = 0;

	dprintk("RPC: %5u %s for uid %u\n",
		task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_cred->fsuid));
	gss_msg = gss_setup_upcall(gss_auth, cred);
	if (PTR_ERR(gss_msg) == -EAGAIN) {
		/* XXX: warning on the first, under the assumption we
@@ -612,7 +608,8 @@ gss_refresh_upcall(struct rpc_task *task)
		warn_gssd();
		task->tk_timeout = 15*HZ;
		rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL);
		return -EAGAIN;
		err = -EAGAIN;
		goto out;
	}
	if (IS_ERR(gss_msg)) {
		err = PTR_ERR(gss_msg);
@@ -635,9 +632,8 @@ gss_refresh_upcall(struct rpc_task *task)
	spin_unlock(&pipe->lock);
	gss_release_msg(gss_msg);
out:
	dprintk("RPC: %5u %s for uid %u result %d\n",
		task->tk_pid, __func__,
		from_kuid(&init_user_ns, cred->cr_cred->fsuid),	err);
	trace_rpcgss_upcall_result(from_kuid(&init_user_ns,
					     cred->cr_cred->fsuid), err);
	return err;
}

@@ -652,14 +648,13 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
	DEFINE_WAIT(wait);
	int err;

	dprintk("RPC:       %s for uid %u\n",
		__func__, from_kuid(&init_user_ns, cred->cr_cred->fsuid));
retry:
	err = 0;
	/* if gssd is down, just skip upcalling altogether */
	if (!gssd_running(net)) {
		warn_gssd();
		return -EACCES;
		err = -EACCES;
		goto out;
	}
	gss_msg = gss_setup_upcall(gss_auth, cred);
	if (PTR_ERR(gss_msg) == -EAGAIN) {
@@ -700,8 +695,8 @@ out_intr:
	finish_wait(&gss_msg->waitqueue, &wait);
	gss_release_msg(gss_msg);
out:
	dprintk("RPC:       %s for uid %u result %d\n",
		__func__, from_kuid(&init_user_ns, cred->cr_cred->fsuid), err);
	trace_rpcgss_upcall_result(from_kuid(&init_user_ns,
					     cred->cr_cred->fsuid), err);
	return err;
}

@@ -794,7 +789,6 @@ err_put_ctx:
err:
	kfree(buf);
out:
	dprintk("RPC:       %s returning %zd\n", __func__, err);
	return err;
}

@@ -863,8 +857,6 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
	struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg);

	if (msg->errno < 0) {
		dprintk("RPC:       %s releasing msg %p\n",
			__func__, gss_msg);
		refcount_inc(&gss_msg->count);
		gss_unhash_msg(gss_msg);
		if (msg->errno == -ETIMEDOUT)
@@ -1024,8 +1016,6 @@ gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
	struct rpc_auth * auth;
	int err = -ENOMEM; /* XXX? */

	dprintk("RPC:       creating GSS authenticator for client %p\n", clnt);

	if (!try_module_get(THIS_MODULE))
		return ERR_PTR(err);
	if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
@@ -1041,10 +1031,8 @@ gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
	gss_auth->net = get_net(rpc_net_ns(clnt));
	err = -EINVAL;
	gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
	if (!gss_auth->mech) {
		dprintk("RPC:       Pseudoflavor %d not found!\n", flavor);
	if (!gss_auth->mech)
		goto err_put_net;
	}
	gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
	if (gss_auth->service == 0)
		goto err_put_mech;
@@ -1099,6 +1087,7 @@ err_free:
	kfree(gss_auth);
out_dec:
	module_put(THIS_MODULE);
	trace_rpcgss_createauth(flavor, err);
	return ERR_PTR(err);
}

@@ -1135,9 +1124,6 @@ gss_destroy(struct rpc_auth *auth)
	struct gss_auth *gss_auth = container_of(auth,
			struct gss_auth, rpc_auth);

	dprintk("RPC:       destroying GSS authenticator %p flavor %d\n",
			auth, auth->au_flavor);

	if (hash_hashed(&gss_auth->hash)) {
		spin_lock(&gss_auth_hash_lock);
		hash_del(&gss_auth->hash);
@@ -1300,8 +1286,6 @@ gss_send_destroy_context(struct rpc_cred *cred)
static void
gss_do_free_ctx(struct gss_cl_ctx *ctx)
{
	dprintk("RPC:       %s\n", __func__);

	gss_delete_sec_context(&ctx->gc_gss_ctx);
	kfree(ctx->gc_wire_ctx.data);
	kfree(ctx->gc_acceptor.data);
@@ -1324,7 +1308,6 @@ gss_free_ctx(struct gss_cl_ctx *ctx)
static void
gss_free_cred(struct gss_cred *gss_cred)
{
	dprintk("RPC:       %s cred=%p\n", __func__, gss_cred);
	kfree(gss_cred);
}

@@ -1381,10 +1364,6 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t
	struct gss_cred	*cred = NULL;
	int err = -ENOMEM;

	dprintk("RPC:       %s for uid %d, flavor %d\n",
		__func__, from_kuid(&init_user_ns, acred->cred->fsuid),
		auth->au_flavor);

	if (!(cred = kzalloc(sizeof(*cred), gfp)))
		goto out_err;

@@ -1400,7 +1379,6 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t
	return &cred->gc_base;

out_err:
	dprintk("RPC:       %s failed with error %d\n", __func__, err);
	return ERR_PTR(err);
}

@@ -1544,15 +1522,14 @@ static int gss_marshal(struct rpc_task *task, struct xdr_stream *xdr)
	struct xdr_netobj mic;
	struct kvec	iov;
	struct xdr_buf	verf_buf;

	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
	int status;

	/* Credential */

	p = xdr_reserve_space(xdr, 7 * sizeof(*p) +
			      ctx->gc_wire_ctx.len);
	if (!p)
		goto out_put_ctx;
		goto marshal_failed;
	*p++ = rpc_auth_gss;
	cred_len = p++;

@@ -1560,7 +1537,8 @@ static int gss_marshal(struct rpc_task *task, struct xdr_stream *xdr)
	req->rq_seqno = (ctx->gc_seq < MAXSEQ) ? ctx->gc_seq++ : MAXSEQ;
	spin_unlock(&ctx->gc_seq_lock);
	if (req->rq_seqno == MAXSEQ)
		goto out_expired;
		goto expired;
	trace_rpcgss_seqno(task);

	*p++ = cpu_to_be32(RPC_GSS_VERSION);
	*p++ = cpu_to_be32(ctx->gc_proc);
@@ -1579,25 +1557,31 @@ static int gss_marshal(struct rpc_task *task, struct xdr_stream *xdr)

	p = xdr_reserve_space(xdr, sizeof(*p));
	if (!p)
		goto out_put_ctx;
		goto marshal_failed;
	*p++ = rpc_auth_gss;
	mic.data = (u8 *)(p + 1);
	maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
		goto out_expired;
		goto expired;
	else if (maj_stat != 0)
		goto out_put_ctx;
		goto bad_mic;
	if (xdr_stream_encode_opaque_inline(xdr, (void **)&p, mic.len) < 0)
		goto out_put_ctx;
	gss_put_ctx(ctx);
	return 0;
out_expired:
		goto marshal_failed;
	status = 0;
out:
	gss_put_ctx(ctx);
	return status;
expired:
	clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
	return -EKEYEXPIRED;
out_put_ctx:
	gss_put_ctx(ctx);
	return -EMSGSIZE;
	status = -EKEYEXPIRED;
	goto out;
marshal_failed:
	status = -EMSGSIZE;
	goto out;
bad_mic:
	trace_rpcgss_get_mic(task, maj_stat);
	status = -EIO;
	goto out;
}

static int gss_renew_cred(struct rpc_task *task)
@@ -1723,8 +1707,7 @@ validate_failed:
	status = -EIO;
	goto out;
bad_mic:
	dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
		task->tk_pid, __func__, maj_stat);
	trace_rpcgss_verify_mic(task, maj_stat);
	status = -EACCES;
	goto out;
}
@@ -1761,13 +1744,16 @@ static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
	else if (maj_stat)
		goto wrap_failed;
		goto bad_mic;
	/* Check that the trailing MIC fit in the buffer, after the fact */
	if (xdr_stream_encode_opaque_inline(xdr, (void **)&p, mic.len) < 0)
		goto wrap_failed;
	return 0;
wrap_failed:
	return -EMSGSIZE;
bad_mic:
	trace_rpcgss_get_mic(task, maj_stat);
	return -EIO;
}

static void
@@ -1860,7 +1846,6 @@ static int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
		snd_buf->tail[0].iov_base = tmp;
	}
	status = -EIO;
	offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
	maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
	/* slack space should prevent this ever happening: */
@@ -1871,7 +1856,7 @@ static int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
	else if (maj_stat)
		goto wrap_failed;
		goto bad_wrap;

	*opaque_len = cpu_to_be32(snd_buf->len - offset);
	/* guess whether the pad goes into the head or the tail: */
@@ -1888,6 +1873,9 @@ static int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
	return 0;
wrap_failed:
	return status;
bad_wrap:
	trace_rpcgss_wrap(task, maj_stat);
	return -EIO;
}

static int gss_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
@@ -1898,7 +1886,6 @@ static int gss_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
	int status;

	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
	status = -EIO;
	if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
		/* The spec seems a little ambiguous here, but I think that not
@@ -1917,10 +1904,11 @@ static int gss_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
	case RPC_GSS_SVC_PRIVACY:
		status = gss_wrap_req_priv(cred, ctx, task, xdr);
		break;
	default:
		status = -EIO;
	}
out:
	gss_put_ctx(ctx);
	dprintk("RPC: %5u %s returning %d\n", task->tk_pid, __func__, status);
	return status;
}

@@ -1932,8 +1920,9 @@ gss_unwrap_resp_auth(struct rpc_cred *cred)
}

static int
gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		      struct rpc_rqst *rqstp, struct xdr_stream *xdr)
gss_unwrap_resp_integ(struct rpc_task *task, struct rpc_cred *cred,
		      struct gss_cl_ctx *ctx, struct rpc_rqst *rqstp,
		      struct xdr_stream *xdr)
{
	struct xdr_buf integ_buf, *rcv_buf = &rqstp->rq_rcv_buf;
	u32 data_offset, mic_offset, integ_len, maj_stat;
@@ -1951,7 +1940,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
	if (mic_offset > rcv_buf->len)
		goto unwrap_failed;
	if (be32_to_cpup(p) != rqstp->rq_seqno)
		goto unwrap_failed;
		goto bad_seqno;

	if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, integ_len))
		goto unwrap_failed;
@@ -1967,16 +1956,20 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
				   1 + XDR_QUADLEN(mic.len);
	return 0;
unwrap_failed:
	trace_rpcgss_unwrap_failed(task);
	return -EIO;
bad_seqno:
	trace_rpcgss_bad_seqno(task, rqstp->rq_seqno, be32_to_cpup(p));
	return -EIO;
bad_mic:
	dprintk("RPC:       %s: gss_verify_mic returned error 0x%08x\n",
		__func__, maj_stat);
	trace_rpcgss_verify_mic(task, maj_stat);
	return -EIO;
}

static int
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		     struct rpc_rqst *rqstp, struct xdr_stream *xdr)
gss_unwrap_resp_priv(struct rpc_task *task, struct rpc_cred *cred,
		     struct gss_cl_ctx *ctx, struct rpc_rqst *rqstp,
		     struct xdr_stream *xdr)
{
	struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
	struct kvec *head = rqstp->rq_rcv_buf.head;
@@ -2000,7 +1993,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
		goto bad_unwrap;
	/* gss_unwrap decrypted the sequence number */
	if (be32_to_cpup(p++) != rqstp->rq_seqno)
		goto unwrap_failed;
		goto bad_seqno;

	/* gss_unwrap redacts the opaque blob from the head iovec.
	 * rcv_buf has changed, thus the stream needs to be reset.
@@ -2011,10 +2004,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
				   XDR_QUADLEN(savedlen - rcv_buf->len);
	return 0;
unwrap_failed:
	trace_rpcgss_unwrap_failed(task);
	return -EIO;
bad_seqno:
	trace_rpcgss_bad_seqno(task, rqstp->rq_seqno, be32_to_cpup(--p));
	return -EIO;
bad_unwrap:
	dprintk("RPC:       %s: gss_unwrap returned error 0x%08x\n",
		__func__, maj_stat);
	trace_rpcgss_unwrap(task, maj_stat);
	return -EIO;
}

@@ -2030,14 +2026,14 @@ gss_xmit_need_reencode(struct rpc_task *task)
	struct rpc_rqst *req = task->tk_rqstp;
	struct rpc_cred *cred = req->rq_cred;
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
	u32 win, seq_xmit;
	u32 win, seq_xmit = 0;
	bool ret = true;

	if (!ctx)
		return true;
		goto out;

	if (gss_seq_is_newer(req->rq_seqno, READ_ONCE(ctx->gc_seq)))
		goto out;
		goto out_ctx;

	seq_xmit = READ_ONCE(ctx->gc_seq_xmit);
	while (gss_seq_is_newer(req->rq_seqno, seq_xmit)) {
@@ -2046,15 +2042,18 @@ gss_xmit_need_reencode(struct rpc_task *task)
		seq_xmit = cmpxchg(&ctx->gc_seq_xmit, tmp, req->rq_seqno);
		if (seq_xmit == tmp) {
			ret = false;
			goto out;
			goto out_ctx;
		}
	}

	win = ctx->gc_win;
	if (win > 0)
		ret = !gss_seq_is_newer(req->rq_seqno, seq_xmit - win);
out:

out_ctx:
	gss_put_ctx(ctx);
out:
	trace_rpcgss_need_reencode(task, seq_xmit, ret);
	return ret;
}

@@ -2075,10 +2074,10 @@ gss_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
		status = gss_unwrap_resp_auth(cred);
		break;
	case RPC_GSS_SVC_INTEGRITY:
		status = gss_unwrap_resp_integ(cred, ctx, rqstp, xdr);
		status = gss_unwrap_resp_integ(task, cred, ctx, rqstp, xdr);
		break;
	case RPC_GSS_SVC_PRIVACY:
		status = gss_unwrap_resp_priv(cred, ctx, rqstp, xdr);
		status = gss_unwrap_resp_priv(task, cred, ctx, rqstp, xdr);
		break;
	}
	if (status)
@@ -2088,8 +2087,6 @@ out_decode:
	status = rpcauth_unwrap_resp_decode(task, xdr);
out:
	gss_put_ctx(ctx);
	dprintk("RPC: %5u %s returning %d\n",
		task->tk_pid, __func__, status);
	return status;
}

Loading