Skip to content

Commit 5f1bc39

Browse files
bcodding-rhamschuma-ntap
authored andcommitted
SUNRPC: Fix buffer handling of GSS MIC without slack
The GSS Message Integrity Check data for krb5i may lie partially in the XDR reply buffer's pages and tail. If so, we try to copy the entire MIC into free space in the tail. But as the estimations of the slack space required for authentication and verification have improved there may be less free space in the tail to complete this copy -- see commit 2c94b8e ("SUNRPC: Use au_rslack when computing reply buffer size"). In fact, there may only be room in the tail for a single copy of the MIC, and not part of the MIC and then another complete copy. The real world failure reported is that `ls` of a directory on NFS may sometimes return -EIO, which can be traced back to xdr_buf_read_netobj() failing to find available free space in the tail to copy the MIC. Fix this by checking for the case of the MIC crossing the boundaries of head, pages, and tail. If so, shift the buffer until the MIC is contained completely within the pages or tail. This allows the remainder of the function to create a sub buffer that directly address the complete MIC. Signed-off-by: Benjamin Coddington <bcodding@redhat.com> Cc: stable@vger.kernel.org # v5.1 Reviewed-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
1 parent 714fbc7 commit 5f1bc39

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

net/sunrpc/xdr.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,16 +1237,29 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
12371237
EXPORT_SYMBOL_GPL(xdr_encode_word);
12381238

12391239
/* If the netobj starting offset bytes from the start of xdr_buf is contained
1240-
* entirely in the head or the tail, set object to point to it; otherwise
1241-
* try to find space for it at the end of the tail, copy it there, and
1242-
* set obj to point to it. */
1240+
* entirely in the head, pages, or tail, set object to point to it; otherwise
1241+
* shift the buffer until it is contained entirely within the pages or tail.
1242+
*/
12431243
int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
12441244
{
12451245
struct xdr_buf subbuf;
1246+
unsigned int boundary;
12461247

12471248
if (xdr_decode_word(buf, offset, &obj->len))
12481249
return -EFAULT;
1249-
if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))
1250+
offset += 4;
1251+
1252+
/* Is the obj partially in the head? */
1253+
boundary = buf->head[0].iov_len;
1254+
if (offset < boundary && (offset + obj->len) > boundary)
1255+
xdr_shift_buf(buf, boundary - offset);
1256+
1257+
/* Is the obj partially in the pages? */
1258+
boundary += buf->page_len;
1259+
if (offset < boundary && (offset + obj->len) > boundary)
1260+
xdr_shrink_pagelen(buf, boundary - offset);
1261+
1262+
if (xdr_buf_subsegment(buf, &subbuf, offset, obj->len))
12501263
return -EFAULT;
12511264

12521265
/* Is the obj contained entirely in the head? */
@@ -1258,11 +1271,7 @@ int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned in
12581271
if (subbuf.tail[0].iov_len == obj->len)
12591272
return 0;
12601273

1261-
/* use end of tail as storage for obj:
1262-
* (We don't copy to the beginning because then we'd have
1263-
* to worry about doing a potentially overlapping copy.
1264-
* This assumes the object is at most half the length of the
1265-
* tail.) */
1274+
/* Find a contiguous area in @buf to hold all of @obj */
12661275
if (obj->len > buf->buflen - buf->len)
12671276
return -ENOMEM;
12681277
if (buf->tail[0].iov_len != 0)

0 commit comments

Comments
 (0)