Skip to content

Commit

Permalink
xfs: fix possible overflow in xfs_ioc_trim()
Browse files Browse the repository at this point in the history
In xfs_ioc_trim it is possible that computing the last allocation group
to discard might overflow for big start & len values, because the result
might be bigger then xfs_agnumber_t which is 32 bit long. Fix this by not
allowing the start and end block of the range to be beyond the end of the
file system.

Note that if the start is beyond the end of the file system we have to
return -EINVAL, but in the "end" case we have to truncate it to the fs
size.

Also introduce "end" variable, rather than using start+len which which
might be more confusing to get right as this bug shows.

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
  • Loading branch information
Lukas Czerner authored and Alex Elder committed Oct 12, 2011
1 parent d952e2f commit c029a50
Showing 1 changed file with 10 additions and 10 deletions.
20 changes: 10 additions & 10 deletions fs/xfs/xfs_discard.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ xfs_trim_extents(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_fsblock_t start,
xfs_fsblock_t len,
xfs_fsblock_t end,
xfs_fsblock_t minlen,
__uint64_t *blocks_trimmed)
{
Expand Down Expand Up @@ -100,7 +100,7 @@ xfs_trim_extents(
* down partially overlapping ranges for now.
*/
if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
XFS_AGB_TO_FSB(mp, agno, fbno) >= start + len) {
XFS_AGB_TO_FSB(mp, agno, fbno) > end) {
trace_xfs_discard_exclude(mp, agno, fbno, flen);
goto next_extent;
}
Expand Down Expand Up @@ -145,7 +145,7 @@ xfs_ioc_trim(
struct request_queue *q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
unsigned int granularity = q->limits.discard_granularity;
struct fstrim_range range;
xfs_fsblock_t start, len, minlen;
xfs_fsblock_t start, end, minlen;
xfs_agnumber_t start_agno, end_agno, agno;
__uint64_t blocks_trimmed = 0;
int error, last_error = 0;
Expand All @@ -165,19 +165,19 @@ xfs_ioc_trim(
* matter as trimming blocks is an advisory interface.
*/
start = XFS_B_TO_FSBT(mp, range.start);
len = XFS_B_TO_FSBT(mp, range.len);
end = start + XFS_B_TO_FSBT(mp, range.len) - 1;
minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));

start_agno = XFS_FSB_TO_AGNO(mp, start);
if (start_agno >= mp->m_sb.sb_agcount)
if (start >= mp->m_sb.sb_dblocks)
return -XFS_ERROR(EINVAL);
if (end > mp->m_sb.sb_dblocks - 1)
end = mp->m_sb.sb_dblocks - 1;

end_agno = XFS_FSB_TO_AGNO(mp, start + len);
if (end_agno >= mp->m_sb.sb_agcount)
end_agno = mp->m_sb.sb_agcount - 1;
start_agno = XFS_FSB_TO_AGNO(mp, start);
end_agno = XFS_FSB_TO_AGNO(mp, end);

for (agno = start_agno; agno <= end_agno; agno++) {
error = -xfs_trim_extents(mp, agno, start, len, minlen,
error = -xfs_trim_extents(mp, agno, start, end, minlen,
&blocks_trimmed);
if (error)
last_error = error;
Expand Down

0 comments on commit c029a50

Please sign in to comment.