mirror of
https://github.com/neovim/neovim.git
synced 2026-02-21 09:50:19 +10:00
vim-patch:9.1.2028: [security]: Buffer-overflow with incomplete multi-byte chars (#37133)
Problem: Buffer overflow in buf_write() when converting incomplete
multi-byte characters (Kevin Goodsell)
Solution: Make the buffer slightly larger
closes: vim/vim#19007
f99de42a9f
Co-authored-by: Christian Brabandt <cb@256bit.org>
(cherry picked from commit 444e1ffe3e)
This commit is contained in:
committed by
github-actions[bot]
parent
18f189a3f3
commit
fda8d2c717
@@ -288,6 +288,17 @@ static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp)
|
||||
c = n > 1 ? (unsigned)utf_ptr2char(*bufp + wlen)
|
||||
: (uint8_t)(*bufp)[wlen];
|
||||
}
|
||||
// Check that there is enough space
|
||||
if (!(flags & FIO_LATIN1)) {
|
||||
size_t need = (flags & FIO_UCS4) ? 4 : 2;
|
||||
if ((flags & FIO_UTF16) && c >= 0x10000) {
|
||||
need = 4;
|
||||
}
|
||||
|
||||
if ((size_t)(p - ip->bw_conv_buf) + need > ip->bw_conv_buflen) {
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) {
|
||||
ip->bw_conv_error = true;
|
||||
@@ -1291,11 +1302,13 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
|
||||
if (converted) {
|
||||
wb_flags = get_fio_flags(fenc);
|
||||
if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) {
|
||||
// overallocate a bit, in case we read incomplete multi-byte chars
|
||||
int size = bufsize + CONV_RESTLEN;
|
||||
// Need to allocate a buffer to translate into.
|
||||
if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) {
|
||||
write_info.bw_conv_buflen = (size_t)bufsize * 2;
|
||||
write_info.bw_conv_buflen = (size_t)size * 2;
|
||||
} else { // FIO_UCS4
|
||||
write_info.bw_conv_buflen = (size_t)bufsize * 4;
|
||||
write_info.bw_conv_buflen = (size_t)size * 4;
|
||||
}
|
||||
write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
|
||||
if (!write_info.bw_conv_buf) {
|
||||
|
||||
@@ -63,3 +63,13 @@ it('no crash when writing "Untitled" file fails', function()
|
||||
eq('Vim(enew):E502: "Untitled" is a directory', pcall_err(command, 'confirm enew'))
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
-- oldtest: Test_crash_bufwrite()
|
||||
it('no crash when converting buffer with incomplete multibyte chars', function()
|
||||
command('edit ++bin test/old/testdir/samples/buffer-test.txt')
|
||||
finally(function()
|
||||
os.remove('Xoutput')
|
||||
end)
|
||||
command('w! ++enc=ucs4 Xoutput')
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
1
test/old/testdir/samples/buffer-test.txt
Normal file
1
test/old/testdir/samples/buffer-test.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -231,4 +231,22 @@ func TearDown()
|
||||
call delete('Untitled')
|
||||
endfunc
|
||||
|
||||
func Test_crash_bufwrite()
|
||||
let lines =<< trim END
|
||||
w! ++enc=ucs4 Xoutput
|
||||
call writefile(['done'], 'Xbufwrite')
|
||||
END
|
||||
call writefile(lines, 'Xvimrc')
|
||||
let opts = #{wait_for_ruler: 0, rows: 20}
|
||||
let args = ' -u NONE -i NONE -b -S Xvimrc'
|
||||
let buf = RunVimInTerminal(args .. ' samples/buffer-test.txt', opts)
|
||||
call TermWait(buf, 1000)
|
||||
call StopVimInTerminal(buf)
|
||||
call WaitForAssert({-> assert_true(filereadable('Xbufwrite'))})
|
||||
call assert_equal(['done'], readfile('Xbufwrite'))
|
||||
call delete('Xbufwrite')
|
||||
call delete('Xoutput')
|
||||
call delete('Xvimrc')
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
Reference in New Issue
Block a user