Skip to content

Commit b2036bb

Browse files
author
Trond Myklebust
committed
NFSv4.2: Protect copy offload and clone against 'eof page pollution'
The NFSv4.2 copy offload and clone functions can also end up extending the size of the destination file, so they too need to call nfs_truncate_last_folio(). Reported-by: Olga Kornievskaia <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent b1817b1 commit b2036bb

File tree

1 file changed

+13
-6
lines changed

1 file changed

+13
-6
lines changed

fs/nfs/nfs42proc.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,22 +362,27 @@ static int process_copy_commit(struct file *dst, loff_t pos_dst,
362362

363363
/**
364364
* nfs42_copy_dest_done - perform inode cache updates after clone/copy offload
365-
* @inode: pointer to destination inode
365+
* @file: pointer to destination file
366366
* @pos: destination offset
367367
* @len: copy length
368+
* @oldsize: length of the file prior to clone/copy
368369
*
369370
* Punch a hole in the inode page cache, so that the NFS client will
370371
* know to retrieve new data.
371372
* Update the file size if necessary, and then mark the inode as having
372373
* invalid cached values for change attribute, ctime, mtime and space used.
373374
*/
374-
static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len)
375+
static void nfs42_copy_dest_done(struct file *file, loff_t pos, loff_t len,
376+
loff_t oldsize)
375377
{
378+
struct inode *inode = file_inode(file);
379+
struct address_space *mapping = file->f_mapping;
376380
loff_t newsize = pos + len;
377381
loff_t end = newsize - 1;
378382

379-
WARN_ON_ONCE(invalidate_inode_pages2_range(inode->i_mapping,
380-
pos >> PAGE_SHIFT, end >> PAGE_SHIFT));
383+
nfs_truncate_last_folio(mapping, oldsize, pos);
384+
WARN_ON_ONCE(invalidate_inode_pages2_range(mapping, pos >> PAGE_SHIFT,
385+
end >> PAGE_SHIFT));
381386

382387
spin_lock(&inode->i_lock);
383388
if (newsize > i_size_read(inode))
@@ -410,6 +415,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
410415
struct nfs_server *src_server = NFS_SERVER(src_inode);
411416
loff_t pos_src = args->src_pos;
412417
loff_t pos_dst = args->dst_pos;
418+
loff_t oldsize_dst = i_size_read(dst_inode);
413419
size_t count = args->count;
414420
ssize_t status;
415421

@@ -483,7 +489,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
483489
goto out;
484490
}
485491

486-
nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count);
492+
nfs42_copy_dest_done(dst, pos_dst, res->write_res.count, oldsize_dst);
487493
nfs_invalidate_atime(src_inode);
488494
status = res->write_res.count;
489495
out:
@@ -1250,6 +1256,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
12501256
struct nfs42_clone_res res = {
12511257
.server = server,
12521258
};
1259+
loff_t oldsize_dst = i_size_read(dst_inode);
12531260
int status;
12541261

12551262
msg->rpc_argp = &args;
@@ -1284,7 +1291,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
12841291
/* a zero-length count means clone to EOF in src */
12851292
if (count == 0 && res.dst_fattr->valid & NFS_ATTR_FATTR_SIZE)
12861293
count = nfs_size_to_loff_t(res.dst_fattr->size) - dst_offset;
1287-
nfs42_copy_dest_done(dst_inode, dst_offset, count);
1294+
nfs42_copy_dest_done(dst_f, dst_offset, count, oldsize_dst);
12881295
status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
12891296
}
12901297

0 commit comments

Comments
 (0)