Re: [LFS Trac] #5982: vim-9.2.0847 (Security Update) (was: vim-9.2.0843 (Security Update))
LFS Trac ([email protected] via lfs-book Mailing List) <[email protected]> Sat, 25 Jul 2026 19:31:35 -0000
| Newsgroups | gmane.linux.lfs.book |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format...
------------=_1785007898-1024790-5931
Content-Type: multipart/related;
boundary="===============7463204950342342417=="
--===============7463204950342342417==
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
#5982: vim-9.2.0847 (Security Update)
-------------------------+-----------------------
Reporter: Joe Locash | Owner: lfs-book
Type: enhancement | Status: new
Priority: normal | Milestone: 13.1
Component: Book | Version: git
Severity: normal | Resolution:
Keywords: |
-------------------------+-----------------------
Changes (by Joe Locash):
* summary: vim-9.2.0843 (Security Update) => vim-9.2.0847 (Security
Update)
Comment:
4 more:
{{{
Use-after-free in JSON Decoding in Vim >= 9.2.0511 && Vim < 9.2.0844
====================================================================
Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Use After Free (CWE-416),
Out-of-bounds Read (CWE-125)
## Summary
When Vim decodes a JSON message received on a channel, the decoder may
need
more bytes than the current read buffer holds. It then obtains the next
buffer, joins the two into a newly allocated one and frees the previous
buffer. The function decoding the surrounding item keeps its own pointer
into the old buffer and does not refresh it after such a refill. When the
decoding of a string fails after a refill has taken place, for example
because of an invalid escape sequence, the shared error path passes that
stale pointer to the routine that formats the error message, which reads
the
freed memory.
## Description
Channel JSON decoding uses a reader that can request more input while an
item is being parsed. `channel_fill()` in `src/channel.c` obtains the
next
queued read buffer, allocates a combined buffer holding the unparsed
remainder followed by the new data, frees the previous buffer and stores
the
new one in the reader.
`json_decode_string()` in `src/json.c` handles this correctly: before
asking
for more input it converts its position into an index, and it recomputes
its
pointer from the reader afterwards. `json_decode_item()`, which parses
the
enclosing value, keeps a separate pointer into the buffer. That pointer
is
refreshed at several points in its loop, but not after the call that
decodes
a string. If that call first triggers a refill and then fails, the buffer
the pointer refers to has been freed, and the error path at the end of the
function reports the position using it. The error text is composed from
the
memory at that address, so the freed buffer is read.
Any channel using one of the JSON based modes is affected, since the
reader
is always given the ability to refill. A peer that writes a message in
parts controls where the input is split, and therefore whether the refill
happens in the middle of a string.
The socket server backend of the client-server feature is reachable
without
any authentication: it decodes whatever bytes a client has sent, before
any
field of the message is examined, so a client can trigger the condition
with
two writes and without a valid message.
## Impact
A read of freed heap memory. The bytes read are used to compose an error
message, which is suppressed while a channel message is decoded and is
only
recorded when channel logging has been enabled, so the contents are
normally
not shown anywhere. Depending on the state of the heap the read can also
fault and end the Vim process, which for a server means the loss of
unsaved
changes.
Exploitation requires:
- Vim decoding JSON from a channel, either a channel opened by the user in
one of the JSON based modes, or the socket server backend of the
client-server feature, which is used when Vim is started with
`--servername` and that backend,
- a peer that can send a message split into parts, which for the socket
server means any process able to connect to it: one running under the
same
user account for the default unix domain socket, or any process on the
local machine for a `channel:` address, since those are bound to the
loopback interface.
The severity is rated Medium because the impact is limited to reading
freed
memory and, where that memory is no longer mapped, to ending the process;
the contents that are read are not returned to the peer and are normally
not
displayed.
## 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.0844](https://github.com/vim/vim/releases/tag/v9.2.0844).
-
[Commit](https://github.com/vim/vim/commit/f8126294a526aa80c5123eb3079e325daee9ec75)
- [Github Security
Advisory](https://github.com/vim/vim/security/advisories/GHSA-69ch-
22ch-r887)
}}}
{{{
Arbitrary Ex Command Execution in C Omni-Completion in Vim < 9.2.0845
======================================================================
Date: 23.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Control of Generation of Code ('Code Injection') (CWE-94),
Inclusion of Functionality from Untrusted Control Sphere (CWE-829)
## Summary
The C omni-completion script in `runtime/autoload/ccomplete.vim` looks up
struct members by building a `:vimgrep` command that contains the type
name
taken from the `typeref:` field of a tags file entry, and running it with
`:execute`. The value was escaped only for the pattern delimiter and the
backslash. That is not sufficient: a value containing an unterminated
collection makes Vim's own pattern skipping fail, after which the command
parser looks for a command separator across the whole argument. A crafted
tags file can therefore run arbitrary Ex commands, and through them shell
commands, when the user invokes omni-completion on a member access.
This is a bypass of the fix released as patch v9.2.0735 for
GHSA-mf92-v4xw-j45x, which prevented the same injection only for values
containing the pattern delimiter.
## Description
`runtime/ftplugin/c.vim` sets `omnifunc=ccomplete#Complete` on C buffers
when filetype plugins are enabled. When completing a member access, and
the
declaration is not found in the buffer itself, `StructMembers()` searches
the
files listed in the tags file:
execute 'silent! keepjumps noautocmd '
.. n .. 'vimgrep ' .. '/\t' .. escape(typename, '/\') ..
'\(\t\|$\)/j '
.. fnames
`typename` comes verbatim from the `typeref:` or `typename:` extension
field
of a tags entry, which Vim returns unchanged.
The `:vimgrep` command may be followed by another command after a bar, so
before looking for that bar Vim first skips over the search pattern. When
skipping the pattern does not end at the closing delimiter, the routine
returns a failure and the caller silently falls back to the beginning of
the
argument, after which the first unescaped bar is treated as a command
separator.
Skipping the pattern fails on an unterminated collection: an opening
bracket
makes the pattern skipping look for the matching closing bracket and run
to
the end of the text instead. A `typeref:` value that opens a bracket and
then contains a bar therefore ends the `:vimgrep` command early, and what
follows the bar is executed as an Ex command. No delimiter character is
needed, so the escaping applied by the earlier fix does not prevent it.
The
leading `:silent!` suppresses the resulting error, so the injected command
runs without a visible failure.
The issue has been addressed by matching the field literally, using the
"very nomagic" mode for the part of the pattern that holds the value, so
that no character in it can affect how the pattern is parsed.
## Impact
Arbitrary Ex command execution, and through commands such as `:!`
arbitrary
operating-system command execution, in the context of the user running
Vim.
Exploitation requires:
- Vim with filetype plugins enabled, which is the default in
`runtime/defaults.vim` and in most distribution configurations, so that
the C omni-completion function is installed on C buffers,
- a tags file under the attacker's control, which is ordinary data to
receive together with source code, for example in a cloned repository or
an unpacked archive,
- the victim opening a C file from that tree and invoking omni-completion
with `CTRL-X CTRL-O` on a member access whose type is only known from
the
tags file.
The severity is rated Medium because the crafted tags file has no effect
until the user invokes omni-completion, which is a deliberate action, and
because the type must not be declared in the edited buffer, since the
completion would otherwise not consult the tags file at all.
## Acknowledgements
The Vim project would like to thank Threonine for reporting the issue.
## References
The issue has been fixed as of Vim patch
[v9.2.0845](https://github.com/vim/vim/releases/tag/v9.2.0845).
-
[Commit](https://github.com/vim/vim/commit/2f628d8104958fa7421664f792ca6d4f7a39a10f)
- [Github Security
Advisory](https://github.com/vim/vim/security/advisories/GHSA-cx73-phcg-
3j5g)
}}}
{{{
Heap Buffer Overflow when Loading a Spell File in Vim < 9.2.0846
================================================================
Date: 24.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Heap-based Buffer Overflow (CWE-122),
Out-of-bounds Write (CWE-787)
## Summary
A spell file may contain a section holding sound-folding rules and a
section
holding a simple character mapping used for the same purpose. Reading the
first of these fills an index table with the value minus one for every
entry.
Reading the second uses that same table to count how many mappings share a
byte, but did not reset it beforehand, so every count came out one too
low.
The buffer allocated from that count is then too small for the mappings
that
are stored into it, and the surplus is written past its end. A crafted
spell
file therefore causes an out-of-bounds write when it is loaded, with part
of
the written data taken from the file.
## Description
Vim loads a spell file when a language is selected with the 'spelllang'
option. The file is a sequence of sections, and the loader in
`src/spellfile.c` dispatches on the section identifier without imposing an
order on them or requiring them to be unique.
Reading the sound-folding section ends with a call to `set_sal_first()`,
which sets all 256 entries of the language's first-index table to minus
one.
This happens even when that section contains no rules at all.
Reading the character mapping section calls `set_sofo()`, which reuses the
same table as a temporary counter. For every mapped character above 255
it
increments the entry belonging to the low byte of that character,
allocates
one list per entry from the resulting counts, and only afterwards clears
the
table again. Since the counting started from minus one rather than zero,
each count is one too low. For a byte value used by two mapped characters
the list is allocated for one pair and two are written into it, so the
storing loop writes past the end of the allocation; part of what is
written
is the mapped-to character taken from the file. For a byte value used by
exactly one mapped character the count becomes zero, no list is allocated
at
all, and the storing loop follows a null pointer.
The two sections are mutually exclusive by construction and the tool that
generates spell files never emits both, but nothing in the loader rejected
a
file that contains them in that order.
The issue has been addressed by clearing the table before it is used as a
counter.
## Impact
An out-of-bounds write to the heap, or a null pointer dereference, while a
spell file is being loaded. Part of the written data is taken from the
spell file, and the sizes of the other sections in the same file influence
the surrounding heap layout, so the effect is not limited to a crash,
although no further consequence has been demonstrated.
Exploitation requires the victim to load a crafted spell file, which
happens
when 'spelllang' is set to a value naming that file, or to a language for
which the crafted file is found in the directories searched for spell
files.
Vim must be built with the spell checking and multi-byte features, which
is
the case for the "huge" feature set used by most distributions.
The severity is rated Medium because a spell file has to be placed where
Vim
will load it and the option has to be set to select it.
## Acknowledgements
The Vim project would like to thank Yazan Balawneh for reporting the
issue.
## References
The issue has been fixed as of Vim patch
[v9.2.0846](https://github.com/vim/vim/releases/tag/v9.2.0846).
-
[Commit](https://github.com/vim/vim/commit/05c41c922309c7a11b6ec2f124be66551c90d66a)
- [Github Security
Advisory](https://github.com/vim/vim/security/advisories/GHSA-9jqx-hgpr-
6v64)
}}}
{{{
Arbitrary Command Execution via the Vimball Record File in Vim < 9.2.0847
=========================================================================
Date: 24.07.2026
Severity: Medium
CVE: *requested, not yet assigned*
CWE: Improper Control of Generation of Code (CWE-94),
Inclusion of Functionality from Untrusted Control Sphere (CWE-829)
## Summary
The vimball plugin records the files it extracts in a plain text file
named
`.VimballRecord`, so that they can be removed again later. Each line of
that
file holds the commands to undo one installation, and they were executed
without being checked. The plugin refused to extract members whose name
could inject into that file, but it did not refuse a member that *is* the
record file. A crafted vimball can therefore write chosen commands into
the
record, which are then executed the next time any vimball operation
consults
it.
## Description
`runtime/autoload/vimball.vim` writes one line per installed vimball into
`.VimballRecord` in the directory used for vimball installations, listing
the
commands that delete the files that were extracted. When a vimball is
installed or removed, `vimball#RmVimball()` searches that file for the
line
belonging to the archive, strips the archive name from the front of it and
runs the remainder:
sil! keepalt keepjumps exe exestring
The name of each member of an archive was already checked, and names that
contain a bar, a quote or a closing parenthesis were rejected, precisely
so
that a file name could not inject commands into the record. That check
does
not apply to a member whose name is `.VimballRecord` itself: extracting it
overwrites the record with content taken straight from the archive, and
the
content of a member is not examined at all.
The commands placed there are run later, when a vimball with the matching
name is installed or removed, and not while the crafted archive is being
extracted.
The issue has been addressed by refusing to extract a member named
`.VimballRecord`, and by executing only entries of the expected form,
namely
a single call that deletes one file or directory. Anything else in the
record is reported and skipped.
## Impact
Execution of arbitrary Ex commands, and through commands such as `:!`
arbitrary operating-system commands, in the context of the user running
Vim.
Exploitation requires the victim to install a vimball from a source
controlled by the attacker, either by sourcing it or through the getscript
plugin, which downloads and sources vimballs automatically. Installing a
vimball already runs the commands contained in it, so the attacker does
not
gain the ability to run commands as such. What the issue adds is that the
archive itself can appear harmless while leaving commands behind that run
at
a later time, during an unrelated vimball installation or removal, and
that
continue to do so after the archive that placed them has been removed.
The severity is rated Medium because installing a vimball from an
untrusted
source already permits commands from that vimball to run, so the issue
extends the reach of such an installation rather than creating it.
## 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.0847](https://github.com/vim/vim/releases/tag/v9.2.0847).
-
[Commit](https://github.com/vim/vim/commit/581a2f3ac9c6f96a26324f6b2c8c11415fd0d452)
- [Github Security
Advisory](https://github.com/vim/vim/security/advisories/GHSA-r22p-
fhw4-84p2)
}}}
--
Ticket URL: <https://wiki.linuxfromscratch.org/lfs/ticket/5982#comment:1>
LFS Trac <https://wiki.linuxfromscratch.org/lfs/>
Linux From Scratch: Your Distro, Your Rules.
--===============7463204950342342417==--
------------=_1785007898-1024790-5931
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
------------=_1785007898-1024790-5931--