From: Darrick J. Wong <djwong@xxxxxxxxxx> Fix various bugs in ext2fs_file_write_inline_data: - "count = nbytes - pos" makes no sense since nbytes is already a length value and results in short writes if pos > 0. - Pass the correct file size to ext2fs_inline_data_set because count will not be the file size if pos > 0. - Simplify the decision to increase the file size. - Don't let a huge write corrupt memory beyond file->buf. - Zero the buffer between isize and pos if we're doing a sparse write past EOF. Cc: <linux-ext4@xxxxxxxxxxxxxxx> # v1.43 Fixes: 54e880b870f7fe ("libext2fs: handle inline data in read/write function") Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- lib/ext2fs/fileio.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c index 900002c5295682..3a36e9e7fff43b 100644 --- a/lib/ext2fs/fileio.c +++ b/lib/ext2fs/fileio.c @@ -349,31 +349,42 @@ ext2fs_file_write_inline_data(ext2_file_t file, const void *buf, unsigned int nbytes, unsigned int *written) { ext2_filsys fs; + uint64_t old_isize = EXT2_I_SIZE(&file->inode); + uint64_t new_isize = old_isize; errcode_t retval; - unsigned int count = 0; size_t size; + if (file->pos + nbytes > old_isize) + new_isize = file->pos + nbytes; + fs = file->fs; retval = ext2fs_inline_data_get(fs, file->ino, &file->inode, file->buf, &size); if (retval) return retval; - if (file->pos < size) { - count = nbytes - file->pos; - memcpy(file->buf + file->pos, buf, count); + /* + * Only try to set new inline data if it won't go past the end of + * @file->buf; if there's not enough space in the ondisk inode, we'll + * jump out to the expand code. + */ + if (new_isize < fs->blocksize) { + if (file->pos > old_isize) + memset(file->buf + old_isize, 0, file->pos - old_isize); + + memcpy(file->buf + file->pos, buf, nbytes); retval = ext2fs_inline_data_set(fs, file->ino, &file->inode, - file->buf, count); + file->buf, new_isize); if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) goto expand; if (retval) return retval; - file->pos += count; + file->pos += nbytes; /* Update inode size */ - if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) { + if (old_isize < new_isize) { errcode_t rc; rc = ext2fs_file_set_size2(file, file->pos); @@ -382,7 +393,7 @@ ext2fs_file_write_inline_data(ext2_file_t file, const void *buf, } if (written) - *written = count; + *written = nbytes; return 0; }