From: Sasha Levin Date: Thu, 25 Jun 2026 10:41:50 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v6.18.37~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b334803e0c24c41a22a76b68bcc4b015cda1e7d;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/af_unix-reject-siocatmark-on-non-stream-sockets.patch b/queue-5.15/af_unix-reject-siocatmark-on-non-stream-sockets.patch new file mode 100644 index 0000000000..7a5ace5186 --- /dev/null +++ b/queue-5.15/af_unix-reject-siocatmark-on-non-stream-sockets.patch @@ -0,0 +1,54 @@ +From 57b3197298bfd366a7fa63f1e114fa87e97dcb81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:16:48 +0000 +Subject: af_unix: Reject SIOCATMARK on non-stream sockets + +From: Jiexun Wang + +commit d119775f2bad827edc28071c061fdd4a91f889a5 upstream. + +SIOCATMARK reports whether the receive queue is at the urgent mark for +MSG_OOB. + +In AF_UNIX, MSG_OOB is supported only for SOCK_STREAM sockets. +SOCK_DGRAM and SOCK_SEQPACKET reject MSG_OOB in sendmsg() and recvmsg(), +so they should not support SIOCATMARK either. + +Return -EOPNOTSUPP for non-stream sockets before checking the receive +queue. + +Fixes: 314001f0bf92 ("af_unix: Add OOB support") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506140825.2987635-1-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Alexander Martyniuk +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 1676bffe7259dc..8e9a8499db5e66 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3040,6 +3040,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + struct sk_buff *skb; + int answ = 0; + ++ if (sk->sk_type != SOCK_STREAM) ++ return -EOPNOTSUPP; ++ + skb = skb_peek(&sk->sk_receive_queue); + if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) + answ = 1; +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index b9e5efaa74..98b54af439 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -15,3 +15,5 @@ rdma-bnxt_re-zero-shared-page-before-exposing-to-userspace.patch i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch +xhci-fix-memory-leak-regression-when-freeing-xhci-vd.patch +af_unix-reject-siocatmark-on-non-stream-sockets.patch diff --git a/queue-5.15/xhci-fix-memory-leak-regression-when-freeing-xhci-vd.patch b/queue-5.15/xhci-fix-memory-leak-regression-when-freeing-xhci-vd.patch new file mode 100644 index 0000000000..64cad8e244 --- /dev/null +++ b/queue-5.15/xhci-fix-memory-leak-regression-when-freeing-xhci-vd.patch @@ -0,0 +1,54 @@ +From 8974b559fc0e47c9a6413f0cc16c7aaa40d02b6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Jun 2026 20:49:38 -0700 +Subject: xhci: fix memory leak regression when freeing xhci vdev devices depth + first + +From: Mathias Nyman + +commit edcbe06453ddfde21f6aa763f7cab655f26133cc upstream + +Suspend-resume cycle test revealed a memory leak in 6.17-rc3 + +Turns out the slot_id race fix changes accidentally ends up calling +xhci_free_virt_device() with an incorrect vdev parameter. +The vdev variable was reused for temporary purposes right before calling +xhci_free_virt_device(). + +Fix this by passing the correct vdev parameter. + +The slot_id race fix that caused this regression was targeted for stable, +so this needs to be applied there as well. + +Fixes: 2eb03376151b ("usb: xhci: Fix slot_id resource race conflict") +Reported-by: David Wang <00107082@163.com> +Closes: https://lore.kernel.org/linux-usb/20250829181354.4450-1-00107082@163.com +Suggested-by: Michal Pecio +Suggested-by: David Wang <00107082@163.com> +Cc: stable@vger.kernel.org +Tested-by: David Wang <00107082@163.com> +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20250902105306.877476-4-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Justin Chen +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-mem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index fb81e61a599d75..7f75298a09d6fc 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -961,7 +961,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i + out: + /* we are now at a leaf device */ + xhci_debugfs_remove_slot(xhci, slot_id); +- xhci_free_virt_device(xhci, vdev, slot_id); ++ xhci_free_virt_device(xhci, xhci->devs[slot_id], slot_id); + } + + int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, +-- +2.53.0 + diff --git a/queue-6.1/af_unix-reject-siocatmark-on-non-stream-sockets.patch b/queue-6.1/af_unix-reject-siocatmark-on-non-stream-sockets.patch new file mode 100644 index 0000000000..7549f9239a --- /dev/null +++ b/queue-6.1/af_unix-reject-siocatmark-on-non-stream-sockets.patch @@ -0,0 +1,54 @@ +From da7af1d1f5d0dc4bed9d6f3dbabb98ccce99c383 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:16:48 +0000 +Subject: af_unix: Reject SIOCATMARK on non-stream sockets + +From: Jiexun Wang + +commit d119775f2bad827edc28071c061fdd4a91f889a5 upstream. + +SIOCATMARK reports whether the receive queue is at the urgent mark for +MSG_OOB. + +In AF_UNIX, MSG_OOB is supported only for SOCK_STREAM sockets. +SOCK_DGRAM and SOCK_SEQPACKET reject MSG_OOB in sendmsg() and recvmsg(), +so they should not support SIOCATMARK either. + +Return -EOPNOTSUPP for non-stream sockets before checking the receive +queue. + +Fixes: 314001f0bf92 ("af_unix: Add OOB support") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506140825.2987635-1-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Alexander Martyniuk +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index f5b215ca76d249..3e5dc698416f09 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3181,6 +3181,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + struct sk_buff *skb; + int answ = 0; + ++ if (sk->sk_type != SOCK_STREAM) ++ return -EOPNOTSUPP; ++ + skb = skb_peek(&sk->sk_receive_queue); + if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) + answ = 1; +-- +2.53.0 + diff --git a/queue-6.1/ring-buffer-remove-ring_buffer_read_prepare_sync.patch b/queue-6.1/ring-buffer-remove-ring_buffer_read_prepare_sync.patch new file mode 100644 index 0000000000..e014a1c184 --- /dev/null +++ b/queue-6.1/ring-buffer-remove-ring_buffer_read_prepare_sync.patch @@ -0,0 +1,222 @@ +From 3ad37d2d981625e9308858e6198c97fdefb0caf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 12:23:22 +0000 +Subject: ring-buffer: Remove ring_buffer_read_prepare_sync() + +From: Bjoern Doebel + +[ Upstream commit 119a5d573622ae90ba730d18acfae9bb75d77b9a ] + +When the ring buffer was first introduced, reading the non-consuming +"trace" file required disabling the writing of the ring buffer. To make +sure the writing was fully disabled before iterating the buffer with a +non-consuming read, it would set the disable flag of the buffer and then +call an RCU synchronization to make sure all the buffers were +synchronized. + +The function ring_buffer_read_start() originally would initialize the +iterator and call an RCU synchronization, but this was for each individual +per CPU buffer where this would get called many times on a machine with +many CPUs before the trace file could be read. The commit 72c9ddfd4c5bf +("ring-buffer: Make non-consuming read less expensive with lots of cpus.") +separated ring_buffer_read_start into ring_buffer_read_prepare(), +ring_buffer_read_sync() and then ring_buffer_read_start() to allow each of +the per CPU buffers to be prepared, call the read_buffer_read_sync() once, +and then the ring_buffer_read_start() for each of the CPUs which made +things much faster. + +The commit 1039221cc278 ("ring-buffer: Do not disable recording when there +is an iterator") removed the requirement of disabling the recording of the +ring buffer in order to iterate it, but it did not remove the +synchronization that was happening that was required to wait for all the +buffers to have no more writers. It's now OK for the buffers to have +writers and no synchronization is needed. + +Remove the synchronization and put back the interface for the ring buffer +iterator back before commit 72c9ddfd4c5bf was applied. + +Cc: Mathieu Desnoyers +Link: https://lore.kernel.org/20250630180440.3eabb514@batman.local.home +Reported-by: David Howells +Fixes: 1039221cc278 ("ring-buffer: Do not disable recording when there is an iterator") +Tested-by: David Howells +Reviewed-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Assisted-by: Kiro:claude-opus-4.8 +Signed-off-by: Bjoern Doebel +Signed-off-by: Sasha Levin +--- + include/linux/ring_buffer.h | 4 +-- + kernel/trace/ring_buffer.c | 67 ++++++------------------------------- + kernel/trace/trace.c | 14 +++----- + kernel/trace/trace_kdb.c | 8 ++--- + 4 files changed, 18 insertions(+), 75 deletions(-) + +diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h +index 3e7bfc0f65aee2..b53335ed2d0efc 100644 +--- a/include/linux/ring_buffer.h ++++ b/include/linux/ring_buffer.h +@@ -130,9 +130,7 @@ ring_buffer_consume(struct trace_buffer *buffer, int cpu, u64 *ts, + unsigned long *lost_events); + + struct ring_buffer_iter * +-ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags); +-void ring_buffer_read_prepare_sync(void); +-void ring_buffer_read_start(struct ring_buffer_iter *iter); ++ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags); + void ring_buffer_read_finish(struct ring_buffer_iter *iter); + + struct ring_buffer_event * +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index d3a31ba7c71044..5edc4126d0c6ba 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -5082,28 +5082,20 @@ ring_buffer_consume(struct trace_buffer *buffer, int cpu, u64 *ts, + EXPORT_SYMBOL_GPL(ring_buffer_consume); + + /** +- * ring_buffer_read_prepare - Prepare for a non consuming read of the buffer ++ * ring_buffer_read_start - start a non consuming read of the buffer + * @buffer: The ring buffer to read from + * @cpu: The cpu buffer to iterate over + * @flags: gfp flags to use for memory allocation + * +- * This performs the initial preparations necessary to iterate +- * through the buffer. Memory is allocated, buffer recording +- * is disabled, and the iterator pointer is returned to the caller. +- * +- * Disabling buffer recording prevents the reading from being +- * corrupted. This is not a consuming read, so a producer is not +- * expected. +- * +- * After a sequence of ring_buffer_read_prepare calls, the user is +- * expected to make at least one call to ring_buffer_read_prepare_sync. +- * Afterwards, ring_buffer_read_start is invoked to get things going +- * for real. ++ * This creates an iterator to allow non-consuming iteration through ++ * the buffer. If the buffer is disabled for writing, it will produce ++ * the same information each time, but if the buffer is still writing ++ * then the first hit of a write will cause the iteration to stop. + * +- * This overall must be paired with ring_buffer_read_finish. ++ * Must be paired with ring_buffer_read_finish. + */ + struct ring_buffer_iter * +-ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags) ++ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags) + { + struct ring_buffer_per_cpu *cpu_buffer; + struct ring_buffer_iter *iter; +@@ -5128,51 +5120,12 @@ ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags) + + atomic_inc(&cpu_buffer->resize_disabled); + +- return iter; +-} +-EXPORT_SYMBOL_GPL(ring_buffer_read_prepare); +- +-/** +- * ring_buffer_read_prepare_sync - Synchronize a set of prepare calls +- * +- * All previously invoked ring_buffer_read_prepare calls to prepare +- * iterators will be synchronized. Afterwards, read_buffer_read_start +- * calls on those iterators are allowed. +- */ +-void +-ring_buffer_read_prepare_sync(void) +-{ +- synchronize_rcu(); +-} +-EXPORT_SYMBOL_GPL(ring_buffer_read_prepare_sync); +- +-/** +- * ring_buffer_read_start - start a non consuming read of the buffer +- * @iter: The iterator returned by ring_buffer_read_prepare +- * +- * This finalizes the startup of an iteration through the buffer. +- * The iterator comes from a call to ring_buffer_read_prepare and +- * an intervening ring_buffer_read_prepare_sync must have been +- * performed. +- * +- * Must be paired with ring_buffer_read_finish. +- */ +-void +-ring_buffer_read_start(struct ring_buffer_iter *iter) +-{ +- struct ring_buffer_per_cpu *cpu_buffer; +- unsigned long flags; +- +- if (!iter) +- return; +- +- cpu_buffer = iter->cpu_buffer; +- +- raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); ++ guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock); + arch_spin_lock(&cpu_buffer->lock); + rb_iter_reset(iter); + arch_spin_unlock(&cpu_buffer->lock); +- raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); ++ ++ return iter; + } + EXPORT_SYMBOL_GPL(ring_buffer_read_start); + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 25f31d7718c64f..5ef1c79dc5c9e4 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -4819,21 +4819,15 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) + if (iter->cpu_file == RING_BUFFER_ALL_CPUS) { + for_each_tracing_cpu(cpu) { + iter->buffer_iter[cpu] = +- ring_buffer_read_prepare(iter->array_buffer->buffer, +- cpu, GFP_KERNEL); +- } +- ring_buffer_read_prepare_sync(); +- for_each_tracing_cpu(cpu) { +- ring_buffer_read_start(iter->buffer_iter[cpu]); ++ ring_buffer_read_start(iter->array_buffer->buffer, ++ cpu, GFP_KERNEL); + tracing_iter_reset(iter, cpu); + } + } else { + cpu = iter->cpu_file; + iter->buffer_iter[cpu] = +- ring_buffer_read_prepare(iter->array_buffer->buffer, +- cpu, GFP_KERNEL); +- ring_buffer_read_prepare_sync(); +- ring_buffer_read_start(iter->buffer_iter[cpu]); ++ ring_buffer_read_start(iter->array_buffer->buffer, ++ cpu, GFP_KERNEL); + tracing_iter_reset(iter, cpu); + } + +diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c +index 59857a1ee44cdf..628c25693cef2f 100644 +--- a/kernel/trace/trace_kdb.c ++++ b/kernel/trace/trace_kdb.c +@@ -43,17 +43,15 @@ static void ftrace_dump_buf(int skip_entries, long cpu_file) + if (cpu_file == RING_BUFFER_ALL_CPUS) { + for_each_tracing_cpu(cpu) { + iter.buffer_iter[cpu] = +- ring_buffer_read_prepare(iter.array_buffer->buffer, +- cpu, GFP_ATOMIC); +- ring_buffer_read_start(iter.buffer_iter[cpu]); ++ ring_buffer_read_start(iter.array_buffer->buffer, ++ cpu, GFP_ATOMIC); + tracing_iter_reset(&iter, cpu); + } + } else { + iter.cpu_file = cpu_file; + iter.buffer_iter[cpu_file] = +- ring_buffer_read_prepare(iter.array_buffer->buffer, ++ ring_buffer_read_start(iter.array_buffer->buffer, + cpu_file, GFP_ATOMIC); +- ring_buffer_read_start(iter.buffer_iter[cpu_file]); + tracing_iter_reset(&iter, cpu_file); + } + +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index fb9a137f05..7df17a4682 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -32,3 +32,5 @@ rdma-bnxt_re-zero-shared-page-before-exposing-to-userspace.patch i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch +af_unix-reject-siocatmark-on-non-stream-sockets.patch +ring-buffer-remove-ring_buffer_read_prepare_sync.patch diff --git a/queue-6.12/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch b/queue-6.12/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch new file mode 100644 index 0000000000..036d13c66f --- /dev/null +++ b/queue-6.12/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch @@ -0,0 +1,140 @@ +From 046411954db8bf65c5ede50306036047ca784ea6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 14:38:16 +0800 +Subject: ACPI: scan: Use async schedule function in acpi_scan_clear_dep_fn() + +From: Yicong Yang + +[ Upstream commit 7cf28b3797a81b616bb7eb3e90cf131afc452919 ] + +The device object rescan in acpi_scan_clear_dep_fn() is scheduled on a +system workqueue which is not guaranteed to be finished before entering +userspace. This may cause some key devices to be missing when userspace +init task tries to find them. Two issues observed on RISCV platforms: + + - Kernel panic due to userspace init cannot have an opened + console. + + The console device scanning is queued by acpi_scan_clear_dep_queue() + and not finished by the time userspace init process running, thus by + the time userspace init runs, no console is present. + + - Entering rescue shell due to the lack of root devices (PCIe nvme in + our case). + + Same reason as above, the PCIe host bridge scanning is queued on + a system workqueue and finished after init process runs. + +The reason is because both devices (console, PCIe host bridge) depend on +riscv-aplic irqchip to serve their interrupts (console's wired interrupt +and PCI's INTx interrupts). In order to keep the dependency, these +devices are scanned and created after initializing riscv-aplic. The +riscv-aplic is initialized in device_initcall() and a device scan work +is queued via acpi_scan_clear_dep_queue(), which is close to the time +userspace init process is run. Since system_dfl_wq is used in +acpi_scan_clear_dep_queue() with no synchronization, the issues will +happen if userspace init runs before these devices are ready. + +The solution is to wait for the queued work to complete before entering +userspace init. One possible way would be to use a dedicated workqueue +instead of system_dfl_wq, and explicitly flush it somewhere in the +initcall stage before entering userspace. Another way is to use +async_schedule_dev_nocall() for scanning these devices. It's designed +for asynchronous initialization and will work in the same way as before +because it's using a dedicated unbound workqueue as well, but the kernel +init code calls async_synchronize_full() right before entering userspace +init which will wait for the work to complete. + +Compared to a dedicated workqueue, the second approach is simpler +because the async schedule framework takes care of all of the details. +The ACPI code only needs to focus on its job. A dedicated workqueue for +this could also be redundant because some platforms don't need +acpi_scan_clear_dep_queue() for their device scanning. + +Signed-off-by: Yicong Yang +[ rjw: Subject adjustment, changelog edits ] +Link: https://patch.msgid.link/20260128132848.93638-1-yang.yicong@picoheart.com +Signed-off-by: Rafael J. Wysocki +[ Vivian: Adjust system_dfl_wq -> system_unbound_wq in removed lines ] +Signed-off-by: Vivian Wang +Signed-off-by: Sasha Levin +--- + drivers/acpi/scan.c | 41 +++++++++++++++-------------------------- + 1 file changed, 15 insertions(+), 26 deletions(-) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 0774cc6921100b..4b9c81fbdc3bb2 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -5,6 +5,7 @@ + + #define pr_fmt(fmt) "ACPI: " fmt + ++#include + #include + #include + #include +@@ -2364,46 +2365,34 @@ static int acpi_dev_get_next_consumer_dev_cb(struct acpi_dep_data *dep, void *da + return 0; + } + +-struct acpi_scan_clear_dep_work { +- struct work_struct work; +- struct acpi_device *adev; +-}; +- +-static void acpi_scan_clear_dep_fn(struct work_struct *work) ++static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie) + { +- struct acpi_scan_clear_dep_work *cdw; +- +- cdw = container_of(work, struct acpi_scan_clear_dep_work, work); ++ struct acpi_device *adev = to_acpi_device(dev); + + acpi_scan_lock_acquire(); +- acpi_bus_attach(cdw->adev, (void *)true); ++ acpi_bus_attach(adev, (void *)true); + acpi_scan_lock_release(); + +- acpi_dev_put(cdw->adev); +- kfree(cdw); ++ acpi_dev_put(adev); + } + + static bool acpi_scan_clear_dep_queue(struct acpi_device *adev) + { +- struct acpi_scan_clear_dep_work *cdw; +- + if (adev->dep_unmet) + return false; + +- cdw = kmalloc(sizeof(*cdw), GFP_KERNEL); +- if (!cdw) +- return false; +- +- cdw->adev = adev; +- INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn); + /* +- * Since the work function may block on the lock until the entire +- * initial enumeration of devices is complete, put it into the unbound +- * workqueue. ++ * Async schedule the deferred acpi_scan_clear_dep_fn() since: ++ * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot ++ * be acquired under acpi_dep_list_lock (held here) ++ * - the deferred work at boot stage is ensured to be finished ++ * before userspace init task by the async_synchronize_full() ++ * barrier ++ * ++ * Use _nocall variant since it'll return on failure instead of ++ * run the function synchronously. + */ +- queue_work(system_unbound_wq, &cdw->work); +- +- return true; ++ return async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev); + } + + static void acpi_scan_delete_dep_data(struct acpi_dep_data *dep) +-- +2.53.0 + diff --git a/queue-6.12/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch b/queue-6.12/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch new file mode 100644 index 0000000000..cf9a7fdf82 --- /dev/null +++ b/queue-6.12/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch @@ -0,0 +1,56 @@ +From 17d137d92bfbb072e6d40ebf18cd706fa389d55e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 14:22:31 +0800 +Subject: bpf: Reject sleepable kprobe_multi programs at attach time + +From: Varun R Mallya + +commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 upstream. + +kprobe.multi programs run in atomic/RCU context and cannot sleep. +However, bpf_kprobe_multi_link_attach() did not validate whether the +program being attached had the sleepable flag set, allowing sleepable +helpers such as bpf_copy_from_user() to be invoked from a non-sleepable +context. + +This causes a "sleeping function called from invalid context" splat: + + BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169 + in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo + preempt_count: 1, expected: 0 + RCU nest depth: 2, expected: 0 + +Fix this by rejecting sleepable programs early in +bpf_kprobe_multi_link_attach(), before any further processing. + +Fixes: 0dcac2725406 ("bpf: Add multi kprobe link") +Signed-off-by: Varun R Mallya +Acked-by: Kumar Kartikeya Dwivedi +Acked-by: Leon Hwang +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + kernel/trace/bpf_trace.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 4a44451efbcc67..41c874fbd6fa79 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2943,6 +2943,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr + if (!is_kprobe_multi(prog)) + return -EINVAL; + ++ /* kprobe_multi is not allowed to be sleepable. */ ++ if (prog->sleepable) ++ return -EINVAL; ++ + flags = attr->link_create.kprobe_multi.flags; + if (flags & ~BPF_F_KPROBE_MULTI_RETURN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch b/queue-6.12/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch new file mode 100644 index 0000000000..cca22ffb82 --- /dev/null +++ b/queue-6.12/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch @@ -0,0 +1,130 @@ +From 762331b2fb6b319a348e7121346a396339b1df07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 14:22:32 +0800 +Subject: selftests/bpf: Add test to ensure kprobe_multi is not sleepable + +From: Varun R Mallya + +commit c7cab53f9d5273f0cf2a26bdf178c4e074bdfb50 upstream. + +Add a selftest to ensure that kprobe_multi programs cannot be attached +using the BPF_F_SLEEPABLE flag. This test succeeds when the kernel +rejects attachment of kprobe_multi when the BPF_F_SLEEPABLE flag is set. + +Suggested-by: Leon Hwang +Signed-off-by: Varun R Mallya +Link: https://lore.kernel.org/r/20260408190137.101418-3-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../bpf/prog_tests/kprobe_multi_test.c | 35 ++++++++++++++++++- + .../bpf/progs/kprobe_multi_sleepable.c | 25 +++++++++++++ + 2 files changed, 59 insertions(+), 1 deletion(-) + create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c + +diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +index 960c9323d1e0f5..4183c2c057a304 100644 +--- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c ++++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +@@ -6,6 +6,7 @@ + #include "kprobe_multi_override.skel.h" + #include "kprobe_multi_session.skel.h" + #include "kprobe_multi_session_cookie.skel.h" ++#include "kprobe_multi_sleepable.skel.h" + #include "bpf/libbpf_internal.h" + #include "bpf/hashmap.h" + +@@ -216,7 +217,9 @@ static void test_attach_api_syms(void) + static void test_attach_api_fails(void) + { + LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); ++ LIBBPF_OPTS(bpf_test_run_opts, topts); + struct kprobe_multi *skel = NULL; ++ struct kprobe_multi_sleepable *sl_skel = NULL; + struct bpf_link *link = NULL; + unsigned long long addrs[2]; + const char *syms[2] = { +@@ -224,7 +227,7 @@ static void test_attach_api_fails(void) + "bpf_fentry_test2", + }; + __u64 cookies[2]; +- int saved_error; ++ int saved_error, err; + + addrs[0] = ksym_get_addr("bpf_fentry_test1"); + addrs[1] = ksym_get_addr("bpf_fentry_test2"); +@@ -323,9 +326,39 @@ static void test_attach_api_fails(void) + if (!ASSERT_EQ(saved_error, -E2BIG, "fail_6_error")) + goto cleanup; + ++ /* fail_9 - sleepable kprobe multi should not attach */ ++ sl_skel = kprobe_multi_sleepable__open(); ++ if (!ASSERT_OK_PTR(sl_skel, "sleep_skel_open")) ++ goto cleanup; ++ ++ sl_skel->bss->user_ptr = sl_skel; ++ ++ err = bpf_program__set_flags(sl_skel->progs.handle_kprobe_multi_sleepable, ++ BPF_F_SLEEPABLE); ++ if (!ASSERT_OK(err, "sleep_skel_set_flags")) ++ goto cleanup; ++ ++ err = kprobe_multi_sleepable__load(sl_skel); ++ if (!ASSERT_OK(err, "sleep_skel_load")) ++ goto cleanup; ++ ++ link = bpf_program__attach_kprobe_multi_opts(sl_skel->progs.handle_kprobe_multi_sleepable, ++ "bpf_fentry_test1", NULL); ++ saved_error = -errno; ++ ++ if (!ASSERT_ERR_PTR(link, "fail_9")) ++ goto cleanup; ++ ++ if (!ASSERT_EQ(saved_error, -EINVAL, "fail_9_error")) ++ goto cleanup; ++ ++ err = bpf_prog_test_run_opts(bpf_program__fd(sl_skel->progs.fentry), &topts); ++ ASSERT_OK(err, "bpf_prog_test_run_opts"); ++ + cleanup: + bpf_link__destroy(link); + kprobe_multi__destroy(skel); ++ kprobe_multi_sleepable__destroy(sl_skel); + } + + static void test_session_skel_api(void) +diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c b/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c +new file mode 100644 +index 00000000000000..932e1d9c72e2d0 +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "vmlinux.h" ++#include ++#include ++ ++void *user_ptr = 0; ++ ++SEC("kprobe.multi") ++int handle_kprobe_multi_sleepable(struct pt_regs *ctx) ++{ ++ int a, err; ++ ++ err = bpf_copy_from_user(&a, sizeof(a), user_ptr); ++ barrier_var(a); ++ return err; ++} ++ ++SEC("fentry/bpf_fentry_test1") ++int BPF_PROG(fentry) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index a214c36f55..6a5480527a 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -28,3 +28,6 @@ rdma-bnxt_re-zero-shared-page-before-exposing-to-userspace.patch i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch +bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch +selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch +acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch diff --git a/queue-6.18/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch b/queue-6.18/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch new file mode 100644 index 0000000000..c5fa8f5276 --- /dev/null +++ b/queue-6.18/acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch @@ -0,0 +1,140 @@ +From d5d924be016df0e9f700868cb35231dbb02ae5a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 14:38:16 +0800 +Subject: ACPI: scan: Use async schedule function in acpi_scan_clear_dep_fn() + +From: Yicong Yang + +[ Upstream commit 7cf28b3797a81b616bb7eb3e90cf131afc452919 ] + +The device object rescan in acpi_scan_clear_dep_fn() is scheduled on a +system workqueue which is not guaranteed to be finished before entering +userspace. This may cause some key devices to be missing when userspace +init task tries to find them. Two issues observed on RISCV platforms: + + - Kernel panic due to userspace init cannot have an opened + console. + + The console device scanning is queued by acpi_scan_clear_dep_queue() + and not finished by the time userspace init process running, thus by + the time userspace init runs, no console is present. + + - Entering rescue shell due to the lack of root devices (PCIe nvme in + our case). + + Same reason as above, the PCIe host bridge scanning is queued on + a system workqueue and finished after init process runs. + +The reason is because both devices (console, PCIe host bridge) depend on +riscv-aplic irqchip to serve their interrupts (console's wired interrupt +and PCI's INTx interrupts). In order to keep the dependency, these +devices are scanned and created after initializing riscv-aplic. The +riscv-aplic is initialized in device_initcall() and a device scan work +is queued via acpi_scan_clear_dep_queue(), which is close to the time +userspace init process is run. Since system_dfl_wq is used in +acpi_scan_clear_dep_queue() with no synchronization, the issues will +happen if userspace init runs before these devices are ready. + +The solution is to wait for the queued work to complete before entering +userspace init. One possible way would be to use a dedicated workqueue +instead of system_dfl_wq, and explicitly flush it somewhere in the +initcall stage before entering userspace. Another way is to use +async_schedule_dev_nocall() for scanning these devices. It's designed +for asynchronous initialization and will work in the same way as before +because it's using a dedicated unbound workqueue as well, but the kernel +init code calls async_synchronize_full() right before entering userspace +init which will wait for the work to complete. + +Compared to a dedicated workqueue, the second approach is simpler +because the async schedule framework takes care of all of the details. +The ACPI code only needs to focus on its job. A dedicated workqueue for +this could also be redundant because some platforms don't need +acpi_scan_clear_dep_queue() for their device scanning. + +Signed-off-by: Yicong Yang +[ rjw: Subject adjustment, changelog edits ] +Link: https://patch.msgid.link/20260128132848.93638-1-yang.yicong@picoheart.com +Signed-off-by: Rafael J. Wysocki +[ Vivian: Adjust system_dfl_wq -> system_unbound_wq in removed lines ] +Signed-off-by: Vivian Wang +Signed-off-by: Sasha Levin +--- + drivers/acpi/scan.c | 41 +++++++++++++++-------------------------- + 1 file changed, 15 insertions(+), 26 deletions(-) + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 50f60da6cf27fc..16704c2a730c04 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -5,6 +5,7 @@ + + #define pr_fmt(fmt) "ACPI: " fmt + ++#include + #include + #include + #include +@@ -2360,46 +2361,34 @@ static int acpi_dev_get_next_consumer_dev_cb(struct acpi_dep_data *dep, void *da + return 0; + } + +-struct acpi_scan_clear_dep_work { +- struct work_struct work; +- struct acpi_device *adev; +-}; +- +-static void acpi_scan_clear_dep_fn(struct work_struct *work) ++static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie) + { +- struct acpi_scan_clear_dep_work *cdw; +- +- cdw = container_of(work, struct acpi_scan_clear_dep_work, work); ++ struct acpi_device *adev = to_acpi_device(dev); + + acpi_scan_lock_acquire(); +- acpi_bus_attach(cdw->adev, (void *)true); ++ acpi_bus_attach(adev, (void *)true); + acpi_scan_lock_release(); + +- acpi_dev_put(cdw->adev); +- kfree(cdw); ++ acpi_dev_put(adev); + } + + static bool acpi_scan_clear_dep_queue(struct acpi_device *adev) + { +- struct acpi_scan_clear_dep_work *cdw; +- + if (adev->dep_unmet) + return false; + +- cdw = kmalloc(sizeof(*cdw), GFP_KERNEL); +- if (!cdw) +- return false; +- +- cdw->adev = adev; +- INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn); + /* +- * Since the work function may block on the lock until the entire +- * initial enumeration of devices is complete, put it into the unbound +- * workqueue. ++ * Async schedule the deferred acpi_scan_clear_dep_fn() since: ++ * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot ++ * be acquired under acpi_dep_list_lock (held here) ++ * - the deferred work at boot stage is ensured to be finished ++ * before userspace init task by the async_synchronize_full() ++ * barrier ++ * ++ * Use _nocall variant since it'll return on failure instead of ++ * run the function synchronously. + */ +- queue_work(system_unbound_wq, &cdw->work); +- +- return true; ++ return async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev); + } + + static void acpi_scan_delete_dep_data(struct acpi_dep_data *dep) +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index ab40c6c336..f123481cea 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -10,3 +10,4 @@ rdma-bnxt_re-zero-shared-page-before-exposing-to-userspace.patch i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch +acpi-scan-use-async-schedule-function-in-acpi_scan_c.patch diff --git a/queue-6.6/af_unix-reject-siocatmark-on-non-stream-sockets.patch b/queue-6.6/af_unix-reject-siocatmark-on-non-stream-sockets.patch new file mode 100644 index 0000000000..ad2c841b84 --- /dev/null +++ b/queue-6.6/af_unix-reject-siocatmark-on-non-stream-sockets.patch @@ -0,0 +1,54 @@ +From 72223310fb78cc5edc8022d598ad1a83f05c2ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:16:48 +0000 +Subject: af_unix: Reject SIOCATMARK on non-stream sockets + +From: Jiexun Wang + +commit d119775f2bad827edc28071c061fdd4a91f889a5 upstream. + +SIOCATMARK reports whether the receive queue is at the urgent mark for +MSG_OOB. + +In AF_UNIX, MSG_OOB is supported only for SOCK_STREAM sockets. +SOCK_DGRAM and SOCK_SEQPACKET reject MSG_OOB in sendmsg() and recvmsg(), +so they should not support SIOCATMARK either. + +Return -EOPNOTSUPP for non-stream sockets before checking the receive +queue. + +Fixes: 314001f0bf92 ("af_unix: Add OOB support") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260506140825.2987635-1-n05ec@lzu.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Alexander Martyniuk +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 32892a40d139c2..8bd78cad69e7c5 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3139,6 +3139,9 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + struct sk_buff *skb; + int answ = 0; + ++ if (sk->sk_type != SOCK_STREAM) ++ return -EOPNOTSUPP; ++ + skb = skb_peek(&sk->sk_receive_queue); + if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) + answ = 1; +-- +2.53.0 + diff --git a/queue-6.6/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch b/queue-6.6/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch new file mode 100644 index 0000000000..56254a8ba2 --- /dev/null +++ b/queue-6.6/bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch @@ -0,0 +1,58 @@ +From 41d26894e1ec21c2773302e49caa5825d2d7caa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:28:59 +0800 +Subject: bpf: Reject sleepable kprobe_multi programs at attach time + +From: Varun R Mallya + +commit eb7024bfcc5f68ed11ed9dd4891a3073c15f04a8 upstream. + +kprobe.multi programs run in atomic/RCU context and cannot sleep. +However, bpf_kprobe_multi_link_attach() did not validate whether the +program being attached had the sleepable flag set, allowing sleepable +helpers such as bpf_copy_from_user() to be invoked from a non-sleepable +context. + +This causes a "sleeping function called from invalid context" splat: + + BUG: sleeping function called from invalid context at ./include/linux/uaccess.h:169 + in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1787, name: sudo + preempt_count: 1, expected: 0 + RCU nest depth: 2, expected: 0 + +Fix this by rejecting sleepable programs early in +bpf_kprobe_multi_link_attach(), before any further processing. + +Fixes: 0dcac2725406 ("bpf: Add multi kprobe link") +Signed-off-by: Varun R Mallya +Acked-by: Kumar Kartikeya Dwivedi +Acked-by: Leon Hwang +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260401191126.440683-1-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +[shung-hsi.yu: sleepable flag was in 'struct bpf_prog_aux' before commit +66c8473135c6 "bpf: move sleepable flag from bpf_prog_aux to bpf_prog"] +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + kernel/trace/bpf_trace.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index a896b80252ae11..87e7cc2dc5ccd8 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -2905,6 +2905,10 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr + if (prog->expected_attach_type != BPF_TRACE_KPROBE_MULTI) + return -EINVAL; + ++ /* kprobe_multi is not allowed to be sleepable. */ ++ if (prog->aux->sleepable) ++ return -EINVAL; ++ + flags = attr->link_create.kprobe_multi.flags; + if (flags & ~BPF_F_KPROBE_MULTI_RETURN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.6/bpf-remove-mark_precise_scalar_ids.patch b/queue-6.6/bpf-remove-mark_precise_scalar_ids.patch new file mode 100644 index 0000000000..c8bb6d8ad8 --- /dev/null +++ b/queue-6.6/bpf-remove-mark_precise_scalar_ids.patch @@ -0,0 +1,473 @@ +From fa38cff5bc2097256305c81974bcc34c278aebe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Jun 2026 01:27:33 +0800 +Subject: bpf: Remove mark_precise_scalar_ids() + +From: Eduard Zingerman + +[ Upstream commit 842edb5507a1038e009d27e69d13b94b6f085763 ] + +Function mark_precise_scalar_ids() is superseded by +bt_sync_linked_regs() and equal scalars tracking in jump history. +mark_precise_scalar_ids() propagates precision over registers sharing +same ID on parent/child state boundaries, while jump history records +allow bt_sync_linked_regs() to propagate same information with +instruction level granularity, which is strictly more precise. + +This commit removes mark_precise_scalar_ids() and updates test cases +in progs/verifier_scalar_ids to reflect new verifier behavior. + +The tests are updated in the following manner: +- mark_precise_scalar_ids() propagated precision regardless of + presence of conditional jumps, while new jump history based logic + only kicks in when conditional jumps are present. + Hence test cases are augmented with conditional jumps to still + trigger precision propagation. +- As equal scalars tracking no longer relies on parent/child state + boundaries some test cases are no longer interesting, + such test cases are removed, namely: + - precision_same_state and precision_cross_state are superseded by + linked_regs_bpf_k; + - precision_same_state_broken_link and equal_scalars_broken_link + are superseded by linked_regs_broken_link. + +Signed-off-by: Eduard Zingerman +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20240718202357.1746514-3-eddyz87@gmail.com +[ zhenzhong: backport to 6.6.y after adapting the first linked-regs + history commit to the older scalar-id verifier layout. ] +Signed-off-by: Zhenzhong Wu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 115 ------------ + .../selftests/bpf/progs/verifier_scalar_ids.c | 171 ++++++------------ + .../testing/selftests/bpf/verifier/precise.c | 2 +- + 3 files changed, 56 insertions(+), 232 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 2268f095203e21..f638b2d3a42fbc 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -4265,96 +4265,6 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ + } + } + +-static bool idset_contains(struct bpf_idset *s, u32 id) +-{ +- u32 i; +- +- for (i = 0; i < s->count; ++i) +- if (s->ids[i] == id) +- return true; +- +- return false; +-} +- +-static int idset_push(struct bpf_idset *s, u32 id) +-{ +- if (WARN_ON_ONCE(s->count >= ARRAY_SIZE(s->ids))) +- return -EFAULT; +- s->ids[s->count++] = id; +- return 0; +-} +- +-static void idset_reset(struct bpf_idset *s) +-{ +- s->count = 0; +-} +- +-/* Collect a set of IDs for all registers currently marked as precise in env->bt. +- * Mark all registers with these IDs as precise. +- */ +-static int mark_precise_scalar_ids(struct bpf_verifier_env *env, struct bpf_verifier_state *st) +-{ +- struct bpf_idset *precise_ids = &env->idset_scratch; +- struct backtrack_state *bt = &env->bt; +- struct bpf_func_state *func; +- struct bpf_reg_state *reg; +- DECLARE_BITMAP(mask, 64); +- int i, fr; +- +- idset_reset(precise_ids); +- +- for (fr = bt->frame; fr >= 0; fr--) { +- func = st->frame[fr]; +- +- bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr)); +- for_each_set_bit(i, mask, 32) { +- reg = &func->regs[i]; +- if (!reg->id || reg->type != SCALAR_VALUE) +- continue; +- if (idset_push(precise_ids, reg->id)) +- return -EFAULT; +- } +- +- bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); +- for_each_set_bit(i, mask, 64) { +- if (i >= func->allocated_stack / BPF_REG_SIZE) +- break; +- if (!is_spilled_scalar_reg(&func->stack[i])) +- continue; +- reg = &func->stack[i].spilled_ptr; +- if (!reg->id) +- continue; +- if (idset_push(precise_ids, reg->id)) +- return -EFAULT; +- } +- } +- +- for (fr = 0; fr <= st->curframe; ++fr) { +- func = st->frame[fr]; +- +- for (i = BPF_REG_0; i < BPF_REG_10; ++i) { +- reg = &func->regs[i]; +- if (!reg->id) +- continue; +- if (!idset_contains(precise_ids, reg->id)) +- continue; +- bt_set_frame_reg(bt, fr, i); +- } +- for (i = 0; i < func->allocated_stack / BPF_REG_SIZE; ++i) { +- if (!is_spilled_scalar_reg(&func->stack[i])) +- continue; +- reg = &func->stack[i].spilled_ptr; +- if (!reg->id) +- continue; +- if (!idset_contains(precise_ids, reg->id)) +- continue; +- bt_set_frame_slot(bt, fr, i); +- } +- } +- +- return 0; +-} +- + /* + * __mark_chain_precision() backtracks BPF program instruction sequence and + * chain of verifier states making sure that register *regno* (if regno >= 0) +@@ -4487,31 +4397,6 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) + bt->frame, last_idx, first_idx, subseq_idx); + } + +- /* If some register with scalar ID is marked as precise, +- * make sure that all registers sharing this ID are also precise. +- * This is needed to estimate effect of sync_linked_regs(). +- * Do this at the last instruction of each state, +- * bpf_reg_state::id fields are valid for these instructions. +- * +- * Allows to track precision in situation like below: +- * +- * r2 = unknown value +- * ... +- * --- state #0 --- +- * ... +- * r1 = r2 // r1 and r2 now share the same ID +- * ... +- * --- state #1 {r1.id = A, r2.id = A} --- +- * ... +- * if (r2 > 10) goto exit; // sync_linked_regs() assigns range to r1 +- * ... +- * --- state #2 {r1.id = A, r2.id = A} --- +- * r3 = r10 +- * r3 += r1 // need to mark both r1 and r2 +- */ +- if (mark_precise_scalar_ids(env, st)) +- return -EFAULT; +- + if (last_idx < 0) { + /* we are at the entry into subprog, which + * is expected for global funcs, but only if +diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +index 22a6cf6e8255df..f70392bf696c62 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c ++++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +@@ -5,54 +5,27 @@ + #include "bpf_misc.h" + + /* Check that precision marks propagate through scalar IDs. +- * Registers r{0,1,2} have the same scalar ID at the moment when r0 is +- * marked to be precise, this mark is immediately propagated to r{1,2}. ++ * Registers r{0,1,2} have the same scalar ID. ++ * Range information is propagated for scalars sharing same ID. ++ * Check that precision mark for r0 causes precision marks for r{1,2} ++ * when range information is propagated for 'if ' insn. + */ + SEC("socket") + __success __log_level(2) +-__msg("frame0: regs=r0,r1,r2 stack= before 4: (bf) r3 = r10") +-__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +-__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +-__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +-__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +-__flag(BPF_F_TEST_STATE_FREQ) +-__naked void precision_same_state(void) +-{ +- asm volatile ( +- /* r0 = random number up to 0xff */ +- "call %[bpf_ktime_get_ns];" +- "r0 &= 0xff;" +- /* tie r0.id == r1.id == r2.id */ +- "r1 = r0;" +- "r2 = r0;" +- /* force r0 to be precise, this immediately marks r1 and r2 as +- * precise as well because of shared IDs +- */ +- "r3 = r10;" +- "r3 += r0;" +- "r0 = 0;" +- "exit;" +- : +- : __imm(bpf_ktime_get_ns) +- : __clobber_all); +-} +- +-/* Same as precision_same_state, but mark propagates through state / +- * parent state boundary. +- */ +-SEC("socket") +-__success __log_level(2) +-__msg("frame0: last_idx 6 first_idx 5 subseq_idx -1") +-__msg("frame0: regs=r0,r1,r2 stack= before 5: (bf) r3 = r10") ++/* first 'if' branch */ ++__msg("6: (0f) r3 += r0") ++__msg("frame0: regs=r0 stack= before 4: (25) if r1 > 0x7 goto pc+0") + __msg("frame0: parent state regs=r0,r1,r2 stack=:") +-__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") + __msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +-__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +-__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +-__msg("frame0: parent state regs=r0 stack=:") +-__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") ++/* second 'if' branch */ ++__msg("from 4 to 5: ") ++__msg("6: (0f) r3 += r0") ++__msg("frame0: regs=r0 stack= before 5: (bf) r3 = r10") ++__msg("frame0: regs=r0 stack= before 4: (25) if r1 > 0x7 goto pc+0") ++/* parent state already has r{0,1,2} as precise */ ++__msg("frame0: parent state regs= stack=:") + __flag(BPF_F_TEST_STATE_FREQ) +-__naked void precision_cross_state(void) ++__naked void linked_regs_bpf_k(void) + { + asm volatile ( + /* r0 = random number up to 0xff */ +@@ -61,9 +34,8 @@ __naked void precision_cross_state(void) + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" +- /* force checkpoint */ +- "goto +0;" +- /* force r0 to be precise, this immediately marks r1 and r2 as ++ "if r1 > 7 goto +0;" ++ /* force r0 to be precise, this eventually marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" +@@ -75,59 +47,18 @@ __naked void precision_cross_state(void) + : __clobber_all); + } + +-/* Same as precision_same_state, but break one of the ++/* Same as linked_regs_bpf_k, but break one of the + * links, note that r1 is absent from regs=... in __msg below. + */ + SEC("socket") + __success __log_level(2) +-__msg("frame0: regs=r0,r2 stack= before 5: (bf) r3 = r10") +-__msg("frame0: regs=r0,r2 stack= before 4: (b7) r1 = 0") +-__msg("frame0: regs=r0,r2 stack= before 3: (bf) r2 = r0") +-__msg("frame0: regs=r0 stack= before 2: (bf) r1 = r0") +-__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +-__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +-__flag(BPF_F_TEST_STATE_FREQ) +-__naked void precision_same_state_broken_link(void) +-{ +- asm volatile ( +- /* r0 = random number up to 0xff */ +- "call %[bpf_ktime_get_ns];" +- "r0 &= 0xff;" +- /* tie r0.id == r1.id == r2.id */ +- "r1 = r0;" +- "r2 = r0;" +- /* break link for r1, this is the only line that differs +- * compared to the previous test +- */ +- "r1 = 0;" +- /* force r0 to be precise, this immediately marks r1 and r2 as +- * precise as well because of shared IDs +- */ +- "r3 = r10;" +- "r3 += r0;" +- "r0 = 0;" +- "exit;" +- : +- : __imm(bpf_ktime_get_ns) +- : __clobber_all); +-} +- +-/* Same as precision_same_state_broken_link, but with state / +- * parent state boundary. +- */ +-SEC("socket") +-__success __log_level(2) +-__msg("frame0: regs=r0,r2 stack= before 6: (bf) r3 = r10") +-__msg("frame0: regs=r0,r2 stack= before 5: (b7) r1 = 0") +-__msg("frame0: parent state regs=r0,r2 stack=:") +-__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") +-__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +-__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +-__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") ++__msg("7: (0f) r3 += r0") ++__msg("frame0: regs=r0 stack= before 6: (bf) r3 = r10") + __msg("frame0: parent state regs=r0 stack=:") +-__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") ++__msg("frame0: regs=r0 stack= before 5: (25) if r0 > 0x7 goto pc+0") ++__msg("frame0: parent state regs=r0,r2 stack=:") + __flag(BPF_F_TEST_STATE_FREQ) +-__naked void precision_cross_state_broken_link(void) ++__naked void linked_regs_broken_link(void) + { + asm volatile ( + /* r0 = random number up to 0xff */ +@@ -136,18 +67,13 @@ __naked void precision_cross_state_broken_link(void) + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" +- /* force checkpoint, although link between r1 and r{0,2} is +- * broken by the next statement current precision tracking +- * algorithm can't react to it and propagates mark for r1 to +- * the parent state. +- */ +- "goto +0;" + /* break link for r1, this is the only line that differs +- * compared to precision_cross_state() ++ * compared to the previous test + */ + "r1 = 0;" +- /* force r0 to be precise, this immediately marks r1 and r2 as +- * precise as well because of shared IDs ++ "if r0 > 7 goto +0;" ++ /* force r0 to be precise, ++ * this eventually marks r2 as precise because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" +@@ -164,10 +90,16 @@ __naked void precision_cross_state_broken_link(void) + */ + SEC("socket") + __success __log_level(2) +-__msg("11: (0f) r2 += r1") ++__msg("12: (0f) r2 += r1") + /* Current state */ +-__msg("frame2: last_idx 11 first_idx 10 subseq_idx -1") +-__msg("frame2: regs=r1 stack= before 10: (bf) r2 = r10") ++__msg("frame2: last_idx 12 first_idx 11 subseq_idx -1 ") ++__msg("frame2: regs=r1 stack= before 11: (bf) r2 = r10") ++__msg("frame2: parent state regs=r1 stack=") ++__msg("frame1: parent state regs= stack=") ++__msg("frame0: parent state regs= stack=") ++/* Parent state */ ++__msg("frame2: last_idx 10 first_idx 10 subseq_idx 11 ") ++__msg("frame2: regs=r1 stack= before 10: (25) if r1 > 0x7 goto pc+0") + __msg("frame2: parent state regs=r1 stack=") + /* frame1.r{6,7} are marked because mark_precise_scalar_ids() + * looks for all registers with frame2.r1.id in the current state +@@ -192,7 +124,7 @@ __msg("frame1: regs=r1 stack= before 4: (85) call pc+1") + __msg("frame0: parent state regs=r1,r6 stack=") + /* Parent state */ + __msg("frame0: last_idx 3 first_idx 1 subseq_idx 4") +-__msg("frame0: regs=r0,r1,r6 stack= before 3: (bf) r6 = r0") ++__msg("frame0: regs=r1,r6 stack= before 3: (bf) r6 = r0") + __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") + __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") + __flag(BPF_F_TEST_STATE_FREQ) +@@ -230,7 +162,8 @@ static __naked __noinline __used + void precision_many_frames__bar(void) + { + asm volatile ( +- /* force r1 to be precise, this immediately marks: ++ "if r1 > 7 goto +0;" ++ /* force r1 to be precise, this eventually marks: + * - bar frame r1 + * - foo frame r{1,6,7} + * - main frame r{1,6} +@@ -247,14 +180,16 @@ void precision_many_frames__bar(void) + */ + SEC("socket") + __success __log_level(2) ++__msg("11: (0f) r2 += r1") + /* foo frame */ +-__msg("frame1: regs=r1 stack=-8,-16 before 9: (bf) r2 = r10") ++__msg("frame1: regs=r1 stack= before 10: (bf) r2 = r10") ++__msg("frame1: regs=r1 stack= before 9: (25) if r1 > 0x7 goto pc+0") + __msg("frame1: regs=r1 stack=-8,-16 before 8: (7b) *(u64 *)(r10 -16) = r1") + __msg("frame1: regs=r1 stack=-8 before 7: (7b) *(u64 *)(r10 -8) = r1") + __msg("frame1: regs=r1 stack= before 4: (85) call pc+2") + /* main frame */ +-__msg("frame0: regs=r0,r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1") +-__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") ++__msg("frame0: regs=r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1") ++__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0") + __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") + __flag(BPF_F_TEST_STATE_FREQ) + __naked void precision_stack(void) +@@ -283,7 +218,8 @@ void precision_stack__foo(void) + */ + "*(u64*)(r10 - 8) = r1;" + "*(u64*)(r10 - 16) = r1;" +- /* force r1 to be precise, this immediately marks: ++ "if r1 > 7 goto +0;" ++ /* force r1 to be precise, this eventually marks: + * - foo frame r1,fp{-8,-16} + * - main frame r1,fp{-8} + */ +@@ -299,15 +235,17 @@ void precision_stack__foo(void) + SEC("socket") + __success __log_level(2) + /* r{6,7} */ +-__msg("11: (0f) r3 += r7") +-__msg("frame0: regs=r6,r7 stack= before 10: (bf) r3 = r10") ++__msg("12: (0f) r3 += r7") ++__msg("frame0: regs=r7 stack= before 11: (bf) r3 = r10") ++__msg("frame0: regs=r7 stack= before 9: (25) if r7 > 0x7 goto pc+0") + /* ... skip some insns ... */ + __msg("frame0: regs=r6,r7 stack= before 3: (bf) r7 = r0") + __msg("frame0: regs=r0,r6 stack= before 2: (bf) r6 = r0") + /* r{8,9} */ +-__msg("12: (0f) r3 += r9") +-__msg("frame0: regs=r8,r9 stack= before 11: (0f) r3 += r7") ++__msg("13: (0f) r3 += r9") ++__msg("frame0: regs=r9 stack= before 12: (0f) r3 += r7") + /* ... skip some insns ... */ ++__msg("frame0: regs=r9 stack= before 10: (25) if r9 > 0x7 goto pc+0") + __msg("frame0: regs=r8,r9 stack= before 7: (bf) r9 = r0") + __msg("frame0: regs=r0,r8 stack= before 6: (bf) r8 = r0") + __flag(BPF_F_TEST_STATE_FREQ) +@@ -328,8 +266,9 @@ __naked void precision_two_ids(void) + "r9 = r0;" + /* clear r0 id */ + "r0 = 0;" +- /* force checkpoint */ +- "goto +0;" ++ /* propagate equal scalars precision */ ++ "if r7 > 7 goto +0;" ++ "if r9 > 7 goto +0;" + "r3 = r10;" + /* force r7 to be precise, this also marks r6 */ + "r3 += r7;" +diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c +index b0b1bcc668adb1..59a020c3564742 100644 +--- a/tools/testing/selftests/bpf/verifier/precise.c ++++ b/tools/testing/selftests/bpf/verifier/precise.c +@@ -106,7 +106,7 @@ + mark_precise: frame0: regs=r2 stack= before 22\ + mark_precise: frame0: parent state regs=r2 stack=:\ + mark_precise: frame0: last_idx 20 first_idx 20\ +- mark_precise: frame0: regs=r2,r9 stack= before 20\ ++ mark_precise: frame0: regs=r2 stack= before 20\ + mark_precise: frame0: parent state regs=r2,r9 stack=:\ + mark_precise: frame0: last_idx 19 first_idx 17\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ +-- +2.53.0 + diff --git a/queue-6.6/bpf-track-equal-scalars-history-on-per-instruction-l.patch b/queue-6.6/bpf-track-equal-scalars-history-on-per-instruction-l.patch new file mode 100644 index 0000000000..b6fc9ca9ef --- /dev/null +++ b/queue-6.6/bpf-track-equal-scalars-history-on-per-instruction-l.patch @@ -0,0 +1,561 @@ +From 68149056b86877c9bf22ac86a175f7bcec2ce1a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Jun 2026 01:27:32 +0800 +Subject: bpf: Track equal scalars history on per-instruction level + +From: Eduard Zingerman + +[ Upstream commit 4bf79f9be434e000c8e12fe83b2f4402480f1460 ] + +Use bpf_verifier_state->jmp_history to track which registers were +updated by find_equal_scalars() (renamed to collect_linked_regs()) +when conditional jump was verified. Use recorded information in +backtrack_insn() to propagate precision. + +E.g. for the following program: + + while verifying instructions + 1: r1 = r0 | + 2: if r1 < 8 goto ... | push r0,r1 as linked registers in jmp_history + 3: if r0 > 16 goto ... | push r0,r1 as linked registers in jmp_history + 4: r2 = r10 | + 5: r2 += r0 v mark_chain_precision(r0) + + while doing mark_chain_precision(r0) + 5: r2 += r0 | mark r0 precise + 4: r2 = r10 | + 3: if r0 > 16 goto ... | mark r0,r1 as precise + 2: if r1 < 8 goto ... | mark r0,r1 as precise + 1: r1 = r0 v + +Technically, do this as follows: +- Use 10 bits to identify each register that gains range because of + sync_linked_regs(): + - 3 bits for frame number; + - 6 bits for register or stack slot number; + - 1 bit to indicate if register is spilled. +- Use u64 as a vector of 6 such records + 4 bits for vector length. +- Augment struct bpf_jmp_history_entry with a field 'linked_regs' + representing such vector. +- When doing check_cond_jmp_op() remember up to 6 registers that + gain range because of sync_linked_regs() in such a vector. +- Don't propagate range information and reset IDs for registers that + don't fit in 6-value vector. +- Push a pair {instruction index, linked registers vector} + to bpf_verifier_state->jmp_history. +- When doing backtrack_insn() check if any of recorded linked + registers is currently marked precise, if so mark all linked + registers as precise. + +This also requires fixes for two test_verifier tests: +- precise: test 1 +- precise: test 2 + +Both tests contain the following instruction sequence: + +19: (bf) r2 = r9 ; R2=scalar(id=3) R9=scalar(id=3) +20: (a5) if r2 < 0x8 goto pc+1 ; R2=scalar(id=3,umin=8) +21: (95) exit +22: (07) r2 += 1 ; R2_w=scalar(id=3+1,...) +23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0 +24: (07) r1 += -8 ; R1_w=fp-8 +25: (b7) r3 = 0 ; R3_w=0 +26: (85) call bpf_probe_read_kernel#113 + +The call to bpf_probe_read_kernel() at (26) forces r2 to be precise. +Previously, this forced all registers with same id to become precise +immediately when mark_chain_precision() is called. +After this change, the precision is propagated to registers sharing +same id only when 'if' instruction is backtracked. +Hence verification log for both tests is changed: +regs=r2,r9 -> regs=r2 for instructions 25..20. + +Fixes: 904e6ddf4133 ("bpf: Use scalar ids in mark_chain_precision()") +Reported-by: Hao Sun +Suggested-by: Andrii Nakryiko +Signed-off-by: Eduard Zingerman +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20240718202357.1746514-2-eddyz87@gmail.com +Closes: https://lore.kernel.org/bpf/CAEf4BzZ0xidVCqB47XnkXcNhkPWF6_nTV7yt+_Lf0kcFEut2Mg@mail.gmail.com/ +[ zhenzhong: backport to 6.6.y verifier layout and adapt + sync_linked_regs() to the pre-BPF_ADD_CONST scalar-id code. ] +Signed-off-by: Zhenzhong Wu +Signed-off-by: Sasha Levin +--- + include/linux/bpf_verifier.h | 4 + + kernel/bpf/verifier.c | 253 ++++++++++++++++-- + .../bpf/progs/verifier_subprog_precision.c | 2 +- + .../testing/selftests/bpf/verifier/precise.c | 2 +- + 4 files changed, 237 insertions(+), 24 deletions(-) + +diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h +index dba211d3bb9a0d..9a3b93c24f19f5 100644 +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -345,6 +345,10 @@ struct bpf_jmp_history_entry { + u32 prev_idx : 22; + /* special flags, e.g., whether insn is doing register stack spill/load */ + u32 flags : 10; ++ /* additional registers that need precision tracking when this ++ * jump is backtracked, vector of six 10-bit records ++ */ ++ u64 linked_regs; + }; + + /* Maximum number of register states that can exist at once */ +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 0d90236d0ad94f..2268f095203e21 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -3461,9 +3461,87 @@ static bool is_jmp_point(struct bpf_verifier_env *env, int insn_idx) + return env->insn_aux_data[insn_idx].jmp_point; + } + ++#define LR_FRAMENO_BITS 3 ++#define LR_SPI_BITS 6 ++#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1) ++#define LR_SIZE_BITS 4 ++#define LR_FRAMENO_MASK ((1ull << LR_FRAMENO_BITS) - 1) ++#define LR_SPI_MASK ((1ull << LR_SPI_BITS) - 1) ++#define LR_SIZE_MASK ((1ull << LR_SIZE_BITS) - 1) ++#define LR_SPI_OFF LR_FRAMENO_BITS ++#define LR_IS_REG_OFF (LR_SPI_BITS + LR_FRAMENO_BITS) ++#define LINKED_REGS_MAX 6 ++ ++struct linked_reg { ++ u8 frameno; ++ union { ++ u8 spi; ++ u8 regno; ++ }; ++ bool is_reg; ++}; ++ ++struct linked_regs { ++ int cnt; ++ struct linked_reg entries[LINKED_REGS_MAX]; ++}; ++ ++static struct linked_reg *linked_regs_push(struct linked_regs *s) ++{ ++ if (s->cnt < LINKED_REGS_MAX) ++ return &s->entries[s->cnt++]; ++ ++ return NULL; ++} ++ ++/* Use u64 as a vector of 6 10-bit values, use first 4-bits to track ++ * number of elements currently in stack. ++ * Pack one history entry for linked registers as 10 bits in the following format: ++ * - 3-bits frameno ++ * - 6-bits spi_or_reg ++ * - 1-bit is_reg ++ */ ++static u64 linked_regs_pack(struct linked_regs *s) ++{ ++ u64 val = 0; ++ int i; ++ ++ for (i = 0; i < s->cnt; ++i) { ++ struct linked_reg *e = &s->entries[i]; ++ u64 tmp = 0; ++ ++ tmp |= e->frameno; ++ tmp |= e->spi << LR_SPI_OFF; ++ tmp |= (e->is_reg ? 1 : 0) << LR_IS_REG_OFF; ++ ++ val <<= LR_ENTRY_BITS; ++ val |= tmp; ++ } ++ val <<= LR_SIZE_BITS; ++ val |= s->cnt; ++ return val; ++} ++ ++static void linked_regs_unpack(u64 val, struct linked_regs *s) ++{ ++ int i; ++ ++ s->cnt = val & LR_SIZE_MASK; ++ val >>= LR_SIZE_BITS; ++ ++ for (i = 0; i < s->cnt; ++i) { ++ struct linked_reg *e = &s->entries[i]; ++ ++ e->frameno = val & LR_FRAMENO_MASK; ++ e->spi = (val >> LR_SPI_OFF) & LR_SPI_MASK; ++ e->is_reg = (val >> LR_IS_REG_OFF) & 0x1; ++ val >>= LR_ENTRY_BITS; ++ } ++} ++ + /* for any branch, call, exit record the history of jmps in the given state */ + static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_state *cur, +- int insn_flags) ++ int insn_flags, u64 linked_regs) + { + u32 cnt = cur->jmp_history_cnt; + struct bpf_jmp_history_entry *p; +@@ -3479,6 +3557,10 @@ static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_st + "verifier insn history bug: insn_idx %d cur flags %x new flags %x\n", + env->insn_idx, env->cur_hist_ent->flags, insn_flags); + env->cur_hist_ent->flags |= insn_flags; ++ WARN_ONCE(env->cur_hist_ent->linked_regs != 0, ++ "verifier insn history bug: insn_idx %d linked_regs != 0: %#llx\n", ++ env->insn_idx, env->cur_hist_ent->linked_regs); ++ env->cur_hist_ent->linked_regs = linked_regs; + return 0; + } + +@@ -3493,6 +3575,7 @@ static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_st + p->idx = env->insn_idx; + p->prev_idx = env->prev_insn_idx; + p->flags = insn_flags; ++ p->linked_regs = linked_regs; + cur->jmp_history_cnt = cnt; + env->cur_hist_ent = p; + +@@ -3668,6 +3751,11 @@ static inline bool bt_is_reg_set(struct backtrack_state *bt, u32 reg) + return bt->reg_masks[bt->frame] & (1 << reg); + } + ++static inline bool bt_is_frame_reg_set(struct backtrack_state *bt, u32 frame, u32 reg) ++{ ++ return bt->reg_masks[frame] & (1 << reg); ++} ++ + static inline bool bt_is_frame_slot_set(struct backtrack_state *bt, u32 frame, u32 slot) + { + return bt->stack_masks[frame] & (1ull << slot); +@@ -3717,6 +3805,42 @@ static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) + } + } + ++/* If any register R in hist->linked_regs is marked as precise in bt, ++ * do bt_set_frame_{reg,slot}(bt, R) for all registers in hist->linked_regs. ++ */ ++static void bt_sync_linked_regs(struct backtrack_state *bt, struct bpf_jmp_history_entry *hist) ++{ ++ struct linked_regs linked_regs; ++ bool some_precise = false; ++ int i; ++ ++ if (!hist || hist->linked_regs == 0) ++ return; ++ ++ linked_regs_unpack(hist->linked_regs, &linked_regs); ++ for (i = 0; i < linked_regs.cnt; ++i) { ++ struct linked_reg *e = &linked_regs.entries[i]; ++ ++ if ((e->is_reg && bt_is_frame_reg_set(bt, e->frameno, e->regno)) || ++ (!e->is_reg && bt_is_frame_slot_set(bt, e->frameno, e->spi))) { ++ some_precise = true; ++ break; ++ } ++ } ++ ++ if (!some_precise) ++ return; ++ ++ for (i = 0; i < linked_regs.cnt; ++i) { ++ struct linked_reg *e = &linked_regs.entries[i]; ++ ++ if (e->is_reg) ++ bt_set_frame_reg(bt, e->frameno, e->regno); ++ else ++ bt_set_frame_slot(bt, e->frameno, e->spi); ++ } ++} ++ + static bool calls_callback(struct bpf_verifier_env *env, int insn_idx); + + /* For given verifier state backtrack_insn() is called from the last insn to +@@ -3756,6 +3880,12 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, + print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); + } + ++ /* If there is a history record that some registers gained range at this insn, ++ * propagate precision marks to those registers, so that bt_is_reg_set() ++ * accounts for these registers. ++ */ ++ bt_sync_linked_regs(bt, hist); ++ + if (class == BPF_ALU || class == BPF_ALU64) { + if (!bt_is_reg_set(bt, dreg)) + return 0; +@@ -3985,7 +4115,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, + */ + bt_set_reg(bt, dreg); + bt_set_reg(bt, sreg); +- /* else dreg K ++ } else if (BPF_SRC(insn->code) == BPF_K) { ++ /* dreg K + * Only dreg still needs precision before + * this insn, so for the K-based conditional + * there is nothing new to be marked. +@@ -4003,6 +4134,10 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, + /* to be analyzed */ + return -ENOTSUPP; + } ++ /* Propagate precision marks to linked registers, to account for ++ * registers marked as precise in this function. ++ */ ++ bt_sync_linked_regs(bt, hist); + return 0; + } + +@@ -4354,7 +4489,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) + + /* If some register with scalar ID is marked as precise, + * make sure that all registers sharing this ID are also precise. +- * This is needed to estimate effect of find_equal_scalars(). ++ * This is needed to estimate effect of sync_linked_regs(). + * Do this at the last instruction of each state, + * bpf_reg_state::id fields are valid for these instructions. + * +@@ -4368,7 +4503,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) + * ... + * --- state #1 {r1.id = A, r2.id = A} --- + * ... +- * if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 ++ * if (r2 > 10) goto exit; // sync_linked_regs() assigns range to r1 + * ... + * --- state #2 {r1.id = A, r2.id = A} --- + * r3 = r10 +@@ -4736,7 +4871,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, + } + + if (insn_flags) +- return push_jmp_history(env, env->cur_state, insn_flags); ++ return push_jmp_history(env, env->cur_state, insn_flags, 0); + return 0; + } + +@@ -5032,7 +5167,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, + insn_flags = 0; /* we are not restoring spilled register */ + } + if (insn_flags) +- return push_jmp_history(env, env->cur_state, insn_flags); ++ return push_jmp_history(env, env->cur_state, insn_flags, 0); + return 0; + } + +@@ -13540,7 +13675,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + ptr_reg = dst_reg; + else + /* Make sure ID is cleared otherwise dst_reg min/max could be +- * incorrectly propagated into other registers by find_equal_scalars() ++ * incorrectly propagated into other registers by sync_linked_regs() + */ + dst_reg->id = 0; + if (BPF_SRC(insn->code) == BPF_X) { +@@ -13700,7 +13835,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) + */ + if (need_id) + /* Assign src and dst registers the same ID +- * that will be used by find_equal_scalars() ++ * that will be used by sync_linked_regs() + * to propagate min/max range. + */ + src_reg->id = ++env->id_gen; +@@ -13746,7 +13881,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) + copy_register_state(dst_reg, src_reg); + /* Make sure ID is cleared if src_reg is not in u32 + * range otherwise dst_reg min/max could be incorrectly +- * propagated into src_reg by find_equal_scalars() ++ * propagated into src_reg by sync_linked_regs() + */ + if (!is_src_reg_u32) + dst_reg->id = 0; +@@ -14564,19 +14699,75 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn, + return true; + } + +-static void find_equal_scalars(struct bpf_verifier_state *vstate, +- struct bpf_reg_state *known_reg) ++static void __collect_linked_regs(struct linked_regs *reg_set, struct bpf_reg_state *reg, ++ u32 id, u32 frameno, u32 spi_or_reg, bool is_reg) + { +- struct bpf_func_state *state; ++ struct linked_reg *e; ++ ++ if (reg->type != SCALAR_VALUE || reg->id != id) ++ return; ++ ++ e = linked_regs_push(reg_set); ++ if (e) { ++ e->frameno = frameno; ++ e->is_reg = is_reg; ++ e->regno = spi_or_reg; ++ } else { ++ reg->id = 0; ++ } ++} ++ ++/* For all R being scalar registers or spilled scalar registers ++ * in verifier state, save R in linked_regs if R->id == id. ++ * If there are too many Rs sharing same id, reset id for leftover Rs. ++ */ ++static void collect_linked_regs(struct bpf_verifier_state *vstate, u32 id, ++ struct linked_regs *linked_regs) ++{ ++ struct bpf_func_state *func; + struct bpf_reg_state *reg; ++ int i, j; + +- bpf_for_each_reg_in_vstate(vstate, state, reg, ({ +- if (reg->type == SCALAR_VALUE && reg->id == known_reg->id) { ++ for (i = vstate->curframe; i >= 0; i--) { ++ func = vstate->frame[i]; ++ for (j = 0; j < BPF_REG_FP; j++) { ++ reg = &func->regs[j]; ++ __collect_linked_regs(linked_regs, reg, id, i, j, true); ++ } ++ for (j = 0; j < func->allocated_stack / BPF_REG_SIZE; j++) { ++ if (!is_spilled_reg(&func->stack[j])) ++ continue; ++ reg = &func->stack[j].spilled_ptr; ++ __collect_linked_regs(linked_regs, reg, id, i, j, false); ++ } ++ } ++} ++ ++/* For all R in linked_regs, copy known_reg range into R ++ * if R->id == known_reg->id. ++ */ ++static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_state *known_reg, ++ struct linked_regs *linked_regs) ++{ ++ struct bpf_reg_state *reg; ++ struct linked_reg *e; ++ int i; ++ ++ for (i = 0; i < linked_regs->cnt; ++i) { ++ e = &linked_regs->entries[i]; ++ reg = e->is_reg ? &vstate->frame[e->frameno]->regs[e->regno] ++ : &vstate->frame[e->frameno]->stack[e->spi].spilled_ptr; ++ if (reg->type != SCALAR_VALUE || reg == known_reg) ++ continue; ++ if (reg->id != known_reg->id) ++ continue; ++ { + s32 saved_subreg_def = reg->subreg_def; ++ + copy_register_state(reg, known_reg); + reg->subreg_def = saved_subreg_def; + } +- })); ++ } + } + + static int check_cond_jmp_op(struct bpf_verifier_env *env, +@@ -14587,6 +14778,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs; + struct bpf_reg_state *dst_reg, *other_branch_regs, *src_reg = NULL; + struct bpf_reg_state *eq_branch_regs; ++ struct linked_regs linked_regs = {}; + u8 opcode = BPF_OP(insn->code); + bool is_jmp32; + int pred = -1; +@@ -14704,6 +14896,21 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + return 0; + } + ++ /* Push scalar registers sharing same ID to jump history, ++ * do this before creating 'other_branch', so that both ++ * 'this_branch' and 'other_branch' share this history ++ * if parent state is created. ++ */ ++ if (BPF_SRC(insn->code) == BPF_X && src_reg->type == SCALAR_VALUE && src_reg->id) ++ collect_linked_regs(this_branch, src_reg->id, &linked_regs); ++ if (dst_reg->type == SCALAR_VALUE && dst_reg->id) ++ collect_linked_regs(this_branch, dst_reg->id, &linked_regs); ++ if (linked_regs.cnt > 1) { ++ err = push_jmp_history(env, this_branch, 0, linked_regs_pack(&linked_regs)); ++ if (err) ++ return err; ++ } ++ + other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx, + false); + if (!other_branch) +@@ -14746,8 +14953,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + src_reg, dst_reg, opcode); + if (src_reg->id && + !WARN_ON_ONCE(src_reg->id != other_branch_regs[insn->src_reg].id)) { +- find_equal_scalars(this_branch, src_reg); +- find_equal_scalars(other_branch, &other_branch_regs[insn->src_reg]); ++ sync_linked_regs(this_branch, src_reg, &linked_regs); ++ sync_linked_regs(other_branch, &other_branch_regs[insn->src_reg], ++ &linked_regs); + } + + } +@@ -14759,8 +14967,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, + + if (dst_reg->type == SCALAR_VALUE && dst_reg->id && + !WARN_ON_ONCE(dst_reg->id != other_branch_regs[insn->dst_reg].id)) { +- find_equal_scalars(this_branch, dst_reg); +- find_equal_scalars(other_branch, &other_branch_regs[insn->dst_reg]); ++ sync_linked_regs(this_branch, dst_reg, &linked_regs); ++ sync_linked_regs(other_branch, &other_branch_regs[insn->dst_reg], ++ &linked_regs); + } + + /* if one pointer register is compared to another pointer +@@ -16182,7 +16391,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, + * + * First verification path is [1-6]: + * - at (4) same bpf_reg_state::id (b) would be assigned to r6 and r7; +- * - at (5) r6 would be marked <= X, find_equal_scalars() would also mark ++ * - at (5) r6 would be marked <= X, sync_linked_regs() would also mark + * r7 <= X, because r6 and r7 share same id. + * Next verification path is [1-4, 6]. + * +@@ -16915,7 +17124,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) + * the current state. + */ + if (is_jmp_point(env, env->insn_idx)) +- err = err ? : push_jmp_history(env, cur, 0); ++ err = err ? : push_jmp_history(env, cur, 0, 0); + err = err ? : propagate_precision(env, &sl->state); + if (err) + return err; +@@ -17181,7 +17390,7 @@ static int do_check(struct bpf_verifier_env *env) + } + + if (is_jmp_point(env, env->insn_idx)) { +- err = push_jmp_history(env, state, 0); ++ err = push_jmp_history(env, state, 0, 0); + if (err) + return err; + } +diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +index 4b8b0f45d17d71..a188e26f04da70 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c ++++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c +@@ -141,7 +141,7 @@ __msg("mark_precise: frame0: last_idx 14 first_idx 9") + __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") + __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") + __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") +-__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") ++__msg("mark_precise: frame0: regs=r0,r6 stack= before 10: (bf) r6 = r0") + __msg("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop") + /* State entering callback body popped from states stack */ + __msg("from 9 to 17: frame1:") +diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c +index 8a2ff81d835088..b0b1bcc668adb1 100644 +--- a/tools/testing/selftests/bpf/verifier/precise.c ++++ b/tools/testing/selftests/bpf/verifier/precise.c +@@ -44,7 +44,7 @@ + mark_precise: frame0: regs=r2 stack= before 23\ + mark_precise: frame0: regs=r2 stack= before 22\ + mark_precise: frame0: regs=r2 stack= before 20\ +- mark_precise: frame0: parent state regs=r2 stack=:\ ++ mark_precise: frame0: parent state regs=r2,r9 stack=:\ + mark_precise: frame0: last_idx 19 first_idx 10\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ + mark_precise: frame0: regs=r9 stack= before 18\ +-- +2.53.0 + diff --git a/queue-6.6/ring-buffer-remove-ring_buffer_read_prepare_sync.patch b/queue-6.6/ring-buffer-remove-ring_buffer_read_prepare_sync.patch new file mode 100644 index 0000000000..169d230d8d --- /dev/null +++ b/queue-6.6/ring-buffer-remove-ring_buffer_read_prepare_sync.patch @@ -0,0 +1,222 @@ +From ea0d47aa0f73bba93be4ff4ca9651e3e0234bdb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 12:22:54 +0000 +Subject: ring-buffer: Remove ring_buffer_read_prepare_sync() + +From: Bjoern Doebel + +[ Upstream commit 119a5d573622ae90ba730d18acfae9bb75d77b9a ] + +When the ring buffer was first introduced, reading the non-consuming +"trace" file required disabling the writing of the ring buffer. To make +sure the writing was fully disabled before iterating the buffer with a +non-consuming read, it would set the disable flag of the buffer and then +call an RCU synchronization to make sure all the buffers were +synchronized. + +The function ring_buffer_read_start() originally would initialize the +iterator and call an RCU synchronization, but this was for each individual +per CPU buffer where this would get called many times on a machine with +many CPUs before the trace file could be read. The commit 72c9ddfd4c5bf +("ring-buffer: Make non-consuming read less expensive with lots of cpus.") +separated ring_buffer_read_start into ring_buffer_read_prepare(), +ring_buffer_read_sync() and then ring_buffer_read_start() to allow each of +the per CPU buffers to be prepared, call the read_buffer_read_sync() once, +and then the ring_buffer_read_start() for each of the CPUs which made +things much faster. + +The commit 1039221cc278 ("ring-buffer: Do not disable recording when there +is an iterator") removed the requirement of disabling the recording of the +ring buffer in order to iterate it, but it did not remove the +synchronization that was happening that was required to wait for all the +buffers to have no more writers. It's now OK for the buffers to have +writers and no synchronization is needed. + +Remove the synchronization and put back the interface for the ring buffer +iterator back before commit 72c9ddfd4c5bf was applied. + +Cc: Mathieu Desnoyers +Link: https://lore.kernel.org/20250630180440.3eabb514@batman.local.home +Reported-by: David Howells +Fixes: 1039221cc278 ("ring-buffer: Do not disable recording when there is an iterator") +Tested-by: David Howells +Reviewed-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt (Google) +Assisted-by: Kiro:claude-opus-4.8 +Signed-off-by: Bjoern Doebel +Signed-off-by: Sasha Levin +--- + include/linux/ring_buffer.h | 4 +-- + kernel/trace/ring_buffer.c | 67 ++++++------------------------------- + kernel/trace/trace.c | 14 +++----- + kernel/trace/trace_kdb.c | 8 ++--- + 4 files changed, 18 insertions(+), 75 deletions(-) + +diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h +index ded528d23f855b..382fbaa701f930 100644 +--- a/include/linux/ring_buffer.h ++++ b/include/linux/ring_buffer.h +@@ -129,9 +129,7 @@ ring_buffer_consume(struct trace_buffer *buffer, int cpu, u64 *ts, + unsigned long *lost_events); + + struct ring_buffer_iter * +-ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags); +-void ring_buffer_read_prepare_sync(void); +-void ring_buffer_read_start(struct ring_buffer_iter *iter); ++ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags); + void ring_buffer_read_finish(struct ring_buffer_iter *iter); + + struct ring_buffer_event * +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index 508edf1f3f1e2e..52c7dbccafedde 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -5084,28 +5084,20 @@ ring_buffer_consume(struct trace_buffer *buffer, int cpu, u64 *ts, + EXPORT_SYMBOL_GPL(ring_buffer_consume); + + /** +- * ring_buffer_read_prepare - Prepare for a non consuming read of the buffer ++ * ring_buffer_read_start - start a non consuming read of the buffer + * @buffer: The ring buffer to read from + * @cpu: The cpu buffer to iterate over + * @flags: gfp flags to use for memory allocation + * +- * This performs the initial preparations necessary to iterate +- * through the buffer. Memory is allocated, buffer recording +- * is disabled, and the iterator pointer is returned to the caller. +- * +- * Disabling buffer recording prevents the reading from being +- * corrupted. This is not a consuming read, so a producer is not +- * expected. +- * +- * After a sequence of ring_buffer_read_prepare calls, the user is +- * expected to make at least one call to ring_buffer_read_prepare_sync. +- * Afterwards, ring_buffer_read_start is invoked to get things going +- * for real. ++ * This creates an iterator to allow non-consuming iteration through ++ * the buffer. If the buffer is disabled for writing, it will produce ++ * the same information each time, but if the buffer is still writing ++ * then the first hit of a write will cause the iteration to stop. + * +- * This overall must be paired with ring_buffer_read_finish. ++ * Must be paired with ring_buffer_read_finish. + */ + struct ring_buffer_iter * +-ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags) ++ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags) + { + struct ring_buffer_per_cpu *cpu_buffer; + struct ring_buffer_iter *iter; +@@ -5130,51 +5122,12 @@ ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags) + + atomic_inc(&cpu_buffer->resize_disabled); + +- return iter; +-} +-EXPORT_SYMBOL_GPL(ring_buffer_read_prepare); +- +-/** +- * ring_buffer_read_prepare_sync - Synchronize a set of prepare calls +- * +- * All previously invoked ring_buffer_read_prepare calls to prepare +- * iterators will be synchronized. Afterwards, read_buffer_read_start +- * calls on those iterators are allowed. +- */ +-void +-ring_buffer_read_prepare_sync(void) +-{ +- synchronize_rcu(); +-} +-EXPORT_SYMBOL_GPL(ring_buffer_read_prepare_sync); +- +-/** +- * ring_buffer_read_start - start a non consuming read of the buffer +- * @iter: The iterator returned by ring_buffer_read_prepare +- * +- * This finalizes the startup of an iteration through the buffer. +- * The iterator comes from a call to ring_buffer_read_prepare and +- * an intervening ring_buffer_read_prepare_sync must have been +- * performed. +- * +- * Must be paired with ring_buffer_read_finish. +- */ +-void +-ring_buffer_read_start(struct ring_buffer_iter *iter) +-{ +- struct ring_buffer_per_cpu *cpu_buffer; +- unsigned long flags; +- +- if (!iter) +- return; +- +- cpu_buffer = iter->cpu_buffer; +- +- raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags); ++ guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock); + arch_spin_lock(&cpu_buffer->lock); + rb_iter_reset(iter); + arch_spin_unlock(&cpu_buffer->lock); +- raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags); ++ ++ return iter; + } + EXPORT_SYMBOL_GPL(ring_buffer_read_start); + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 6b35666a4e0be6..f57baf67726da8 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -4792,21 +4792,15 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) + if (iter->cpu_file == RING_BUFFER_ALL_CPUS) { + for_each_tracing_cpu(cpu) { + iter->buffer_iter[cpu] = +- ring_buffer_read_prepare(iter->array_buffer->buffer, +- cpu, GFP_KERNEL); +- } +- ring_buffer_read_prepare_sync(); +- for_each_tracing_cpu(cpu) { +- ring_buffer_read_start(iter->buffer_iter[cpu]); ++ ring_buffer_read_start(iter->array_buffer->buffer, ++ cpu, GFP_KERNEL); + tracing_iter_reset(iter, cpu); + } + } else { + cpu = iter->cpu_file; + iter->buffer_iter[cpu] = +- ring_buffer_read_prepare(iter->array_buffer->buffer, +- cpu, GFP_KERNEL); +- ring_buffer_read_prepare_sync(); +- ring_buffer_read_start(iter->buffer_iter[cpu]); ++ ring_buffer_read_start(iter->array_buffer->buffer, ++ cpu, GFP_KERNEL); + tracing_iter_reset(iter, cpu); + } + +diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c +index 59857a1ee44cdf..628c25693cef2f 100644 +--- a/kernel/trace/trace_kdb.c ++++ b/kernel/trace/trace_kdb.c +@@ -43,17 +43,15 @@ static void ftrace_dump_buf(int skip_entries, long cpu_file) + if (cpu_file == RING_BUFFER_ALL_CPUS) { + for_each_tracing_cpu(cpu) { + iter.buffer_iter[cpu] = +- ring_buffer_read_prepare(iter.array_buffer->buffer, +- cpu, GFP_ATOMIC); +- ring_buffer_read_start(iter.buffer_iter[cpu]); ++ ring_buffer_read_start(iter.array_buffer->buffer, ++ cpu, GFP_ATOMIC); + tracing_iter_reset(&iter, cpu); + } + } else { + iter.cpu_file = cpu_file; + iter.buffer_iter[cpu_file] = +- ring_buffer_read_prepare(iter.array_buffer->buffer, ++ ring_buffer_read_start(iter.array_buffer->buffer, + cpu_file, GFP_ATOMIC); +- ring_buffer_read_start(iter.buffer_iter[cpu_file]); + tracing_iter_reset(&iter, cpu_file); + } + +-- +2.53.0 + diff --git a/queue-6.6/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch b/queue-6.6/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch new file mode 100644 index 0000000000..4ff4c73306 --- /dev/null +++ b/queue-6.6/selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch @@ -0,0 +1,131 @@ +From 8dc4160546b2ef51f215e7a62cb71bfd7ba41711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Jun 2026 15:29:00 +0800 +Subject: selftests/bpf: Add test to ensure kprobe_multi is not sleepable + +From: Varun R Mallya + +commit c7cab53f9d5273f0cf2a26bdf178c4e074bdfb50 upstream. + +Add a selftest to ensure that kprobe_multi programs cannot be attached +using the BPF_F_SLEEPABLE flag. This test succeeds when the kernel +rejects attachment of kprobe_multi when the BPF_F_SLEEPABLE flag is set. + +Suggested-by: Leon Hwang +Signed-off-by: Varun R Mallya +Link: https://lore.kernel.org/r/20260408190137.101418-3-varunrmallya@gmail.com +Signed-off-by: Alexei Starovoitov +[shung-hsi.yu: borrowed 'saved_error' variable from commit 00cdcd2900bd +("selftests/bpf: Don't use libbpf_get_error() in kprobe_multi_test"). ] +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../bpf/prog_tests/kprobe_multi_test.c | 34 +++++++++++++++++++ + .../bpf/progs/kprobe_multi_sleepable.c | 25 ++++++++++++++ + 2 files changed, 59 insertions(+) + create mode 100644 tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c + +diff --git a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +index 4041cfa670eb4c..d41e140c315083 100644 +--- a/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c ++++ b/tools/testing/selftests/bpf/prog_tests/kprobe_multi_test.c +@@ -4,6 +4,7 @@ + #include "trace_helpers.h" + #include "kprobe_multi_empty.skel.h" + #include "kprobe_multi_override.skel.h" ++#include "kprobe_multi_sleepable.skel.h" + #include "bpf/libbpf_internal.h" + #include "bpf/hashmap.h" + +@@ -214,7 +215,9 @@ static void test_attach_api_syms(void) + static void test_attach_api_fails(void) + { + LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); ++ LIBBPF_OPTS(bpf_test_run_opts, topts); + struct kprobe_multi *skel = NULL; ++ struct kprobe_multi_sleepable *sl_skel = NULL; + struct bpf_link *link = NULL; + unsigned long long addrs[2]; + const char *syms[2] = { +@@ -222,6 +225,7 @@ static void test_attach_api_fails(void) + "bpf_fentry_test2", + }; + __u64 cookies[2]; ++ int saved_error, err; + + addrs[0] = ksym_get_addr("bpf_fentry_test1"); + addrs[1] = ksym_get_addr("bpf_fentry_test2"); +@@ -300,9 +304,39 @@ static void test_attach_api_fails(void) + if (!ASSERT_EQ(libbpf_get_error(link), -EINVAL, "fail_5_error")) + goto cleanup; + ++ /* fail_9 - sleepable kprobe multi should not attach */ ++ sl_skel = kprobe_multi_sleepable__open(); ++ if (!ASSERT_OK_PTR(sl_skel, "sleep_skel_open")) ++ goto cleanup; ++ ++ sl_skel->bss->user_ptr = sl_skel; ++ ++ err = bpf_program__set_flags(sl_skel->progs.handle_kprobe_multi_sleepable, ++ BPF_F_SLEEPABLE); ++ if (!ASSERT_OK(err, "sleep_skel_set_flags")) ++ goto cleanup; ++ ++ err = kprobe_multi_sleepable__load(sl_skel); ++ if (!ASSERT_OK(err, "sleep_skel_load")) ++ goto cleanup; ++ ++ link = bpf_program__attach_kprobe_multi_opts(sl_skel->progs.handle_kprobe_multi_sleepable, ++ "bpf_fentry_test1", NULL); ++ saved_error = -errno; ++ ++ if (!ASSERT_ERR_PTR(link, "fail_9")) ++ goto cleanup; ++ ++ if (!ASSERT_EQ(saved_error, -EINVAL, "fail_9_error")) ++ goto cleanup; ++ ++ err = bpf_prog_test_run_opts(bpf_program__fd(sl_skel->progs.fentry), &topts); ++ ASSERT_OK(err, "bpf_prog_test_run_opts"); ++ + cleanup: + bpf_link__destroy(link); + kprobe_multi__destroy(skel); ++ kprobe_multi_sleepable__destroy(sl_skel); + } + + static size_t symbol_hash(long key, void *ctx __maybe_unused) +diff --git a/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c b/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c +new file mode 100644 +index 00000000000000..932e1d9c72e2d0 +--- /dev/null ++++ b/tools/testing/selftests/bpf/progs/kprobe_multi_sleepable.c +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "vmlinux.h" ++#include ++#include ++ ++void *user_ptr = 0; ++ ++SEC("kprobe.multi") ++int handle_kprobe_multi_sleepable(struct pt_regs *ctx) ++{ ++ int a, err; ++ ++ err = bpf_copy_from_user(&a, sizeof(a), user_ptr); ++ barrier_var(a); ++ return err; ++} ++ ++SEC("fentry/bpf_fentry_test1") ++int BPF_PROG(fentry) ++{ ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; +-- +2.53.0 + diff --git a/queue-6.6/selftests-bpf-tests-for-per-insn-sync_linked_regs-pr.patch b/queue-6.6/selftests-bpf-tests-for-per-insn-sync_linked_regs-pr.patch new file mode 100644 index 0000000000..451cc0f376 --- /dev/null +++ b/queue-6.6/selftests-bpf-tests-for-per-insn-sync_linked_regs-pr.patch @@ -0,0 +1,221 @@ +From 5b907cc78afd5b4ddaa993898b4996a4eae29143 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Jun 2026 01:27:34 +0800 +Subject: selftests/bpf: Tests for per-insn sync_linked_regs() precision + tracking + +From: Eduard Zingerman + +[ Upstream commit bebc17b1c03b224a0b4aec6a171815e39f8ba9bc ] + +Add a few test cases to verify precision tracking for scalars gaining +range because of sync_linked_regs(): +- check what happens when more than 6 registers might gain range in + sync_linked_regs(); +- check if precision is propagated correctly when operand of + conditional jump gained range in sync_linked_regs() and one of + linked registers is marked precise; +- check if precision is propagated correctly when operand of + conditional jump gained range in sync_linked_regs() and a + other-linked operand of the conditional jump is marked precise; +- add a minimized reproducer for precision tracking bug reported in [0]; +- Check that mark_chain_precision() for one of the conditional jump + operands does not trigger equal scalars precision propagation. + +[0] https://lore.kernel.org/bpf/CAEf4BzZ0xidVCqB47XnkXcNhkPWF6_nTV7yt+_Lf0kcFEut2Mg@mail.gmail.com/ + +Signed-off-by: Eduard Zingerman +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20240718202357.1746514-4-eddyz87@gmail.com +[ zhenzhong: keep the linked_regs_broken_link_2 reject check, but + drop the mark_precise log expectations because 6.6.y does not derive + the scalar-vs-scalar range for that non-constant JMP_X comparison. ] +Signed-off-by: Zhenzhong Wu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_scalar_ids.c | 162 ++++++++++++++++++ + 1 file changed, 162 insertions(+) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +index f70392bf696c62..2eb85eb3a06ccb 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c ++++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +@@ -47,6 +47,72 @@ __naked void linked_regs_bpf_k(void) + : __clobber_all); + } + ++/* Registers r{0,1,2} share same ID when 'if r1 > ...' insn is processed, ++ * check that verifier marks r{1,2} as precise while backtracking ++ * 'if r1 > ...' with r0 already marked. ++ */ ++SEC("socket") ++__success __log_level(2) ++__flag(BPF_F_TEST_STATE_FREQ) ++__msg("frame0: regs=r0 stack= before 5: (2d) if r1 > r3 goto pc+0") ++__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") ++__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") ++__naked void linked_regs_bpf_x_src(void) ++{ ++ asm volatile ( ++ /* r0 = random number up to 0xff */ ++ "call %[bpf_ktime_get_ns];" ++ "r0 &= 0xff;" ++ /* tie r0.id == r1.id == r2.id */ ++ "r1 = r0;" ++ "r2 = r0;" ++ "r3 = 7;" ++ "if r1 > r3 goto +0;" ++ /* force r0 to be precise, this eventually marks r1 and r2 as ++ * precise as well because of shared IDs ++ */ ++ "r4 = r10;" ++ "r4 += r0;" ++ "r0 = 0;" ++ "exit;" ++ : ++ : __imm(bpf_ktime_get_ns) ++ : __clobber_all); ++} ++ ++/* Registers r{0,1,2} share same ID when 'if r1 > r3' insn is processed, ++ * check that verifier marks r{0,1,2} as precise while backtracking ++ * 'if r1 > r3' with r3 already marked. ++ */ ++SEC("socket") ++__success __log_level(2) ++__flag(BPF_F_TEST_STATE_FREQ) ++__msg("frame0: regs=r3 stack= before 5: (2d) if r1 > r3 goto pc+0") ++__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:") ++__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7") ++__naked void linked_regs_bpf_x_dst(void) ++{ ++ asm volatile ( ++ /* r0 = random number up to 0xff */ ++ "call %[bpf_ktime_get_ns];" ++ "r0 &= 0xff;" ++ /* tie r0.id == r1.id == r2.id */ ++ "r1 = r0;" ++ "r2 = r0;" ++ "r3 = 7;" ++ "if r1 > r3 goto +0;" ++ /* force r0 to be precise, this eventually marks r1 and r2 as ++ * precise as well because of shared IDs ++ */ ++ "r4 = r10;" ++ "r4 += r3;" ++ "r0 = 0;" ++ "exit;" ++ : ++ : __imm(bpf_ktime_get_ns) ++ : __clobber_all); ++} ++ + /* Same as linked_regs_bpf_k, but break one of the + * links, note that r1 is absent from regs=... in __msg below. + */ +@@ -280,6 +346,102 @@ __naked void precision_two_ids(void) + : __clobber_all); + } + ++SEC("socket") ++__success __log_level(2) ++__flag(BPF_F_TEST_STATE_FREQ) ++/* check thar r0 and r6 have different IDs after 'if', ++ * collect_linked_regs() can't tie more than 6 registers for a single insn. ++ */ ++__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1") ++__msg("9: (bf) r6 = r6 ; R6_w=scalar(id=2") ++/* check that r{0-5} are marked precise after 'if' */ ++__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0") ++__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:") ++__naked void linked_regs_too_many_regs(void) ++{ ++ asm volatile ( ++ /* r0 = random number up to 0xff */ ++ "call %[bpf_ktime_get_ns];" ++ "r0 &= 0xff;" ++ /* tie r{0-6} IDs */ ++ "r1 = r0;" ++ "r2 = r0;" ++ "r3 = r0;" ++ "r4 = r0;" ++ "r5 = r0;" ++ "r6 = r0;" ++ /* propagate range for r{0-6} */ ++ "if r0 > 7 goto +0;" ++ /* make r6 appear in the log */ ++ "r6 = r6;" ++ /* force r0 to be precise, ++ * this would cause r{0-4} to be precise because of shared IDs ++ */ ++ "r7 = r10;" ++ "r7 += r0;" ++ "r0 = 0;" ++ "exit;" ++ : ++ : __imm(bpf_ktime_get_ns) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__failure __log_level(2) ++__flag(BPF_F_TEST_STATE_FREQ) ++__msg("div by zero") ++__naked void linked_regs_broken_link_2(void) ++{ ++ asm volatile ( ++ "call %[bpf_get_prandom_u32];" ++ "r7 = r0;" ++ "r8 = r0;" ++ "call %[bpf_get_prandom_u32];" ++ "if r0 > 1 goto +0;" ++ /* r7.id == r8.id, ++ * thus r7 precision implies r8 precision, ++ * which implies r0 precision because of the conditional below. ++ */ ++ "if r8 >= r0 goto 1f;" ++ /* break id relation between r7 and r8 */ ++ "r8 += r8;" ++ /* make r7 precise */ ++ "if r7 == 0 goto 1f;" ++ "r0 /= 0;" ++"1:" ++ "r0 = 42;" ++ "exit;" ++ : ++ : __imm(bpf_get_prandom_u32) ++ : __clobber_all); ++} ++ ++/* Check that mark_chain_precision() for one of the conditional jump ++ * operands does not trigger equal scalars precision propagation. ++ */ ++SEC("socket") ++__success __log_level(2) ++__msg("3: (25) if r1 > 0x100 goto pc+0") ++__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0") ++__naked void cjmp_no_linked_regs_trigger(void) ++{ ++ asm volatile ( ++ /* r0 = random number up to 0xff */ ++ "call %[bpf_ktime_get_ns];" ++ "r0 &= 0xff;" ++ /* tie r0.id == r1.id */ ++ "r1 = r0;" ++ /* the jump below would be predicted, thus r1 would be marked precise, ++ * this should not imply precision mark for r0 ++ */ ++ "if r1 > 256 goto +0;" ++ "r0 = 0;" ++ "exit;" ++ : ++ : __imm(bpf_ktime_get_ns) ++ : __clobber_all); ++} ++ + /* Verify that check_ids() is used by regsafe() for scalars. + * + * r9 = ... some pointer with range X ... +-- +2.53.0 + diff --git a/queue-6.6/selftests-bpf-update-comments-find_equal_scalars-syn.patch b/queue-6.6/selftests-bpf-update-comments-find_equal_scalars-syn.patch new file mode 100644 index 0000000000..edc5b968ac --- /dev/null +++ b/queue-6.6/selftests-bpf-update-comments-find_equal_scalars-syn.patch @@ -0,0 +1,47 @@ +From 98cd3c2569986f8bc34dd093556847edd66e3f8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Jun 2026 01:27:35 +0800 +Subject: selftests/bpf: Update comments find_equal_scalars->sync_linked_regs + +From: Eduard Zingerman + +[ Upstream commit cfbf25481d6dec0089c99c9d33a2ea634fe8f008 ] + +find_equal_scalars() is renamed to sync_linked_regs(), +this commit updates existing references in the selftests comments. + +Signed-off-by: Eduard Zingerman +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20240718202357.1746514-5-eddyz87@gmail.com +[ zhenzhong: only two pre-existing comments still needed updating in 6.6.y. ] +Signed-off-by: Zhenzhong Wu +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/verifier_spill_fill.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +index 1f71f596d33f8b..07a2527a8f47a7 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c ++++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c +@@ -392,7 +392,7 @@ __naked void spill_32bit_of_64bit_fail(void) + *(u32*)(r10 - 8) = r1; \ + /* 32-bit fill r2 from stack. */ \ + r2 = *(u32*)(r10 - 8); \ +- /* Compare r2 with another register to trigger find_equal_scalars.\ ++ /* Compare r2 with another register to trigger sync_linked_regs.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. If the ID was mistakenly preserved on spill, this would\ + * cause the verifier to think that r1 is also equal to zero in one of\ +@@ -431,7 +431,7 @@ __naked void spill_16bit_of_32bit_fail(void) + *(u16*)(r10 - 8) = r1; \ + /* 16-bit fill r2 from stack. */ \ + r2 = *(u16*)(r10 - 8); \ +- /* Compare r2 with another register to trigger find_equal_scalars.\ ++ /* Compare r2 with another register to trigger sync_linked_regs.\ + * Having one random bit is important here, otherwise the verifier cuts\ + * the corners. If the ID was mistakenly preserved on spill, this would\ + * cause the verifier to think that r1 is also equal to zero in one of\ +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 4dabbbb607..d54e8b625e 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -18,3 +18,11 @@ rdma-bnxt_re-zero-shared-page-before-exposing-to-userspace.patch i2c-stub-reject-i2c-block-transfers-with-invalid-length.patch net-qualcomm-rmnet-fix-endpoint-use-after-free-in-rmnet_dellink.patch agp-amd64-fix-broken-error-propagation-in-agp_amd64_probe.patch +bpf-reject-sleepable-kprobe_multi-programs-at-attach.patch +selftests-bpf-add-test-to-ensure-kprobe_multi-is-not.patch +af_unix-reject-siocatmark-on-non-stream-sockets.patch +bpf-track-equal-scalars-history-on-per-instruction-l.patch +bpf-remove-mark_precise_scalar_ids.patch +selftests-bpf-tests-for-per-insn-sync_linked_regs-pr.patch +selftests-bpf-update-comments-find_equal_scalars-syn.patch +ring-buffer-remove-ring_buffer_read_prepare_sync.patch