afs: Fix StoreData op marshalling [Linux 3.16.72]

This Linux kernel change "afs: Fix StoreData op marshalling" is included in the Linux 3.16.72 release. This change is authored by David Howells <dhowells [at]> on Wed Mar 27 22:48:02 2019 +0000. The commit for this change in Linux stable tree is 4f7aaea (patch) which is from upstream commit 8c7ae38. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 8c7ae38.

afs: Fix StoreData op marshalling

commit 8c7ae38d1ce12a0eaeba655df8562552b3596c7f upstream.

The marshalling of AFS.StoreData, AFS.StoreData64 and YFS.StoreData64 calls
generated by ->setattr() ops for the purpose of expanding a file is
incorrect due to older documentation incorrectly describing the way the RPC
'FileLength' parameter is meant to work.

The older documentation says that this is the length the file is meant to
end up at the end of the operation; however, it was never implemented this
way in any of the servers, but rather the file is truncated down to this
before the write operation is effected, and never expanded to it (and,
indeed, it was renamed to 'TruncPos' in 2014).

Fix this by setting the position parameter to the new file length and doing
a zero-lengh write there.

The bug causes Xwayland to SIGBUS due to unexpected non-expansion of a file
it then mmaps.  This can be tested by giving the following test program a
filename in an AFS directory:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    int main(int argc, char *argv[])
        char *p;
        int fd;
        if (argc != 2) {
                "Format: test-trunc-mmap <file>\n");
        fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC);
        if (fd < 0) {
        if (ftruncate(fd, 0x140008) == -1) {
        p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
             MAP_SHARED, fd, 0);
        if (p == MAP_FAILED) {
        p[0] = 'a';
        if (munmap(p, 4096) < 0) {
        if (close(fd) < 0) {

Fixes: 31143d5d515e ("AFS: implement basic file write support")
Reported-by: Jonathan Billings <>
Tested-by: Jonathan Billings <>
Signed-off-by: David Howells <>
Signed-off-by: Linus Torvalds <>
[bwh: Backported to 3.16: drop change in yfsclient.c]
Signed-off-by: Ben Hutchings <>

There are 6 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/afs/fsclient.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index c2e930e..696db17 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -1382,8 +1382,8 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,

    xdr_encode_AFS_StoreStatus(&bp, attr);

-   *bp++ = 0;              /* position of start of write */
-   *bp++ = 0;
+   *bp++ = htonl(attr->ia_size >> 32); /* position of start of write */
+   *bp++ = htonl((u32) attr->ia_size);
    *bp++ = 0;              /* size of write */
    *bp++ = 0;
    *bp++ = htonl(attr->ia_size >> 32); /* new file length */
@@ -1433,7 +1433,7 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key,

    xdr_encode_AFS_StoreStatus(&bp, attr);

-   *bp++ = 0;              /* position of start of write */
+   *bp++ = htonl(attr->ia_size);       /* position of start of write */
    *bp++ = 0;              /* size of write */
    *bp++ = htonl(attr->ia_size);       /* new file length */

Leave a Reply

Your email address will not be published. Required fields are marked *