aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2015-05-14 19:11:50 -0400
committerWilly Tarreau <w@1wt.eu>2015-09-18 13:52:01 +0200
commit06763ca2d529c0f2bfcf13aa47bdf211de4259c9 (patch)
tree0ae2ba7dbcae86834433fb619f3bd6f354d2aced
parent6c43247b73b100ba8ff51bc06997a7c1fd157bbc (diff)
jbd2: fix r_count overflows leading to buffer overflow in journal recovery
commit e531d0bceb402e643a4499de40dd3fa39d8d2e43 upstream. The journal revoke block recovery code does not check r_count for sanity, which means that an evil value of r_count could result in the kernel reading off the end of the revoke table and into whatever garbage lies beyond. This could crash the kernel, so fix that. However, in testing this fix, I discovered that the code to write out the revoke tables also was not correctly checking to see if the block was full -- the current offset check is fine so long as the revoke table space size is a multiple of the record size, but this is not true when either journal_csum_v[23] are set. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz> [bwh: Backported to 3.2: journal checksumming is not supported, so only the first fix is needed] Signed-off-by: Ben Hutchings <ben@decadent.org.uk> (cherry picked from commit 2f6a2bcc01bc9ed73bfb4d698da94ed2a5fcb18c) Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--fs/jbd2/recovery.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 73063285b13f..59cc9c5231ed 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -718,11 +718,16 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
{
jbd2_journal_revoke_header_t *header;
int offset, max;
+ __u32 rcount;
int record_len = 4;
header = (jbd2_journal_revoke_header_t *) bh->b_data;
offset = sizeof(jbd2_journal_revoke_header_t);
- max = be32_to_cpu(header->r_count);
+ rcount = be32_to_cpu(header->r_count);
+
+ if (rcount > journal->j_blocksize)
+ return -EINVAL;
+ max = rcount;
if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
record_len = 8;