aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-03-27 18:48:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-28 11:54:20 -0400
commit8c7ae38d1ce12a0eaeba655df8562552b3596c7f (patch)
treec4823b9f7c1238ecf4c459971ae2819118c0fc41 /fs/afs
parent7d6ab823d6461e60d211d4c8d89a13dce08b730d (diff)
afs: Fix StoreData op marshalling
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) { fprintf(stderr, "Format: test-trunc-mmap <file>\n"); exit(2); } fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC); if (fd < 0) { perror(argv[1]); exit(1); } if (ftruncate(fd, 0x140008) == -1) { perror("ftruncate"); exit(1); } p = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { perror("mmap"); exit(1); } p[0] = 'a'; if (munmap(p, 4096) < 0) { perror("munmap"); exit(1); } if (close(fd) < 0) { perror("close"); exit(1); } exit(0); } Fixes: 31143d5d515e ("AFS: implement basic file write support") Reported-by: Jonathan Billings <jsbillin@umich.edu> Tested-by: Jonathan Billings <jsbillin@umich.edu> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/fsclient.c6
-rw-r--r--fs/afs/yfsclient.c2
2 files changed, 4 insertions, 4 deletions
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index ca08c83168f5..0b37867b5c20 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -1515,8 +1515,8 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
1515 1515
1516 xdr_encode_AFS_StoreStatus(&bp, attr); 1516 xdr_encode_AFS_StoreStatus(&bp, attr);
1517 1517
1518 *bp++ = 0; /* position of start of write */ 1518 *bp++ = htonl(attr->ia_size >> 32); /* position of start of write */
1519 *bp++ = 0; 1519 *bp++ = htonl((u32) attr->ia_size);
1520 *bp++ = 0; /* size of write */ 1520 *bp++ = 0; /* size of write */
1521 *bp++ = 0; 1521 *bp++ = 0;
1522 *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1522 *bp++ = htonl(attr->ia_size >> 32); /* new file length */
@@ -1564,7 +1564,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
1564 1564
1565 xdr_encode_AFS_StoreStatus(&bp, attr); 1565 xdr_encode_AFS_StoreStatus(&bp, attr);
1566 1566
1567 *bp++ = 0; /* position of start of write */ 1567 *bp++ = htonl(attr->ia_size); /* position of start of write */
1568 *bp++ = 0; /* size of write */ 1568 *bp++ = 0; /* size of write */
1569 *bp++ = htonl(attr->ia_size); /* new file length */ 1569 *bp++ = htonl(attr->ia_size); /* new file length */
1570 1570
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index 5aa57929e8c2..6e97a42d24d1 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -1514,7 +1514,7 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
1514 bp = xdr_encode_u32(bp, 0); /* RPC flags */ 1514 bp = xdr_encode_u32(bp, 0); /* RPC flags */
1515 bp = xdr_encode_YFSFid(bp, &vnode->fid); 1515 bp = xdr_encode_YFSFid(bp, &vnode->fid);
1516 bp = xdr_encode_YFS_StoreStatus(bp, attr); 1516 bp = xdr_encode_YFS_StoreStatus(bp, attr);
1517 bp = xdr_encode_u64(bp, 0); /* position of start of write */ 1517 bp = xdr_encode_u64(bp, attr->ia_size); /* position of start of write */
1518 bp = xdr_encode_u64(bp, 0); /* size of write */ 1518 bp = xdr_encode_u64(bp, 0); /* size of write */
1519 bp = xdr_encode_u64(bp, attr->ia_size); /* new file length */ 1519 bp = xdr_encode_u64(bp, attr->ia_size); /* new file length */
1520 yfs_check_req(call, bp); 1520 yfs_check_req(call, bp);