mirror of
https://github.com/neovim/neovim.git
synced 2026-04-23 15:55:36 +00:00
fix(prompt): heap-buffer-overflow in prompt_setprompt
Problem: prompt_setprompt may check the wrong buffer, which can lead to a heap-buffer-overflow. Solution: don't use curbuf. Also replace all kCallbackNone initializers with CALLBACK_INIT.
This commit is contained in:
@@ -712,7 +712,7 @@ void restore_buffer(bufref_T *save_curbuf)
|
|||||||
/// "prompt_setcallback({buffer}, {callback})" function
|
/// "prompt_setcallback({buffer}, {callback})" function
|
||||||
void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
{
|
{
|
||||||
Callback prompt_callback = { .type = kCallbackNone };
|
Callback prompt_callback = CALLBACK_INIT;
|
||||||
|
|
||||||
if (check_secure()) {
|
if (check_secure()) {
|
||||||
return;
|
return;
|
||||||
@@ -735,7 +735,7 @@ void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
/// "prompt_setinterrupt({buffer}, {callback})" function
|
/// "prompt_setinterrupt({buffer}, {callback})" function
|
||||||
void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
{
|
{
|
||||||
Callback interrupt_callback = { .type = kCallbackNone };
|
Callback interrupt_callback = CALLBACK_INIT;
|
||||||
|
|
||||||
if (check_secure()) {
|
if (check_secure()) {
|
||||||
return;
|
return;
|
||||||
@@ -772,10 +772,8 @@ void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
// Update the prompt-text and prompt-marks if a plugin calls prompt_setprompt()
|
// Update the prompt-text and prompt-marks if a plugin calls prompt_setprompt()
|
||||||
// even while user is editing their input.
|
// even while user is editing their input.
|
||||||
if (bt_prompt(buf)) {
|
if (bt_prompt(buf)) {
|
||||||
if (buf->b_prompt_start.mark.lnum > buf->b_ml.ml_line_count) {
|
// In case the mark is set to a nonexistent line.
|
||||||
// In case the mark is set to a nonexistent line.
|
buf->b_prompt_start.mark.lnum = MIN(buf->b_prompt_start.mark.lnum, buf->b_ml.ml_line_count);
|
||||||
buf->b_prompt_start.mark.lnum = buf->b_ml.ml_line_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
linenr_T prompt_lno = buf->b_prompt_start.mark.lnum;
|
linenr_T prompt_lno = buf->b_prompt_start.mark.lnum;
|
||||||
char *old_prompt = buf_prompt_text(buf);
|
char *old_prompt = buf_prompt_text(buf);
|
||||||
@@ -786,8 +784,7 @@ void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
colnr_T cursor_col = curwin->w_cursor.col;
|
colnr_T cursor_col = curwin->w_cursor.col;
|
||||||
|
|
||||||
if (buf->b_prompt_start.mark.col < old_prompt_len
|
if (buf->b_prompt_start.mark.col < old_prompt_len
|
||||||
|| curbuf->b_prompt_start.mark.col < old_prompt_len
|
|| !strnequal(old_prompt, old_line + buf->b_prompt_start.mark.col - old_prompt_len,
|
||||||
|| !strnequal(old_prompt, old_line + curbuf->b_prompt_start.mark.col - old_prompt_len,
|
|
||||||
(size_t)old_prompt_len)) {
|
(size_t)old_prompt_len)) {
|
||||||
// If for some odd reason the old prompt is missing,
|
// If for some odd reason the old prompt is missing,
|
||||||
// replace prompt line with new-prompt (discards user-input).
|
// replace prompt line with new-prompt (discards user-input).
|
||||||
|
|||||||
@@ -4883,7 +4883,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
|
|||||||
typval_T *cancelreturn = NULL;
|
typval_T *cancelreturn = NULL;
|
||||||
typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE;
|
typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE;
|
||||||
const char *xp_name = NULL;
|
const char *xp_name = NULL;
|
||||||
Callback input_callback = { .type = kCallbackNone };
|
Callback input_callback = CALLBACK_INIT;
|
||||||
char prompt_buf[NUMBUFLEN];
|
char prompt_buf[NUMBUFLEN];
|
||||||
char defstr_buf[NUMBUFLEN];
|
char defstr_buf[NUMBUFLEN];
|
||||||
char cancelreturn_buf[NUMBUFLEN];
|
char cancelreturn_buf[NUMBUFLEN];
|
||||||
|
|||||||
@@ -798,8 +798,8 @@ describe('prompt buffer', function()
|
|||||||
api.nvim_set_option_value('buftype', 'prompt', { buf = 0 })
|
api.nvim_set_option_value('buftype', 'prompt', { buf = 0 })
|
||||||
local buf = api.nvim_get_current_buf()
|
local buf = api.nvim_get_current_buf()
|
||||||
|
|
||||||
local function set_prompt(prompt)
|
local function set_prompt(prompt, b)
|
||||||
fn('prompt_setprompt', buf, prompt)
|
fn('prompt_setprompt', b or buf, prompt)
|
||||||
end
|
end
|
||||||
|
|
||||||
set_prompt('> ')
|
set_prompt('> ')
|
||||||
@@ -846,5 +846,20 @@ describe('prompt buffer', function()
|
|||||||
{5:-- INSERT --} |
|
{5:-- INSERT --} |
|
||||||
]])
|
]])
|
||||||
eq({ 1, 13 }, api.nvim_buf_get_mark(0, ':'))
|
eq({ 1, 13 }, api.nvim_buf_get_mark(0, ':'))
|
||||||
|
|
||||||
|
-- No crash when setting shorter prompt than curbuf's in other buffer.
|
||||||
|
command('new | setlocal buftype=prompt')
|
||||||
|
set_prompt('looooooooooooooooooooooooooooooooooooooooooooong > ', '') -- curbuf
|
||||||
|
set_prompt('foo > ')
|
||||||
|
screen:expect([[
|
||||||
|
loooooooooooooooooooooooo|
|
||||||
|
ooooooooooooooooooooong >|
|
||||||
|
^ |
|
||||||
|
{1:~ }|
|
||||||
|
{3:[Prompt] [+] }|
|
||||||
|
foo > user input |
|
||||||
|
{1:~ }|*3
|
||||||
|
{5:-- INSERT --} |
|
||||||
|
]])
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user