Mercurial > vim
view src/testdir/test_shell.vim @ 33776:9503dc55b5ed v9.0.2108
patch 9.0.2108: [security]: overflow with count for :s command
Commit: https://github.com/vim/vim/commit/ac63787734fda2e294e477af52b3bd601517fa78
Author: Christian Brabandt <cb@256bit.org>
Date: Tue Nov 14 20:45:48 2023 +0100
patch 9.0.2108: [security]: overflow with count for :s command
Problem: [security]: overflow with count for :s command
Solution: Abort the :s command if the count is too large
If the count after the :s command is larger than what fits into a
(signed) long variable, abort with e_value_too_large.
Adds a test with INT_MAX as count and verify it correctly fails.
It seems the return value on Windows using mingw compiler wraps around,
so the initial test using :s/./b/9999999999999999999999999990 doesn't
fail there, since the count is wrapping around several times and finally
is no longer larger than 2147483647. So let's just use 2147483647 in the
test, which hopefully will always cause a failure
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 16 Nov 2023 22:15:10 +0100 |
parents | 30ea99dff3be |
children | 48d01e3323ca |
line wrap: on
line source
" Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe', " 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote') source check.vim source shared.vim func Test_shell_options() if has('win32') " FIXME: This test is flaky on MS-Windows. let g:test_is_flaky = 1 endif " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote', " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells. let shells = [] if has('unix') let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''], \ ['csh', '-c', '|& tee', '', '>&', '', ''], \ ['tcsh', '-c', '|& tee', '', '>&', '', ''], \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '', '']] endif if has('win32') let shells += [['cmd', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', ''], \ ['cmd.exe', '/c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '('], \ ['powershell.exe', '-Command', '2>&1 | Out-File -Encoding default', \ '', '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], \ ['powershell', '-Command', '2>&1 | Out-File -Encoding default', '', \ '2>&1 | Out-File -Encoding default', '"&|<>()@^', '"'], \ ['pwsh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['pwsh', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['sh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['ksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['mksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['pdksh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['zsh.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['zsh-beta.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['bash.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['dash.exe', '-c', '>%s 2>&1', '', '>%s 2>&1', '"&|<>()@^', '"'], \ ['csh.exe', '-c', '>&', '', '>&', '"&|<>()@^', '"'], \ ['tcsh.exe', '-c', '>&', '', '>&', '"&|<>()@^', '"']] endif " start a new Vim instance with 'shell' set to each of the supported shells " and check the default shell option settings let after =<< trim END let l = [&shell, &shellcmdflag, &shellpipe, &shellquote] let l += [&shellredir, &shellxescape, &shellxquote] call writefile([json_encode(l)], 'Xtestout') qall! END for e in shells if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"') call assert_equal(e, json_decode(readfile('Xtestout')[0])) endif endfor " Test shellescape() for each of the shells. for e in shells exe 'set shell=' .. e[0] if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$' let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%# \\'\\'' \\\\! \\% \\#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\# \\'\\'' \\\\\\! \\\\% \\\\#'" elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$' \ || e[0] =~# '.*pwsh$' || e[0] =~# '.*pwsh.exe$' let str1 = "'cmd \"arg1\" ''arg2'' !%# \\'' \\! \\% \\#'" let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\# \\'' \\\\! \\\\% \\\\#'" elseif e[0] =~# '.*fish$' || e[0] =~# '.*fish.exe$' let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\\\'\\'' \\\\! \\\\% \\\\#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\\\'\\'' \\\\\\! \\\\\\% \\\\\\#'" else let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%# \\'\\'' \\! \\% \\#'" let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\# \\'\\'' \\\\! \\\\% \\\\#'" endif call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%# \\' \\! \\% \\#"), e[0]) call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%# \\' \\! \\% \\#", 1), e[0]) " Try running an external command with the shell. if executable(e[0]) " set the shell options for the current 'shell' let [&shellcmdflag, &shellpipe, &shellquote, &shellredir, \ &shellxescape, &shellxquote] = e[1:6] new try r !echo hello call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0]) catch call assert_report('Failed to run shell command, shell: ' .. e[0] \ .. ', caught ' .. v:exception) finally bwipe! endtry " filter buffer contents through an external command new call setline(1, ['tom', 'sam', 'andy']) try %!sort call assert_equal(['andy', 'sam', 'tom'], getline(1, '$'), e[0]) catch call assert_report($'Failed to filter buffer contents, shell: {e[0]}, caught {v:exception}') finally bwipe! endtry endif endfor set shell& shellcmdflag& shellpipe& shellquote& set shellredir& shellxescape& shellxquote& call delete('Xtestout') endfunc " Test for the 'shell' option func Test_shell() CheckUnix let save_shell = &shell set shell= let caught_e91 = 0 try shell catch /E91:/ let caught_e91 = 1 endtry call assert_equal(1, caught_e91) let &shell = save_shell endfunc " Test for the 'shellquote' option func Test_shellquote() CheckUnix set shellquote=# set verbose=20 redir => v silent! !echo Hello redir END set verbose& set shellquote& call assert_match(': "#echo Hello#"', v) endfunc " Test for the 'shellescape' option func Test_shellescape() let save_shell = &shell set shell=bash call assert_equal("'text'", shellescape('text')) call assert_equal("'te\"xt'", 'te"xt'->shellescape()) call assert_equal("'te'\\''xt'", shellescape("te'xt")) call assert_equal("'te%xt'", shellescape("te%xt")) call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) call assert_equal("'te#xt'", shellescape("te#xt")) call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) call assert_equal("'te!xt'", shellescape("te!xt")) call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) call assert_equal("'te\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) set shell=tcsh call assert_equal("'te\\!xt'", shellescape("te!xt")) call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) call assert_equal("'te\\\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) let &shell = save_shell endfunc " Test for 'shellslash' func Test_shellslash() CheckOption shellslash let save_shellslash = &shellslash " The shell and cmdflag, and expected slash in tempname with shellslash set or " unset. The assert checks the file separator before the leafname. " ".*\\\\[^\\\\]*$" let shells = [['cmd', '/c', '\\', '/'], \ ['powershell', '-Command', '\\', '/'], \ ['pwsh', '-Command', '\\', '/'], \ ['pwsh', '-c', '\\', '/'], \ ['sh', '-c', '/', '/']] for e in shells exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1] set noshellslash let file = tempname() call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl') set shellslash let file = tempname() call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl') endfor let &shellslash = save_shellslash endfunc " Test for 'shellxquote' func Test_shellxquote() CheckUnix let save_shell = &shell let save_sxq = &shellxquote let save_sxe = &shellxescape call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell', 'D') call setfperm('Xtestshell', "r-x------") set shell=./Xtestshell set shellxquote=\\" call feedkeys(":!pwd\<CR>\<CR>", 'xt') call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) set shellxquote=( call feedkeys(":!pwd\<CR>\<CR>", 'xt') call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) set shellxquote=\\"( call feedkeys(":!pwd\<CR>\<CR>", 'xt') call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) set shellxescape=\"&<<()@^ set shellxquote=( call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) let &shell = save_shell let &shellxquote = save_sxq let &shellxescape = save_sxe call delete('Xlog') endfunc " Test for using the shell set in the $SHELL environment variable func Test_set_shell() let after =<< trim [CODE] call writefile([&shell], "Xtestout") quit! [CODE] if has('win32') let $SHELL = 'C:\with space\cmd.exe' let expected = '"C:\with space\cmd.exe"' else let $SHELL = '/bin/with space/sh' let expected = '/bin/with\ space/sh' endif if RunVimPiped([], after, '', '') let lines = readfile('Xtestout') call assert_equal(expected, lines[0]) endif call delete('Xtestout') endfunc func Test_shell_repeat() CheckUnix let save_shell = &shell call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell', 'D') call setfperm('Xtestshell', "r-x------") set shell=./Xtestshell defer delete('Xlog') call feedkeys(":!echo coconut\<CR>", 'xt') " Run command call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) call feedkeys(":!!\<CR>", 'xt') " Re-run previous call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) call writefile(['empty'], 'Xlog') call feedkeys(":!\<CR>", 'xt') " :! call assert_equal(['Cmd: [-c ]'], readfile('Xlog')) call feedkeys(":!!\<CR>", 'xt') " :! doesn't clear previous command call assert_equal(['Cmd: [-c echo coconut]'], readfile('Xlog')) call feedkeys(":!echo banana\<CR>", 'xt') " Make sure setting previous command keeps working after a :! no-op call assert_equal(['Cmd: [-c echo banana]'], readfile('Xlog')) call feedkeys(":!!\<CR>", 'xt') call assert_equal(['Cmd: [-c echo banana]'], readfile('Xlog')) let &shell = save_shell endfunc func Test_shell_no_prevcmd() " this doesn't do anything, just check it doesn't crash let after =<< trim END exe "normal !!\<CR>" call writefile([v:errmsg, 'done'], 'Xtestdone') qall! END if RunVim([], after, '--clean') call assert_equal(['E34: No previous command', 'done'], readfile('Xtestdone')) endif call delete('Xtestdone') endfunc " vim: shiftwidth=2 sts=2 expandtab