| From 3a6308af7c7b5e68ae9ea1f677aab150f00f45f6 Mon Sep 17 00:00:00 2001 |
| From: David Howells <dhowells@redhat.com> |
| Date: Wed, 8 Apr 2020 16:13:20 +0100 |
| Subject: [PATCH] afs: Fix missing XDR advance in |
| xdr_decode_{AFS,YFS}FSFetchStatus() |
| |
| commit c72057b56f7e24865840a6961d801a7f21d30a5f upstream. |
| |
| If we receive a status record that has VNOVNODE set in the abort field, |
| xdr_decode_AFSFetchStatus() and xdr_decode_YFSFetchStatus() don't advance |
| the XDR pointer, thereby corrupting anything subsequent decodes from the |
| same block of data. |
| |
| This has the potential to affect AFS.InlineBulkStatus and |
| YFS.InlineBulkStatus operation, but probably doesn't since the status |
| records are extracted as individual blocks of data and the buffer pointer |
| is reset between blocks. |
| |
| It does affect YFS.RemoveFile2 operation, corrupting the volsync record - |
| though that is not currently used. |
| |
| Other operations abort the entire operation rather than returning an error |
| inline, in which case there is no decoding to be done. |
| |
| Fix this by unconditionally advancing the xdr pointer. |
| |
| Fixes: 684b0f68cf1c ("afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility") |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c |
| index a1ef0266422a..451c709e1f50 100644 |
| --- a/fs/afs/fsclient.c |
| +++ b/fs/afs/fsclient.c |
| @@ -67,6 +67,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, |
| bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); |
| u64 data_version, size; |
| u32 type, abort_code; |
| + int ret; |
| |
| abort_code = ntohl(xdr->abort_code); |
| |
| @@ -80,7 +81,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, |
| */ |
| status->abort_code = abort_code; |
| scb->have_error = true; |
| - return 0; |
| + goto good; |
| } |
| |
| pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); |
| @@ -89,7 +90,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, |
| |
| if (abort_code != 0 && inline_error) { |
| status->abort_code = abort_code; |
| - return 0; |
| + goto good; |
| } |
| |
| type = ntohl(xdr->type); |
| @@ -125,13 +126,16 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, |
| data_version |= (u64)ntohl(xdr->data_version_hi) << 32; |
| status->data_version = data_version; |
| scb->have_status = true; |
| - |
| +good: |
| + ret = 0; |
| +advance: |
| *_bp = (const void *)*_bp + sizeof(*xdr); |
| - return 0; |
| + return ret; |
| |
| bad: |
| xdr_dump_bad(*_bp); |
| - return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status); |
| + ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status); |
| + goto advance; |
| } |
| |
| static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry) |
| diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c |
| index a1baf3f1f14d..505f9cb298dc 100644 |
| --- a/fs/afs/yfsclient.c |
| +++ b/fs/afs/yfsclient.c |
| @@ -186,13 +186,14 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp, |
| const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp; |
| struct afs_file_status *status = &scb->status; |
| u32 type; |
| + int ret; |
| |
| status->abort_code = ntohl(xdr->abort_code); |
| if (status->abort_code != 0) { |
| if (status->abort_code == VNOVNODE) |
| status->nlink = 0; |
| scb->have_error = true; |
| - return 0; |
| + goto good; |
| } |
| |
| type = ntohl(xdr->type); |
| @@ -220,13 +221,16 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp, |
| status->size = xdr_to_u64(xdr->size); |
| status->data_version = xdr_to_u64(xdr->data_version); |
| scb->have_status = true; |
| - |
| +good: |
| + ret = 0; |
| +advance: |
| *_bp += xdr_size(xdr); |
| - return 0; |
| + return ret; |
| |
| bad: |
| xdr_dump_bad(*_bp); |
| - return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status); |
| + ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status); |
| + goto advance; |
| } |
| |
| /* |
| -- |
| 2.7.4 |
| |