From bbdf21455561afec58cf55bb01691cb48f302744 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 2 Oct 2016 20:32:00 +0900 Subject: [PATCH] libsegment: check finfo position before reading finfo Accesses to finfo in nilfs_file_next() and nilfs_file_init() can overrun since the termination condition of the file iterator is tested after these functions return and the position of finfo is checked afterwards as well. This fixes the issue by inserting pre-checks for the position of finfo before reading it. Signed-off-by: Ryusuke Konishi --- lib/segment.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/segment.c b/lib/segment.c index cbc790c..9992edf 100644 --- a/lib/segment.c +++ b/lib/segment.c @@ -196,6 +196,21 @@ static size_t nilfs_file_info_size(struct nilfs_file *file) return delta; } +static void nilfs_file_init_from_finfo(struct nilfs_file *file) +{ + if (file->offset + sizeof(struct nilfs_finfo) > file->sumbytes) { + /* + * Set a dummy value to file->sumlen so that + * nilfs_file_is_valid() will always fail. + */ + file->sumlen = sizeof(struct nilfs_finfo); + return; + } + + file->use_real_blocknr = nilfs_finfo_use_real_blocknr(file->finfo); + file->sumlen = nilfs_file_info_size(file); +} + void nilfs_file_init(struct nilfs_file *file, const struct nilfs_psegment *pseg) { @@ -214,9 +229,8 @@ void nilfs_file_init(struct nilfs_file *file, file->offset = hdrsize; file->finfo = (void *)pseg->segsum + hdrsize; nilfs_file_adjust_finfo_position(file, blksize); + nilfs_file_init_from_finfo(file); - file->use_real_blocknr = nilfs_finfo_use_real_blocknr(file->finfo); - file->sumlen = nilfs_file_info_size(file); file->error = NILFS_FILE_SUCCESS; } @@ -225,6 +239,12 @@ static int nilfs_file_is_valid(struct nilfs_file *file) const struct nilfs_psegment *pseg = file->psegment; __u32 nblocks, pseg_nblocks, ndatablk, blkoff; + /* Sanity check for total length of finfo + binfos */ + if (unlikely(file->offset + file->sumlen > file->sumbytes)) { + file->error = NILFS_FILE_ERROR_OVERRUN; + goto error; + } + /* Sanity check for payload block count */ nblocks = le32_to_cpu(file->finfo->fi_nblocks); blkoff = file->blocknr - pseg->blocknr; @@ -241,12 +261,6 @@ static int nilfs_file_is_valid(struct nilfs_file *file) goto error; } - /* Sanity check for total length of finfo + binfos */ - if (unlikely(file->offset + file->sumlen > file->sumbytes)) { - file->error = NILFS_FILE_ERROR_OVERRUN; - goto error; - } - return 1; error: @@ -268,9 +282,8 @@ void nilfs_file_next(struct nilfs_file *file) file->offset += file->sumlen; file->finfo = (void *)file->finfo + file->sumlen; nilfs_file_adjust_finfo_position(file, blksize); + nilfs_file_init_from_finfo(file); - file->use_real_blocknr = nilfs_finfo_use_real_blocknr(file->finfo); - file->sumlen = nilfs_file_info_size(file); file->index++; }