dnkl/foot
41
2.0k
Fork
You've already forked foot
242

Heap OOB read in uri_parse %xx decode #2361

Closed
opened 2026年05月24日 13:11:34 +02:00 by jackoftrade · 1 comment

Foot Version

1.27.0

TERM environment variable

foot

Compositor Name and Version

sway 1.11

Distribution

arch

Terminal multiplexer

No response

Shell, TUI, application

No response

Server/standalone mode

  • Standalone
  • Server

Foot config

default

Description of Bug and Steps to Reproduce

uri.c uri_parse, in the path %xx decode loop:

if (hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15) {
 *p++ = hex2nibble(next[1]) << 4 | hex2nibble(next[2]);
 ...
} else {
 *p++ = *next;
 ...
}

next points to a '%' returned by memchr inside the path segment. When
that '%' is the last byte of the URI, next[1] reads uri[len]; if it
is a hex digit, next[2] reads uri[len+1]. The short-circuit on next[1]
prevents next[2] from being read only when uri[len] is itself not a
hex digit.

For OSC 7 (osc.c:462), uri is the OSC buffer, which action_osc_end
explicitly null-terminates (vt.c:612). uri[len] = '0円' makes the
short-circuit fire, so the bug is not reachable there.

For selection.c:2150 (fdm_receive_finish_uri, the final URI in a
clipboard text/uri-list payload), uri is ctx->buf.data and len is
ctx->buf.idx. selection.c:2114-2121 grows ctx->buf with xrealloc and
memcpy without writing a terminator. uri[len] is therefore uninitialised
heap memory or, when idx == sz, one byte past the allocation. When
uri[len] happens to be a hex character (about 22/256 chance from
uninitialised data), the decoder then reads uri[len+1], appends the
decoded byte to path, and pastes it into the slave.

Reproduce: as a Wayland clipboard provider, advertise text/uri-list
data ending in something like "file:///x%" with no trailing CR or LF,
then have the foot user paste from clipboard. The OOB read fires when
foot processes the final URI.

Fix: in the decode loop, only read next[1] and next[2] when they are
within [encoded, encoded + encoded_len). Equivalent: require
encoded_len >= 3 before treating it as a %xx escape, otherwise emit a
literal '%' and advance by one.

Relevant logs, stacktraces, etc.

No response

### Foot Version 1.27.0 ### TERM environment variable foot ### Compositor Name and Version sway 1.11 ### Distribution arch ### Terminal multiplexer _No response_ ### Shell, TUI, application _No response_ ### Server/standalone mode - [ ] Standalone - [ ] Server ### Foot config ```ini default ``` ### Description of Bug and Steps to Reproduce uri.c uri_parse, in the path %xx decode loop: if (hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15) { *p++ = hex2nibble(next[1]) << 4 | hex2nibble(next[2]); ... } else { *p++ = *next; ... } next points to a '%' returned by memchr inside the path segment. When that '%' is the last byte of the URI, next[1] reads uri[len]; if it is a hex digit, next[2] reads uri[len+1]. The short-circuit on next[1] prevents next[2] from being read only when uri[len] is itself not a hex digit. For OSC 7 (osc.c:462), uri is the OSC buffer, which action_osc_end explicitly null-terminates (vt.c:612). uri[len] = '0円' makes the short-circuit fire, so the bug is not reachable there. For selection.c:2150 (fdm_receive_finish_uri, the final URI in a clipboard text/uri-list payload), uri is ctx->buf.data and len is ctx->buf.idx. selection.c:2114-2121 grows ctx->buf with xrealloc and memcpy without writing a terminator. uri[len] is therefore uninitialised heap memory or, when idx == sz, one byte past the allocation. When uri[len] happens to be a hex character (about 22/256 chance from uninitialised data), the decoder then reads uri[len+1], appends the decoded byte to path, and pastes it into the slave. Reproduce: as a Wayland clipboard provider, advertise text/uri-list data ending in something like "file:///x%" with no trailing CR or LF, then have the foot user paste from clipboard. The OOB read fires when foot processes the final URI. Fix: in the decode loop, only read next[1] and next[2] when they are within [encoded, encoded + encoded_len). Equivalent: require encoded_len >= 3 before treating it as a %xx escape, otherwise emit a literal '%' and advance by one. ### Relevant logs, stacktraces, etc. _No response_
Owner
Copy link

Duplicate of #2353

Duplicate of https://codeberg.org/dnkl/foot/issues/2353
dnkl 2026年06月12日 18:16:34 +02:00
Sign in to join this conversation.
No Branch/Tag specified
master
osc-5522
sixel-heap-buffer-overflow
releases/1.27
releases/1.26
releases/1.25
releases/1.24
multi-cursor
releases/1.23
pixman-16f-2
releases/1.22
releases/1.21
releases/1.20
releases/1.19
releases/1.18
releases/1.17
releases/1.16
releases/1.15
releases/1.14
releases/1.13
releases/1.12
releases/1.11
releases/1.10
releases/1.9
releases/1.8
releases/1.7
releases/1.6
releases/1.5
releases/1.4
releases/1.3
releases/1.2
releases/1.1
releases/1.0
1.27.0
1.26.1
1.26.0
1.25.0
1.24.0
1.23.1
1.23.0
1.22.3
1.22.2
1.22.1
1.22.0
1.21.0
1.20.2
1.20.1
1.20.0
1.19.0
1.18.1
1.18.0
1.17.2
1.17.1
1.17.0
1.16.2
1.16.1
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.0
1.13.1
1.13.0
1.12.1
1.12.0
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.2
1.9.1
1.9.0
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.3
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
0.9.0
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dnkl/foot#2361
Reference in a new issue
dnkl/foot
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?