Skip to content

Commit

Permalink
dax: fix offset overflow in dax_io
Browse files Browse the repository at this point in the history
This isn't functionally apparent for some reason, but
when we test io at extreme offsets at the end of the loff_t
rang, such as in fstests xfs/071, the calculation of
"max" in dax_io() can be wrong due to pos + size overflowing.

For example,

# xfs_io -c "pwrite 9223372036854771712 512" /mnt/test/file

enters dax_io with:

start 0x7ffffffffffff000
end   0x7ffffffffffff200

and the rounded up "size" variable is 0x1000.  This yields:

pos + size 0x8000000000000000 (overflows loff_t)
       end 0x7ffffffffffff200

Due to the overflow, the min() function picks the wrong
value for the "max" variable, and when we send (max - pos)
into i.e. copy_from_iter_pmem() it is also the wrong value.

This somehow(tm) gets magically absorbed without incident,
probably because iter->count is correct.  But it seems best
to fix it up properly by comparing the two values as
unsigned.

Signed-off-by: Eric Sandeen <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
Eric Sandeen authored and djbw committed Jun 27, 2016
1 parent 4995734 commit 0239543
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion fs/dax.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,12 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
dax.addr += first;
size = map_len - first;
}
max = min(pos + size, end);
/*
* pos + size is one past the last offset for IO,
* so pos + size can overflow loff_t at extreme offsets.
* Cast to u64 to catch this and get the true minimum.
*/
max = min_t(u64, pos + size, end);
}

if (iov_iter_rw(iter) == WRITE) {
Expand Down

0 comments on commit 0239543

Please sign in to comment.