[LFS Trac] #5982: vim-9.2.0843 (Security Update)

LFS Trac ([email protected] via lfs-book Mailing List) <[email protected]> Fri, 24 Jul 2026 17:40:44 -0000
Newsgroups gmane.linux.lfs.book
Message-ID <[email protected]>
This is a multi-part message in MIME format...

------------=_1784914847-1024790-5752
Content-Type: multipart/related;
 boundary="===============3868538093036280515=="

--===============3868538093036280515==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit

#5982: vim-9.2.0843 (Security Update)
-------------------------+----------------------
 Reporter:  Joe Locash   |      Owner:  lfs-book
     Type:  enhancement  |     Status:  new
 Priority:  normal       |  Milestone:  13.1
Component:  Book         |    Version:  git
 Severity:  normal       |   Keywords:
-------------------------+----------------------
 5 CVE's have been fixed.

 {{{
 Arbitrary Code Execution via Shell Keyword Lookup in Vim < 9.2.0839
 ===================================================================

 Date: 23.07.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Improper Neutralization of Special Elements used in an OS Command
      (CWE-78)

 ## Summary

 The shell filetype plugins `runtime/ftplugin/sh.vim` and
 `runtime/ftplugin/zsh.vim` install a buffer-local `keywordprg` that
 interpolates its argument into a `bash -c` or `zsh -c` command without
 shell escaping.  Because a `keywordprg` beginning with `:` is escaped with
 `fnameescape()`, which does not neutralize shell metacharacters, and
 because
 `K` in Visual mode passes the whole selection verbatim, a crafted line in
 a
 shell script can execute arbitrary commands when the user selects it and
 presses `K`.  `runtime/ftplugin/ps1.vim` is affected in the same way
 through
 PowerShell.

 ## Description

 When a buffer's filetype resolves to bash, zsh or PowerShell, the bundled
 filetype plugin defines a keyword lookup command and points `keywordprg`
 at
 it, for example:

     command! -buffer -nargs=1 ShKeywordPrg silent exe
       \ ':hor term bash -c "help "<args>" 2>/dev/null || man "<args>""'
     setlocal keywordprg=:ShKeywordPrg

 For a `keywordprg` that starts with `:`, Vim escapes the argument of `K`
 with `vim_strsave_fnameescape()` (`src/normal.c`), which uses
 `PATH_ESC_CHARS` (`src/vim.h`).  That set omits the shell metacharacters
 `;`, `&`, `(`, `)` and `>`; those appear only in `SHELL_ESC_CHARS`, which
 is
 used exclusively for a `keywordprg` that is not an Ex command.  The
 filetype
 plugin adds no escaping of its own, so these characters reach the inner
 `bash -c` unchanged and terminate the intended command.

 In Visual mode, `K` passes the entire selection rather than the keyword
 under the cursor, so shell metacharacters are preserved.  In Normal mode
 the
 argument is restricted to 'iskeyword' characters, which excludes these
 metacharacters, and the issue does not arise.

 The same pattern applies to `runtime/ftplugin/zsh.vim`, which builds a
 `zsh -c` command, and to `runtime/ftplugin/ps1.vim`, which passes the
 argument to PowerShell via `-Command`.

 ## Impact

 Arbitrary operating-system command execution in the context of the user
 running Vim.  Exploitation requires:

 - Vim with filetype plugins enabled
 - the buffer's filetype resolving to sh, bash, zsh or PowerShell
 - the victim opening a crafted file, selecting the crafted line in Visual
   mode and invoking the keyword lookup with `K`.

 The severity is rated Medium because Normal-mode `K` is not affected and
 exploitation requires the victim to deliberately select the crafted text
 in
 Visual mode and invoke the keyword lookup; the bug does not fire on
 file-open alone.

 ## Acknowledgements

 The Vim project would like to thank Github user @manus-use for reporting
 the issue.

 ## References

 The issue has been fixed as of Vim patch
 [v9.2.0839](https://github.com/vim/vim/releases/tag/v9.2.0839).

 -
 [Commit](https://github.com/vim/vim/commit/c5a82fe013e73c98004ad7cd4f906b1ad1ed610e)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-
 r5v6-q6j8-8qw2)
 }}}

 {{{
 Arbitrary Code Execution via Netrw Menu Construction in Vim < 9.2.0840
 =======================================================================

 Date: 23.07.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Improper Control of Generation of Code (CWE-94),
      Incomplete List of Disallowed Inputs (CWE-184)

 ## Summary

 The netrw file browser builds its Bookmarks, History and Targets menus by
 interpolating directory paths into `:execute`d `:menu` commands.  The
 paths
 are escaped with the character set in `g:netrw_menu_escape`, which did not
 include the Ex command separator `|`.  Because `:menu` treats an unescaped
 bar as the end of the command, a directory path containing a bar
 terminates
 the `:menu` command and the remainder of the path is executed as Ex
 commands, and via `:!` as operating-system commands.  Two of the affected
 sites additionally interpolate the path into a single-quoted Vim string
 without neutralizing the quote.

 ## Description

 `runtime/plugin/netrwPlugin.vim` loads the netrw package on startup, so no
 opt-in is required.  While browsing, netrw records visited directories in
 its history and rebuilds its menus, calling `s:NetrwBookmarkMenu()` and
 `s:NetrwTgtMenu()` in `runtime/pack/dist/opt/netrw/autoload/netrw.vim`.
 Those functions construct the menu entries by concatenation, for example:

     let bmd = escape(bmd, g:netrw_menu_escape)
     exe 'sil! menu ' .. ... .. 'Bookmarks.' .. bmd .. '    :e ' .. bmd ..
 "\<cr>"

 `g:netrw_menu_escape` defaulted to `'.&? \'`, which neutralizes characters
 significant to menu rendering but not the bar.  The `:menu` command
 carries
 the `EX_TRLBAR` attribute, so an unescaped bar in the interpolated path
 ends
 the `:menu` command and everything after it is parsed as a further Ex
 command.

 The Targets menu entries additionally embed the path in a single-quoted
 Vim
 string passed to `netrw#MakeTgt()` without escaping, so a path containing
 a
 single quote can terminate that string early and inject Vim script.

 Five construction sites were affected: the bookmark goto and bookmark
 delete
 entries, the history entry, and the bookmark and history entries of the
 Targets menu.

 Menu construction is guarded by `has("gui")`, `has("menu")`,
 `has("gui_running")`, the `'m'` flag in 'guioptions' and `g:netrw_menu`.
 Vim running in a terminal is therefore not affected; the issue applies to
 the GUI version with the menu bar enabled.

 ## Impact

 Arbitrary Ex command execution, and via the `:!` command arbitrary
 operating-system command execution, in the context of the user running
 Vim.
 Exploitation requires:

 - the GUI version of Vim with menus enabled (`has("gui_running")`, the
 `'m'`
   flag in 'guioptions' and `g:netrw_menu` set, which are the defaults),
 - a directory path under the attacker's control, for example on a shared
   filesystem or a remote host browsed over FTP or SFTP,
 - the victim browsing that path with netrw, or bookmarking it, so that it
   enters netrw's history or bookmark list and the menus are rebuilt.

 The severity is rated Medium because the console version of Vim is not
 affected and the crafted path must first be recorded in the bookmark list
 or
 the browsing history.

 ## Acknowledgements

 The Vim project would like to thank David Carliez for reporting the issue.

 ## References

 The issue has been fixed as of Vim patch
 [v9.2.0840](https://github.com/vim/vim/releases/tag/v9.2.0840).

 -
 [Commit](https://github.com/vim/vim/commit/29c6fd090d4520592f8be7d9ec81190edf25ef69)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-rcr7-f3wr-
 22r2)
 }}}

 {{{
 Heap Buffer Overflow in Text Property Handling in Vim < 9.2.0841
 ================================================================

 Date: 23.07.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Integer Overflow or Wraparound (CWE-190),
      Heap-based Buffer Overflow (CWE-122)

 ## Summary

 The number of text properties attached to a line is stored in the memline
 as a 16-bit value.  When adding a property, `prop_add_one()` in
 `src/textprop.c` computes the new count as `(uint16_t)(proplen + 1)`
 without checking the existing count against the 16-bit ceiling.  On a line
 that already holds 65535 text properties the increment wraps to zero, so
 the buffer allocated for the rewritten line reserves no space for any
 property records, while the existing records are then copied into it.
 This
 writes far past the end of the allocation.

 ## Description

 Text properties are stored inline in the memline entry for a line, in the
 layout `[text][NUL][prop_count][textprop_T...][vtext...]`, where
 `prop_count` is a `uint16_t`.  When `prop_add()` adds a property,
 `prop_add_one()` obtains the current count from `get_text_props()` and
 computes the new one:

     uint16_t new_propcount = (uint16_t)(proplen + 1);

 The size of the replacement line is then derived from that value:

     new_line_len = (int)textlen + (int)PROP_COUNT_SIZE
                     + new_propcount * (int)sizeof(textprop_T)
                     + vtext_total;
     newtext = alloc(new_line_len);

 When `proplen` is already 65535, `proplen + 1` is 65536, which does not
 fit
 in a `uint16_t` and truncates to zero.  The allocation therefore contains
 room for the line text and the count field but for no property records at
 all.  The subsequent copies, which move the existing records into the new
 buffer, are driven by `proplen` rather than by the truncated count, so all
 65535 existing records are written into a buffer sized for none of them.

 The existing validation of the property block, added in patch 9.2.0670,
 checks the structural consistency of the stored data but does not impose
 an
 upper bound on the property count, so nothing prevents a line from
 reaching
 65535 properties.

 The data written past the allocation consists of the existing `textprop_T`
 records, whose field values derive from the arguments of earlier
 `prop_add()` calls.

 ## Impact

 An out-of-bounds heap write of attacker-influenced data, which typically
 results in a crash and may be usable for further exploitation.
 Exploitation requires:

 - Vim built with the `textprop` feature, which is included in the "huge"
   feature set used by most distributions,
 - 65536 text properties being added to a single line of a buffer, either
 by
   a Vim script the user runs, or by a plugin that derives text properties
   from data the attacker controls, such as the contents of an opened file.

 The severity is rated Medium because reaching the 16-bit ceiling on a
 single line does not occur in normal use and requires either a script
 written for the purpose or a plugin driven with crafted input.

 ## Acknowledgements

 The Vim project would like to thank Github user @Wang1rrr for reporting
 the issue.

 ## References

 The issue has been fixed as of Vim patch
 [v9.2.0841](https://github.com/vim/vim/releases/tag/v9.2.0841).

 -
 [Commit](https://github.com/vim/vim/commit/a9336b476fd1a182e3f79b5f83c0ffb04f8a922b)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-hm4g-pjfx-
 m27j)
 }}}

 {{{
 Stack Buffer Overflow in the Vim Socket Server in Vim < 9.2.0842
 =================================================================

 Date: 23.07.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Stack-based Buffer Overflow (CWE-121),
      Out-of-bounds Write (CWE-787)

 ## Summary

 The socket server backend of Vim's client-server feature accepted an
 unbounded number of client connections.  Every accepted connection becomes
 a
 channel with its own file descriptor, and each wait cycle of the main loop
 adds all channel descriptors to fixed-size structures: an `fd_set` when
 Vim
 uses `select()`, or a stack array of `struct pollfd` sized for a small
 fixed
 number of channels when Vim uses `poll()`.  Neither the number of accepted
 clients nor the value of a descriptor was checked against those limits, so
 a
 process able to connect to the server socket can make Vim write past the
 end
 of a stack object.

 ## Description

 A Vim server started with `--servername` and the socket backend listens on
 a
 unix domain socket, or on a loopback address when a `channel:` address is
 used.  Each accepted connection is turned into a channel by
 `socketserver_accept()` in `src/socketserver.c` and linked into both the
 client list and the global channel list, without any limit on the number
 of
 clients.

 On builds that use `select()`, `channel_select_setup()` in `src/channel.c`
 adds every channel descriptor to an `fd_set` with `FD_SET()`.  An `fd_set`
 holds a fixed number of descriptors, given by `FD_SETSIZE`, which is 1024
 on
 common systems.  A descriptor greater than or equal to that value writes
 past the end of the set, and the following `select()` call causes the
 kernel
 to read and write back beyond it as well.  The same unchecked pattern was
 present in `channel_fill_wfds()`, `channel_select_check()` and in the
 client
 loop of `socketserver_wait()`.

 On builds that use `poll()` instead, `socketserver_wait()` and
 `RealWaitForChar()` in `src/os_unix.c` collect the descriptors in a stack
 array of `struct pollfd` dimensioned by `MAX_OPEN_CHANNELS`, which is ten.
 Here no unusual descriptor numbers are required: the array is exceeded
 once
 more than about ten clients are connected.

 Reaching a descriptor number of 1024 or more on the `select()` path
 requires
 the process limit on open files to be higher than that value, which is the
 case for services and desktop sessions on current systems, but not where
 the
 limit is left at 1024.  On the `poll()` path no such condition applies.

 The issue has been addressed by limiting the number of simultaneously
 accepted client connections, by checking descriptors against `FD_SETSIZE`
 before adding them to an `fd_set`, and by sizing the `struct pollfd`
 arrays
 for the new limit.

 ## Impact

 An out-of-bounds write to a stack object.  On the builds shipped by most
 distributions, which enable `_FORTIFY_SOURCE`, the affected library
 routine
 detects the condition and terminates the process, so the practical result
 is
 that the Vim server is killed and unsaved changes are lost.  On builds
 without that hardening the write is a single bit at an offset determined
 by
 the descriptor number, together with the kernel writing back past the set.

 Exploitation requires:

 - Vim built with the socket server backend of the client-server feature
 and
   running as a server, that is started with `--servername`,
 - a process able to connect to that server: for the default unix domain
   socket, one running under the same user account, since the socket
   directory is only accessible to its owner; for a `channel:` address, any
   process on the local machine, since such addresses are bound to the
   loopback interface,
 - on builds using `select()`, a limit on open files above 1024 and enough
   connections to exceed it; on builds using `poll()`, about ten
   connections.

 No action by the user of the Vim server is required, since an idle server
 reaches the affected code continuously.

 The severity is rated Medium because the impact is limited to
 availability,
 the attacker must already be able to reach the server socket, and on the
 `select()` path a raised limit on open files is required as well.

 ## Acknowledgements

 The Vim project would like to thank @tdjackey for reporting the issue.

 ## References

 The issue has been fixed as of Vim patch
 [v9.2.0842](https://github.com/vim/vim/releases/tag/v9.2.0842).

 -
 [Commit](https://github.com/vim/vim/commit/2e967091c3c78cab4524609aa67fbca49e10a32d)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-49m8-wwxj-
 mr69)
 }}}

 {{{
 Out-of-bounds Access in Popup Opacity Handling in Vim >= 9.2.0469 && Vim <
 9.2.0843
 ===================================================================================

 Date: 23.07.2026
 Severity: Medium
 CVE: *requested, not yet assigned*
 CWE: Buffer Underwrite (CWE-124),
      Out-of-bounds Read (CWE-125)

 ## Summary

 A popup window created with the "clipwindow" option is clipped to its host
 window rather than to the screen.  When such a popup is anchored to a text
 property and the host window is scrolled so that the anchor moves above
 the
 visible area, the popup's window row is negative by design, and the rows
 clipped off the top are recorded separately.  The code that marks the
 screen
 cells covered by a popup using the "opacity" option did not account for
 this: it iterated from the popup's window row without a lower bound, so it
 indexed the screen-sized array before its start.  This causes a read
 outside
 the allocated array, and a write outside it when the stored value is
 smaller
 than the popup's z-index.

 ## Description

 `popup_mark_opacity_zindex()` in `src/popupwin.c` fills an array holding,
 for
 each screen cell, the highest z-index of an opacity popup covering that
 cell.  The array is allocated for the current screen size, and the cell
 offset is computed as the row multiplied by the number of screen columns
 plus the column.

 The loop over the popup's rows was bounded above, by the popup height and
 by
 the number of screen rows, but not below.  For a "clipwindow" popup whose
 anchor has scrolled above the top of the host window, the window row is
 negative, so the computed offset is negative as well and refers to memory
 before the array.  The value found there is compared with the popup's
 z-index, which is set from Vim script, and overwritten when it is smaller.

 The column dimension is not affected, because the popup's window column is
 always clamped to a non-negative value.  A related function that reads the
 same array checks its arguments before indexing, so only the marking code
 was affected.

 The issue has been addressed by making the popup's window row always refer
 to the first visible row, and recording the rows clipped off the top only
 in
 the separate top offset, so that no consumer of the window row has to
 clamp
 it.

 ## Impact

 A read outside the bounds of a heap array, and a conditional write of a
 16-bit value outside it.  The written value comes from the popup's z-index
 and the affected offsets follow from the scroll position and the popup
 geometry, so both are influenced by the Vim script that creates the popup.
 In a default layout the accesses fall into a neighbouring array used for
 the
 popup mask, and the editor continues to run, so the effect is silent.

 Exploitation requires Vim script that creates a popup using the
 "clipwindow", "opacity" and text property anchor options together, and a
 host window that is scrolled so the anchor leaves the visible area.  The
 issue is therefore reachable from a plugin or from a script the user runs,
 but not from opening a file, since a modeline cannot call functions.

 The severity is rated Medium because the affected code can only be reached
 by running Vim script, and because the write is constrained: it stores a
 16-bit value and only where the value already present is smaller, so it
 can
 raise the affected memory but not set it to an arbitrary value.

 ## Acknowledgements

 The Vim project would like to thank @tdjackey for reporting the issue.

 ## References

 The issue has been fixed as of Vim patch
 [v9.2.0843](https://github.com/vim/vim/releases/tag/v9.2.0843).

 -
 [Commit](https://github.com/vim/vim/commit/975e191dc817d8d00abca7197c4529a417c2f805)
 - [Github Security
 Advisory](https://github.com/vim/vim/security/advisories/GHSA-pmvp-6rcj-
 98p4)
 }}}
-- 
Ticket URL: <https://wiki.linuxfromscratch.org/lfs/ticket/5982>
LFS Trac <https://wiki.linuxfromscratch.org/lfs/>
Linux From Scratch: Your Distro, Your Rules.

--===============3868538093036280515==--

------------=_1784914847-1024790-5752
Content-Type: text/plain; charset="UTF-8"
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0

-- 
http://lists.linuxfromscratch.org/sympa/info/lfs-book
Unsubscribe: See the above information page

------------=_1784914847-1024790-5752--