| CVE |
Vendors |
Products |
Updated |
CVSS v3.1 |
| A flaw was found in the libblkid library of util-linux. During nested partition probing, the BSD, Minix, Solaris x86, and UnixWare partition probers cache a raw pointer to a parent partition entry in a dynamically allocated array. When subsequent partition additions cause the array to be reallocated, this pointer becomes stale, leading to a heap use-after-free read. An attacker who can present a crafted block device image (for example, via USB insertion or a loop-mounted disk image) can trigger this flaw without user interaction, as libblkid is invoked automatically by udev/udisks as root on block-device hot-plug events. This could lead to limited information disclosure or denial of service. |
| A flaw was found in util-linux. Restricted bind mounts take the source path from fstab but do not pin that source before the privileged mount. A local unprivileged user who can replace the authorized source or a writable ancestor can redirect SUID mount(8) to bind another host directory. If the fstab entry also sets X-mount.owner, X-mount.group, or X-mount.mode, root then changes ownership or mode on that redirected inode. |
| The nsenter --join-cgroup option opens the target cgroup.procs file as root and leaves that file descriptor open across later namespace and credential changes and across execve(). Because the kernel checks later cgroup migrations using the credentials from the original open, a program run in an attacker-controlled target can inherit root's ability to move host processes between cgroups. After a privileged operator uses --join-cgroup against that target, an unprivileged user can migrate and terminate unrelated root processes. |
| In the Linux kernel, the following vulnerability has been resolved:
ring-buffer: Fix the sub-buffer array base in rb_meta_subbuf_idx()
On a persistent ring buffer, rb_meta_subbuf_idx() can return an index one
sub-buffer too high. rb_setup_ids_meta_page() then fills subbuf_ids[]
shifted by one and leaves subbuf_ids[0] NULL, which __rb_map_vma()
dereferences when userspace maps trace_pipe_raw. rb_update_meta_reader()
writes two such indices into meta->buffers[], which rb_cpu_meta_valid()
would reject on the next boot, discarding the previous boot's trace.
A CPU's sub-buffer array starts after its meta header and the nr_subbufs
integers that follow, aligned up to a sub-buffer. rb_meta_subbuf_idx()
inverts that calculation but skips only the integers, not the header, so
its base is one sub-buffer low whenever the omitted header size crosses
the alignment boundary.
Invert the calculation with rb_subbufs_from_meta() rather than repeating
it. rb_range_buffer() maps an index back to an address through the same
helper, so the two directions can no longer disagree. |
| In the Linux kernel, the following vulnerability has been resolved:
scsi: libiscsi: Reject a negative task index from parse_pdu_itt
A transport that implements parse_pdu_itt hands libiscsi an index taken
from the PDU, and both lookups bound it from above only:
if (i >= session->cmds_max)
i and cmds_max are both int, so a negative index passes and
session->cmds[i] is read from before the array.
be2iscsi produces one. beiscsi_parse_pdu() assigns the raw tag,
*index = (int)itt;
and beiscsi_complete_pdu() forwards an unsolicited NOP-In from the
hardware async ring without replacing its ITT, so the value is the
target's. It also reports the session's own age rather than the one in
the tag, which leaves the age comparison in iscsi_verify_itt() with
nothing to reject.
Bound the index from below in both lookups. |
| In the Linux kernel, the following vulnerability has been resolved:
scsi: st: Fix use-after-free race between st_remove() and st_open()
st_remove() drops the probe reference on the scsi_tape with kref_put()
and only afterwards removes its index from st_index_idr. If that was the
last reference, scsi_tape_release() frees the structure while it is
still published in the idr.
scsi_tape_get(), called from st_open(), looks up the tape in
st_index_idr and takes a reference under st_ref_mutex and
st_index_lock. remove_cdevs() does not wait for opens that are already
past chrdev_open(), so an open that is blocked on st_ref_mutex while
st_remove() holds it can take the mutex as soon as st_remove() drops it,
find the freed tpnt in the idr and call kref_get() on it:
BUG: KASAN: slab-use-after-free in st_open
Write of size 4 ...
st_open (drivers/scsi/st.c:254 drivers/scsi/st.c:1291)
chrdev_open
...
Freed by task ...:
kfree
st_remove (drivers/scsi/st.c:4512)
Remove the index from the idr before dropping the reference, all under
st_ref_mutex. A concurrent scsi_tape_get() now either runs first and
holds a valid reference that keeps the tape alive, or runs afterwards
and finds nothing, so st_open() fails with -ENXIO.
This restores the ordering st_remove() had before the conversion to
st_index_idr, where the tape was unpublished from scsi_tapes[] before
the final kref_put(). |
| In the Linux kernel, the following vulnerability has been resolved:
ring-buffer: Fix false warning in ring_buffer_map_get_reader()
The mmap reader can warn when it catches up with a writer that is still
committing events. rb_get_reader_page() returns NULL in this case, but
ring_buffer_map_get_reader() treats that result as an error.
The initial rb_per_cpu_empty() check filters out an empty buffer, but it
does not guarantee that the next reader page has committed data. Writers
do not take reader_lock and can advance commit_page before publishing the
committed length on the new page. rb_get_reader_page() can swap to that
page, catch up with the writer and return NULL.
Handle NULL through the existing no-data exit without warning. Remove the
caller's reader_page == commit_page check as well, since the reader-page
helper already handles that case. The existing metadata update and return
path remain in place. |
| In the Linux kernel, the following vulnerability has been resolved:
ring-buffer: Do not show buffer_meta for CPUs without a buffer
The per_cpu/cpuN/buffer_meta files are created for every possible CPU,
but buffer->buffers[cpu] is only allocated once that CPU comes online.
Reading the file of a CPU that never came online dereferences a NULL
cpu_buffer in rbm_start().
Fail the open with -ENODEV when the CPU has no buffer, as the other
per CPU ring buffer interfaces do. |
| In the Linux kernel, the following vulnerability has been resolved:
i2c: viai2c-wmt: Fix clock leak in wmt_i2c_probe()
In wmt_i2c_probe(), i2c->clk is acquired using of_clk_get(). If any
subsequent operation fails or when the module is unloaded, the clock
reference count is never decremented via clk_put(), leading to a
resource leak.
Switch to devm_clk_get() so that the clock is automatically managed
and released. |
| In the Linux kernel, the following vulnerability has been resolved:
gpio: shared: fix use-after-free bug when adding shared proxies
The GPIO lookup table can stay alive for longer than the kobject whose
name string's address we're assigning to lookup->dev_id. Fix a potential
UAF by duplicating the string. |
| In the Linux kernel, the following vulnerability has been resolved:
firewire: core: fix race condition in split transaction handling
For a split transaction, either fw_core_handle_response() or
split_transaction_timeout_callback() may manipulate the same transaction
entry in the pending transaction list. The return value of timer_delete()
is used to determine which function handles the entry. If the transaction
is a split transaction and timer_delete() returns zero, the timeout
callback may already be running. In this case, the response handler must
leave the entry in the list for the timeout callback to remove.
A previous code refactoring broke this behavior, introducing a race
condition in which both functions could process the same transaction.
This could lead to a use-after-free on the transaction initiator side.
Fix the regression by ensuring that the response handler does not process
the transaction when timer_delete() returns zero. The timeout callback is
responsible for removing the entry from the pending transaction list. |
| In the Linux kernel, the following vulnerability has been resolved:
ipv4: free inet_opt and ireq_opt after an RCU grace period
tcp_v4_syn_recv_sock() transfers ownership of ireq->ireq_opt to the
child socket (newinet->inet_opt) without copying it.
Another cpu can concurrently process a retransmitted SYN for the same
request socket, and send a SYNACK from tcp_check_req().
tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt
under rcu_read_lock() only, and ip_build_and_send_pkt() and
ip_options_build() then read opt->optlen twice.
Note that the SYNACK timer itself is not an issue: it holds a
reference on its request socket, and inet_csk_reqsk_queue_drop()
calls timer_delete_sync() before the child can be freed.
Since commit 079096f103fa ("tcp/dccp: install syn_recv requests
into ehash table"), request sockets are processed without holding
the listener lock, so nothing prevents the child socket from being
freed while the SYNACK is still being built. TCP child sockets do
not have SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt
with a plain kfree(), leading to a use-after-free in
ip_options_build().
A similar issue exists with request socket migration
(net.ipv4.tcp_migrate_req=1, or a BPF_SK_REUSEPORT_SELECT_OR_MIGRATE
program). reqsk_timer_handler() clones the request socket with
inet_reqsk_clone(), so that the old request socket and its clone
share the same ireq_opt, then reqsk_migrate_reset() clears the
pointer in the old one. Another cpu holding a reference on the old
request socket can still be using these options (sending a SYNACK,
or creating a child in tcp_v4_syn_recv_sock()) when the clone is
freed, and tcp_v4_reqsk_destructor() also uses a plain kfree().
Readers already use RCU, and other paths replacing inet_opt
(do_ip_setsockopt(), cipso_v4_sock_setattr()...) already use
kfree_rcu(). Use kfree_rcu() in inet_sock_destruct() and
tcp_v4_reqsk_destructor() as well.
IPv6 is not affected by the first issue, because tcp_v6_syn_recv_sock()
duplicates the options. tcp_v6_reqsk_destructor() has the same
migration issue with ipv6_opt, which is only set by CALIPSO. This
will be addressed in a separate patch. |
| In the Linux kernel, the following vulnerability has been resolved:
scsi: libiscsi: Validate the ITT reflected in a Reject PDU
A Reject PDU carries a copy of the header it rejects, and
iscsi_handle_reject() takes the ITT out of that copy to find the task to
clean up:
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
...
task = iscsi_itt_to_task(conn, rejected_pdu.itt);
That value is whatever the target put there. iscsi_itt_to_task() bounds
the index against cmds_max and checks nothing else, so any task in the
pool can be named, and iscsi_nop_out_rsp() then completes it.
An index that has never been used gives a NULL task->conn: the pool is
zeroed at session setup and conn is assigned only when a task is
allocated. If the task was used and returned, iscsi_complete_task() hits
its WARN_ON_ONCE(task->state == ISCSI_TASK_FREE) and the refcount
underflows. An in-flight SCSI command is completed as successful - a 1
MiB read returned 1048576 with none of its buffer written and no
warning.
Validate the reflected ITT the way iscsi_itt_to_ctask() validates a
command ITT, and require the task to be in flight and not a SCSI
command.
[ 6.248477] Oops: general protection fault, probably for non-canonical address 0xdffffc000000000c: 0000 [#1] SMP KASAN NOPTI
[ 6.249357] KASAN: null-ptr-deref in range [0x0000000000000060-0x0000000000000067]
[ 6.249951] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted 7.2.0-rc5-ISCSI1-gf5098b6bae76 #1 PREEMPT(lazy)
[ 6.250718] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 6.251616] RIP: 0010:iscsi_nop_out_rsp.constprop.0+0x46/0x160
[ 6.252043] Code: c1 ea 03 48 83 ec 08 80 3c 02 00 0f 85 f5 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 58 48 8d 7d 60 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 c0 00 00 00 48 8b 45 60 48 39 c3 74 50 48 b8 00
[ 6.252813] RSP: 0018:ffff88806c907b80 EFLAGS: 00010206
[ 6.253042] RAX: dffffc0000000000 RBX: ffff88800607e000 RCX: ffffffff8d571a25
[ 6.253345] RDX: 000000000000000c RSI: ffff88806c907c38 RDI: 0000000000000060
[ 6.253642] RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff235a504
[ 6.253947] R10: 0000000000000003 R11: 7463656e6e6f6320 R12: 0000000000000000
[ 6.254251] R13: 0000000000000000 R14: ffff88806c907c38 R15: 0000000000000000
[ 6.254549] FS: 0000000000000000(0000) GS:ffff8880d95bc000(0000) knlGS:0000000000000000
[ 6.254887] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6.255140] CR2: 00007fc393e8ffc0 CR3: 0000000005252006 CR4: 0000000000770ef0
[ 6.255439] PKRU: 55555554
[ 6.255564] Call Trace:
[ 6.255674] <IRQ>
[ 6.255768] __iscsi_complete_pdu+0x18bf/0x22a0
[ 6.256733] iscsi_complete_pdu+0x54/0xa0
[ 6.256905] iscsi_tcp_data_recv_done+0xf4/0x250
[ 6.257103] iscsi_tcp_recv_skb+0x31e/0xec0
[ 6.257680] iscsi_sw_tcp_recv+0x12f/0x390
[ 6.258061] __tcp_read_sock+0x1ab/0x810
[ 6.258853] iscsi_sw_tcp_data_ready+0x18b/0x510
[ 6.259808] tcp_data_queue+0x1f13/0x4cd0
[ 6.260567] tcp_rcv_established+0x8a5/0x3a00
[ 6.261931] tcp_v4_do_rcv+0x449/0x960
[ 6.262269] tcp_v4_rcv+0x2245/0x3bc0 |
| In the Linux kernel, the following vulnerability has been resolved:
spi: imx: fix slab corruption from undersized DMA bounce buffers
Since commit faa8e404ad8e ("spi: imx: support dynamic burst length for
ECSPI DMA mode"), the driver allocates its private DMA TX/RX buffers
with kzalloc(dma_len), where dma_len is only rounded up to 4 bytes, but
maps, syncs and unmaps them with DMA_CACHE_ALIGNED_LEN(dma_len), i.e.
rounded up to the cache line size. As a result, the DMA API operates on
memory beyond the end of the allocation.
This was observed on a custom i.MX8MP platform with an mcp251xfd CAN
controller under heavy RPMSG load, as a series of refcount_t warnings
triggered from rpmsg_recv_done() in virtio_rpmsg_bus:
refcount_t: addition on 0; use-after-free.
refcount_t: underflow; use-after-free.
refcount_t: saturated; leaking memory.
Leading finally to an "Unable to handle kernel paging request" oops.
Reproducing this problem took between 30 minutes and roughly 30 hours
under the same workload.
Hardware watchpoints on the refcount of a struct rpmsg_endpoint showed
it was overwritten from 2 to 1 by __pi_memcpy_generic() in the
irq/155-spi2.0 thread. Additionally it was found that a "normal"
rpmsg_recv_done() took 11µs +/-2µs from its kref_get to kref_put. In
the error case the same sequence took about 215µs +/-10µs. Based on
this, an LLM was used to identify the size mismatch fixed here.
Allocate the buffers with DMA_CACHE_ALIGNED_LEN(dma_len) so they cover
the full mapped length, and use the same length for
dma_sync_single_for_cpu() to stay consistent with map and unmap.
With this patch applied, the same workload ran for more than 200 hours
without the problem reproducing. |
| In the Linux kernel, the following vulnerability has been resolved:
vsock: treat TCP_CLOSING as once-established
Handle the TCP_ESTABLISHED -> TCP_CLOSING transition on OP_RST, which can
race with the connect loop. Immediately break and return 0 on
ESTABLISHED/CLOSING. The return value of connect() should reflect what
happened up to the point the connection was established or failed. Events
that occur afterwards must not affect it. E.g. even if OP_RW has already
set sk_err, connect() should still return 0, not ENOBUFS because of it.
Adapt the inaccurate comment above signal_pending().
Resetting a socket that is still present in connected_table can lead to
memory corruption. The reporter noted lost transports for in-flight skbs,
and I have reproduced crashes caused by re-insertion into connected_table.
list_add double add: new=, prev=, next=.
kernel BUG at lib/list_debug.c:35!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
Workqueue: vsock-loopback vsock_loopback_work
RIP: 0010:__list_add_valid_or_report+0x11f/0x130
Call Trace:
vsock_insert_connected.cold+0xe/0x13
virtio_transport_recv_pkt+0x10e9/0x1460
vsock_loopback_work+0x305/0x480
process_one_work+0xe4c/0x1560
worker_thread+0x4f1/0xd60
kthread+0x36e/0x470
ret_from_fork+0x47b/0x6b0
ret_from_fork_asm+0x1a/0x30
This fix is supplementary to commit 002541ef650b ("vsock: Ignore
signal/timeout on connect() if already established"). Details under Link. |
| In the Linux kernel, the following vulnerability has been resolved:
scsi: libiscsi: Validate the task named by a management response
__iscsi_complete_pdu() fetches the task for five response types from one
place and checks only that the index resolved:
case ISCSI_OP_LOGOUT_RSP:
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
case ISCSI_OP_SCSI_TMFUNC_RSP:
case ISCSI_OP_NOOP_IN:
task = iscsi_itt_to_task(conn, hdr->itt);
if (!task)
return ISCSI_ERR_BAD_ITT;
iscsi_itt_to_task() bounds the index against cmds_max and looks at
nothing else, so a target can name any slot in the pool, including one
that has never been used. task->conn is then NULL, and both
iscsi_nop_out_rsp() and iscsi_complete_task() dereference it. One
unsolicited NOP-In is enough; a Text Response carrying the same ITT
crashes in iscsi_complete_task() instead.
Require the task to be in flight and not a SCSI command, the way
iscsi_itt_to_ctask() does for the command opcodes.
[ 6.298634] Oops: general protection fault, probably for non-canonical address 0xdffffc000000000c: 0000 [#1] SMP KASAN NOPTI
[ 6.298642] KASAN: null-ptr-deref in range [0x0000000000000060-0x0000000000000067]
[ 6.298652] CPU: 1 UID: 0 PID: 111 Comm: iscsistart Not tainted 7.2.0-rc5-ISCSI1-gf5098b6bae76 #1 PREEMPT(lazy)
[ 6.298654] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 6.298656] RIP: 0010:iscsi_nop_out_rsp.constprop.0+0x46/0x160
[ 6.298691] Code: c1 ea 03 48 83 ec 08 80 3c 02 00 0f 85 f5 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 58 48 8d 7d 60 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 c0 00 00 00 48 8b 45 60 48 39 c3 74 50 48 b8 00
[ 6.298698] RSP: 0018:ffff88806c907be8 EFLAGS: 00010206
[ 6.298701] RAX: dffffc0000000000 RBX: ffff888006116800 RCX: 0000000000000020
[ 6.298702] RDX: 000000000000000c RSI: ffff88800525d578 RDI: 0000000000000060
[ 6.298703] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[ 6.298706] R10: 0000000000000020 R11: 0000000000000000 R12: 0000000000000000
[ 6.298706] R13: 000000000000002e R14: ffff8880056eb440 R15: ffff888006116800
[ 6.298707] FS: 00007fc02d1c2740(0000) GS:ffff8880b29bc000(0000) knlGS:0000000000000000
[ 6.298710] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6.298711] CR2: 000055fe3b56ddf8 CR3: 00000000053b9004 CR4: 0000000000770ef0
[ 6.298712] PKRU: 55555554
[ 6.298713] Call Trace:
[ 6.298714] <IRQ>
[ 6.298714] __iscsi_complete_pdu+0x13a8/0x22a0
[ 6.298758] iscsi_complete_pdu+0x54/0xa0
[ 6.298759] iscsi_tcp_hdr_recv_done+0x870/0x2c80
[ 6.298778] iscsi_tcp_recv_skb+0x31e/0xec0
[ 6.298800] iscsi_sw_tcp_recv+0x12f/0x390
[ 6.298804] __tcp_read_sock+0x1ab/0x810
[ 6.298812] iscsi_sw_tcp_data_ready+0x18b/0x510
[ 6.298814] tcp_rcv_established+0x1f56/0x3a00
[ 6.298842] tcp_v4_do_rcv+0x449/0x960
[ 6.298847] tcp_v4_rcv+0x2245/0x3bc0 |
| In the Linux kernel, the following vulnerability has been resolved:
KVM: SEV: Fix page dirtying in sev_gmem_post_populate()
set_page_dirty() requires that the caller holds some kind of lock to
ensure that the page's mapping does not concurrently go away.
That is not the case for a random page we got from get_user_pages_fast(),
so use set_page_dirty_lock().
[sean: tag for stable] |
| In the Linux kernel, the following vulnerability has been resolved:
unicode: free the map after a grace period
generic_ci_d_hash() and generic_ci_d_compare() read sb->s_encoding and
dereference the unicode map while a pathwalk in rcu mode holds nothing
but rcu_read_lock(). The filesystems that use them, ext4, f2fs and
tmpfs, drop the map with utf8_unload() from ->put_super(), which runs
when the last reference to the mount goes away. A lookup that is still
inside such a filesystem at that point reads a freed map.
With a pathwalk held up in utf8_casefold_hash() while the last reference
to a casefolded tmpfs goes away:
BUG: KASAN: slab-use-after-free in utf8nlookup+0x74c/0x950
Read of size 8 at addr ff110001030fe658 by task walker/98
Call Trace:
<TASK>
utf8nlookup+0x74c/0x950
utf8byte+0x160/0x1560
utf8_casefold_hash+0x167/0x230
generic_ci_d_hash+0xdd/0x1c0
link_path_walk+0x11ad/0x1d30
path_lookupat+0x63/0xb00
filename_lookup+0x1f1/0x5b0
vfs_statx+0xd7/0x3b0
[...]
Allocated by task 94:
__kmalloc_cache_noprof+0x249/0x560
utf8_load+0x4e/0x570
shmem_parse_opt_casefold.isra.0+0x92/0x270
[...]
Freed by task 97:
kfree+0x1db/0x5b0
shmem_put_super+0x72/0x170
generic_shutdown_super+0x14c/0x530
kill_anon_super+0x3a/0x60
deactivate_locked_super+0x9c/0xf0
cleanup_mnt+0x9f/0x130
So far that has been hard to hit. umount(2) waits for a grace period
in namespace_unlock() before it drops the mount, so only a mount whose
last reference goes away elsewhere, like the close of a file or a chdir
out of a lazily unmounted directory, can race a walker. So it is
reachable.
Delay the free until a grace period has passed. The map and the data
table it holds a reference to then outlive any pathwalk that found the
superblock before the mount went away. The reference on the data table
module is dropped from the rcu callback as well. utf8-core is built in
whenever CONFIG_UNICODE is set, so there is no module exit that would
have to wait for the callbacks.
Overlayfs points the s_encoding of an overlay at the map of its first
layer without taking a reference of its own. That stays correct. The
layer is held by the overlay, so its map is dropped only after the
overlay is gone. |
| In the Linux kernel, the following vulnerability has been resolved:
vsock/vmci: validate packet source for connected sockets
vmci_transport_recv_stream_cb() looks up sockets first by the full source
and destination tuple, then by destination only in the bound table. The
fallback can select a non-listening socket without checking whether the
packet came from its stored peer.
This was reproduced with two VMCI contexts. A RST from the context not
stored in a TCP_SYN_SENT socket reset that socket after it was selected by
the destination-only lookup.
VMCI can process notification packets in bottom-half context when the
socket is not owned by user context, or defer packets to a workqueue. Use
vsock_check_source() after taking the socket lock in the bottom-half path,
and recheck after lock_sock() in the workqueue path. Listening sockets
continue to accept packets from any source.
Reply with a RST addressed from the received packet before dropping a
source that fails validation. This preserves the existing reset behavior
for bound non-listening and concurrently closed sockets without directing
the reset to a connected socket's stored peer. |
| In the Linux kernel, the following vulnerability has been resolved:
tracing: Keep the predicate limit separate from program capacity
predicate_parse() adds two to nr_preds to reserve the terminal TRUE
and FALSE entries. It also uses that increased value as the limit for
parsed predicates. If the initial count is smaller than the number
actually parsed, the program can fill the allocation and subsequent
accesses can go past its end.
Keep nr_preds as the predicate limit and use a separate value for the
allocation size. This leaves space for both terminal entries and a
zeroed entry when parsing stops at the limit. |