From 0c23994bcfe8f2c5a90f3cfbc452e9953fe00e17 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 2 Aug 2011 10:31:59 +0100 Subject: [PATCH] GFS2: make sure fallocate bytes is a multiple of blksize, CVE-2011-2689 The GFS2 fallocate code chooses a target size to for allocating chunks of space. Whenever it can't find any resource groups with enough space free, it halves its target. Since this target is in bytes, eventually it will no longer be a multiple of blksize. As long as there is more space available in the resource group than the target, this isn't a problem, since gfs2 will use the actual space available, which is always a multiple of blksize. However, when gfs couldn't fallocate a bigger chunk than the target, it was using the non-blksize aligned number. This caused a BUG in later code that required blksize aligned offsets. GFS2 now ensures that bytes is always a multiple of blksize Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse (cherry picked from commit 6905d9e4dda6112f007e9090bca80507da158e63) CVE-2011-2689 BugLink: http://bugs.launchpad.net/bugs/819572 Signed-off-by: Andy Whitcroft Acked-by: Stefan Bader Signed-off-by: Tim Gardner --- fs/gfs2/file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 7cfdcb9..ade0b56 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -777,6 +777,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t bytes, max_bytes; struct gfs2_alloc *al; int error; + loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1); loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; next = (next + 1) << sdp->sd_sb.sb_bsize_shift; @@ -784,13 +785,15 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, if (mode & ~FALLOC_FL_KEEP_SIZE) return -EOPNOTSUPP; - offset = (offset >> sdp->sd_sb.sb_bsize_shift) << - sdp->sd_sb.sb_bsize_shift; + offset &= bsize_mask; len = next - offset; bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; if (!bytes) bytes = UINT_MAX; + bytes &= bsize_mask; + if (bytes == 0) + bytes = sdp->sd_sb.sb_bsize; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); error = gfs2_glock_nq(&ip->i_gh); @@ -821,6 +824,9 @@ retry: if (error) { if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { bytes >>= 1; + bytes &= bsize_mask; + if (bytes == 0) + bytes = sdp->sd_sb.sb_bsize; goto retry; } goto out_qunlock; -- 1.7.10.4