From: Martijn de Gouw martijn.de.gouw@prodrive-technologies.com
[ Upstream commit d48c8124749c9a5081fe68680f83605e272c984b ]
When the passed token is longer than 4032 bytes, the remaining part of the token must be copied from the rqstp->rq_arg.pages. But the copy must make sure it happens in a consecutive way.
With the existing code, the first memcpy copies 'length' bytes from argv->iobase, but since the header is in front, this never fills the whole first page of in_token->pages.
The mecpy in the loop copies the following bytes, but starts writing at the next page of in_token->pages. This leaves the last bytes of page 0 unwritten.
Symptoms were that users with many groups were not able to access NFS exports, when using Active Directory as the KDC.
Signed-off-by: Martijn de Gouw martijn.de.gouw@prodrive-technologies.com Fixes: 5866efa8cbfb "SUNRPC: Fix svcauth_gss_proxy_init()" Signed-off-by: J. Bruce Fields bfields@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- net/sunrpc/auth_gss/svcauth_gss.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 68259eec6afd..ab086081be9c 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1079,9 +1079,9 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, struct gssp_in_token *in_token) { struct kvec *argv = &rqstp->rq_arg.head[0]; - unsigned int page_base, length; - int pages, i, res; - size_t inlen; + unsigned int length, pgto_offs, pgfrom_offs; + int pages, i, res, pgto, pgfrom; + size_t inlen, to_offs, from_offs;
res = gss_read_common_verf(gc, argv, authp, in_handle); if (res) @@ -1109,17 +1109,24 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, memcpy(page_address(in_token->pages[0]), argv->iov_base, length); inlen -= length;
- i = 1; - page_base = rqstp->rq_arg.page_base; + to_offs = length; + from_offs = rqstp->rq_arg.page_base; while (inlen) { - length = min_t(unsigned int, inlen, PAGE_SIZE); - memcpy(page_address(in_token->pages[i]), - page_address(rqstp->rq_arg.pages[i]) + page_base, + pgto = to_offs >> PAGE_SHIFT; + pgfrom = from_offs >> PAGE_SHIFT; + pgto_offs = to_offs & ~PAGE_MASK; + pgfrom_offs = from_offs & ~PAGE_MASK; + + length = min_t(unsigned int, inlen, + min_t(unsigned int, PAGE_SIZE - pgto_offs, + PAGE_SIZE - pgfrom_offs)); + memcpy(page_address(in_token->pages[pgto]) + pgto_offs, + page_address(rqstp->rq_arg.pages[pgfrom]) + pgfrom_offs, length);
+ to_offs += length; + from_offs += length; inlen -= length; - page_base = 0; - i++; } return 0; }