Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SUNRPC: Fix GSS privacy computation of auth->au_ralign

When the au_ralign field was added to gss_unwrap_resp_priv, the
wrong calculation was used. Setting au_rslack == au_ralign is
probably correct for kerberos_v1 privacy, but kerberos_v2 privacy
adds additional GSS data after the clear text RPC message.
au_ralign needs to be smaller than au_rslack in that fairly common
case.

When xdr_buf_trim() is restored to gss_unwrap_kerberos_v2(), it does
exactly what I feared it would: it trims off part of the clear text
RPC message. However, that's because rpc_prepare_reply_pages() does
not set up the rq_rcv_buf's tail correctly because au_ralign is too
large.

Fixing the au_ralign computation also corrects the alignment of
rq_rcv_buf->pages so that the client does not have to shift reply
data payloads after they are received.

Fixes: 35e77d21baa0 ("SUNRPC: Add rpc_auth::au_ralign field")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

+19 -9
+1
include/linux/sunrpc/gss_api.h
··· 21 21 struct gss_ctx { 22 22 struct gss_api_mech *mech_type; 23 23 void *internal_ctx_id; 24 + unsigned int slack, align; 24 25 }; 25 26 26 27 #define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
+3 -5
net/sunrpc/auth_gss/auth_gss.c
··· 2032 2032 struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; 2033 2033 struct kvec *head = rqstp->rq_rcv_buf.head; 2034 2034 struct rpc_auth *auth = cred->cr_auth; 2035 - unsigned int savedlen = rcv_buf->len; 2036 2035 u32 offset, opaque_len, maj_stat; 2037 2036 __be32 *p; 2038 2037 ··· 2058 2059 */ 2059 2060 xdr_init_decode(xdr, rcv_buf, p, rqstp); 2060 2061 2061 - auth->au_rslack = auth->au_verfsize + 2 + 2062 - XDR_QUADLEN(savedlen - rcv_buf->len); 2063 - auth->au_ralign = auth->au_verfsize + 2 + 2064 - XDR_QUADLEN(savedlen - rcv_buf->len); 2062 + auth->au_rslack = auth->au_verfsize + 2 + ctx->gc_gss_ctx->slack; 2063 + auth->au_ralign = auth->au_verfsize + 2 + ctx->gc_gss_ctx->align; 2064 + 2065 2065 return 0; 2066 2066 unwrap_failed: 2067 2067 trace_rpcgss_unwrap_failed(task);
+15 -4
net/sunrpc/auth_gss/gss_krb5_wrap.c
··· 262 262 263 263 static u32 264 264 gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, int len, 265 - struct xdr_buf *buf) 265 + struct xdr_buf *buf, unsigned int *slack, 266 + unsigned int *align) 266 267 { 267 268 int signalg; 268 269 int sealalg; ··· 281 280 u32 conflen = kctx->gk5e->conflen; 282 281 int crypt_offset; 283 282 u8 *cksumkey; 283 + unsigned int saved_len = buf->len; 284 284 285 285 dprintk("RPC: gss_unwrap_kerberos\n"); 286 286 ··· 385 383 if (gss_krb5_remove_padding(buf, blocksize)) 386 384 return GSS_S_DEFECTIVE_TOKEN; 387 385 386 + /* slack must include room for krb5 padding */ 387 + *slack = XDR_QUADLEN(saved_len - buf->len); 388 + /* The GSS blob always precedes the RPC message payload */ 389 + *align = *slack; 388 390 return GSS_S_COMPLETE; 389 391 } 390 392 ··· 495 489 496 490 static u32 497 491 gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, int len, 498 - struct xdr_buf *buf) 492 + struct xdr_buf *buf, unsigned int *slack, 493 + unsigned int *align) 499 494 { 500 495 time64_t now; 501 496 u8 *ptr; ··· 590 583 /* Trim off the trailing "extra count" and checksum blob */ 591 584 buf->len -= ec + GSS_KRB5_TOK_HDR_LEN + tailskip; 592 585 586 + *align = XDR_QUADLEN(GSS_KRB5_TOK_HDR_LEN + headskip); 587 + *slack = *align + XDR_QUADLEN(ec + GSS_KRB5_TOK_HDR_LEN + tailskip); 593 588 return GSS_S_COMPLETE; 594 589 } 595 590 ··· 626 617 case ENCTYPE_DES_CBC_RAW: 627 618 case ENCTYPE_DES3_CBC_RAW: 628 619 case ENCTYPE_ARCFOUR_HMAC: 629 - return gss_unwrap_kerberos_v1(kctx, offset, len, buf); 620 + return gss_unwrap_kerberos_v1(kctx, offset, len, buf, 621 + &gctx->slack, &gctx->align); 630 622 case ENCTYPE_AES128_CTS_HMAC_SHA1_96: 631 623 case ENCTYPE_AES256_CTS_HMAC_SHA1_96: 632 - return gss_unwrap_kerberos_v2(kctx, offset, len, buf); 624 + return gss_unwrap_kerberos_v2(kctx, offset, len, buf, 625 + &gctx->slack, &gctx->align); 633 626 } 634 627 }