From nobody Sat Sep 26 04:30:59 2026 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C46703BB672 for ; Fri, 4 Sep 2026 16:46:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540367; cv=none; b=DP5LN/GgtlV/6kx1zD+fyUUG377/upd6KX5S1DPonEfrfk8ePG3MzowhFSXbjF28G607RHAPTmxraYKm1vBzwBzBRSgkTdi/5eIY6l+Fya8pMlGVx+xP7oVkccLnaMibN2aMfWOZKdYZDvmzRYN/erwawonXVsU32BUpSgCj56s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540367; c=relaxed/simple; bh=hxQZMLwG6yecstcTEMEbqIUKya/zeWZiCbghCJI8fVQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=hzaNNZ4Y5c/PNz66QT6gXNbARi1GdMoU7Tw8MiD9bSDl+GSWvFkeDq8vfth30uCnZa1n7+mXmVXY6f5xi5r9NDNTzrJfNFhAF1kwUh2a0vpy9DfXSBP2NEwI38QYe1qSFwrJrqVwuGYQyMV1Gz2MOHX4Lg4Q0vo4ByNzK8GE/0M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=vpkXyu6U; arc=none smtp.client-ip=209.85.128.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="vpkXyu6U" Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-49b7c1dc61eso11047585e9.3 for ; Fri, 04 Sep 2026 09:46:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788540360; x=1789145160; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=vWNAdrwGmNJRf6eRTL3iblh5LCxPTOBo/qfLWNuuaXo=; b=vpkXyu6UIvcaSzsDleZpo1eGIF5yY+lTSnOrIhzO5QZNnnGlE05girF4gH4JixmfzK 50xri6fSK8PczTnr6MUN2GNZ8+fGTML/jfDv+s5+kKvZ++wKj7VArYmCwBJVzY6ok6dI 16uDI+uTmP0Yg6KEbmZgB6sHCemsYvLIbjQB4shpHvkoH7kgDoS2nOWxQZEH2nenm7E+ 3BiM+0fozaacAidqi66ze+841KgVSvmBfvFH4/XaAMuhhVkqchiR0xAUWAbIZzMWhtfe uABTOB/sIUCEkBAEiLLLocP8WBfBR0Pg6ItcfjHhreQXKjyE8b5B+xLeqVYHbYrjOjgY io0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788540360; x=1789145160; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vWNAdrwGmNJRf6eRTL3iblh5LCxPTOBo/qfLWNuuaXo=; b=ioJ9kJ+Pz1OcB4uap2Rn3Mck8JY5PErfHbQN6NMLz9qij/6DsqKga5dRgGQ3NESpeG EYL1B3NZnYO5NA0IasUyqS0eb0ogBClwZanZQmv4YtMsfUux4aoKyZiL/ypBuM7wEWuM ffAUL/kjyE6nA7KmEws8tebSo4Soe0dvIUO5ETCLiq0tv0K8rUoJjejwHMmnD6ju2H0p V2WmUonL9dFRKTDbgXJ6j1hEAmalh0nwoRcXVPyIER818cPKdXyjY1EJrZfvnPkkh9jE xkvhOVUVdF3F9xWOzKsbdOdkeIBnAH63Q9C9uHTLbbt6VlRBHy8OLnxoyKCCpeh23GLi 4z0A== X-Forwarded-Encrypted: i=1; AKwUvByb4pDppUGaZNngdxZfIJepfbEjuBGlDTH3q9Iyyy/oPKD9+v9Q5zbdTLc94E5t5MkMqdaZQ0p7GfvvbzA=@vger.kernel.org X-Gm-Message-State: AFuF++kI0oHZ0miN5lbVKrxovwBRHLvLCzRLIK6CWUoN2eifqIcennt1 GkaaXOv/NAfC8vIbZW6nUg3l3ltIPvhGxZ7dh0fIlAtn6mnpQ72qUC/hvwYENZS5SjM2pS44wUc Xx/H08buvn+Q7FsL6RV+ReA== X-Received: from wmwb5-n2.prod.google.com ([2002:a05:600d:4445:20b0:49a:1b4c:be]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:a40f:b0:49c:fa21:e74b with SMTP id 5b1f17b1804b1-49cfa21e9a7mr42587355e9.33.1788540360049; Fri, 04 Sep 2026 09:46:00 -0700 (PDT) Date: Fri, 4 Sep 2026 17:44:47 +0100 In-Reply-To: <20260904164450.1345852-1-vdonnefort@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260904164450.1345852-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog Message-ID: <20260904164450.1345852-2-vdonnefort@google.com> Subject: [PATCH v10 1/4] ring-buffer: Allow splice reads on static buffers From: Vincent Donnefort To: rostedt@goodmis.org, mhiramat@kernel.org, linux-trace-kernel@vger.kernel.org Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com, linux-kernel@vger.kernel.org, Vincent Donnefort Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ring_buffer_read_page() rejects splice (full=3D1) reads on static buffers (that is user-mapped, persistent or remote) because !read check assumes unread pages must be swapped. However for those buffers we have no other choice than memcpy the data. For the memcpy case, only return an error when the writer is still on the reader page for the splice interface to wait. Fixes: 117c39200d9d ("ring-buffer: Introducing ring-buffer mapping function= s") Signed-off-by: Vincent Donnefort diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index b0963ac6fd16..84fd4cdd486f 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -7193,15 +7193,8 @@ int ring_buffer_read_page(struct trace_buffer *buffe= r, unsigned int event_size; unsigned int flags =3D 0; =20 - /* - * If a full page is expected, this can still be returned - * if there's been a previous partial read and the - * rest of the page can be read and the commit page is off - * the reader page. - */ - if (full && - (!read || (len < (size - read)) || - cpu_buffer->reader_page =3D=3D cpu_buffer->commit_page)) + /* If a full page is requested, it cannot be the commit page */ + if (full && cpu_buffer->reader_page =3D=3D cpu_buffer->commit_page) return -1; =20 if (len > (size - read)) --=20 2.55.0.979.g7e5102b832-goog From nobody Sat Sep 26 04:30:59 2026 Received: from mail-ej1-f69.google.com (mail-ej1-f69.google.com [209.85.218.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0226B50AC26 for ; Fri, 4 Sep 2026 16:46:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540368; cv=none; b=UAQZrlAofqO8JWMZuaIJ9SQl/tz95Zety0HF//HhtWpODEQ+ideVmi/VGxnpKJCe8T5eMmQbX+A1Xq6NPyF8drYFvR18FwNuKdceD/iaRQHtqK4vbWTfT118/iY9Te4lwNPrPSj22rn3ZdDCA0KiaNTaXqn01gVZhwoKjop2ovk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540368; c=relaxed/simple; bh=hI6Yo/SzzDeDQdp1YtwKfqyl2kRcauH48h7Jd6w8i1A=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=aKtYS7WjrRUzkUEpkSzx32HMzvgcYbgLPrgm89wV+asM2Tc8B7g8PoA9oAYHxQGkbGzm+nlGn6c3wepb90kZjKA4Xkquxdb4A5YQwYIAVZ9DfzpLk8YnHLOIK55Ha/VI2BpOtc6cRdRUbK3mlCOlvgW4lkVKflVtaQ/0JMYIbfM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=c2eeeiR7; arc=none smtp.client-ip=209.85.218.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="c2eeeiR7" Received: by mail-ej1-f69.google.com with SMTP id a640c23a62f3a-c252a2ae8e1so134296666b.1 for ; Fri, 04 Sep 2026 09:46:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788540362; x=1789145162; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=eNMw7QkipfdJb+h9Ivn9kj53U0JBStcCK4SgvNSd3Ws=; b=c2eeeiR75/WRNgy2CCVjYfNmAynG8YUc27+ObOPr3ZALjk6lIUgasgbhbJagyiOMHn vh6mDGuVr+EPKI4ar2w//ERHi3UYfZWqTQPqDkKCEk0JTYb6tuXCeophuwFBUcW8wLu4 BVmqUqWq8cm9lPAPHnjerjUh2YXvbbgsRzKbY5sPlXZ0LQAG/Yr37h8ZpKidKspfpJaD NasZqgN6KvHHivC6Juwt6po+iw/vvkRnOtLVd9eDx4QJcoMKo1lvqIrxMqXykux067jC K+qqVWYbbVyFLF0xeBXDnRTLSKdaZ/HvSvbw7pOEAUMmsv98P9PTkdBJRfdnCeMeGz6j moeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788540362; x=1789145162; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=eNMw7QkipfdJb+h9Ivn9kj53U0JBStcCK4SgvNSd3Ws=; b=FKguvjn+F68v0OQ/C+VhUHFpBFxNEzauxYMtqfLZ4IwK5e70CL4tB971F2ZrnW4u8i NPq6CLABoy0YvrAgBVfLX+GIQSP7esAjK0oKoXWGycVKrogkKNtJsWPZ59jOF8ZqiD8X ocJULaQ5S9jg10u2JCDdAt0WmZoXBZjROp1npipkESwv6SFGBDTGJBqtAP846I+pE/li UPlEpSW8NiCp7oaG7yVT9M7cCG/C3qSw/jyUGfIUJUrcW9fo8OQOD0iVF5MMPI5JVbtu 3EnF9WEQuZP6lHdlTntQHlMlqjd7acvBtXxy/0YFbtsRtlekvi2fckYc1lhi0P7MJ4Ox x+AQ== X-Forwarded-Encrypted: i=1; AKwUvBwU9tfuxwcuPafvsOa8wrpPFtsRIUhgmszAfjpRy6goDQSNqllGNRoDx+2b0ZBGmnJs4HKTFIG8CYRO03w=@vger.kernel.org X-Gm-Message-State: AFuF++kyw4OwkWehpzoXET2JBBtHVKSBW0ERURCLBFkMZNB5BQGW/NHM 1I+PvehS4bfRrYa0Dl+A1N9QXjKRGFVZMlqLGliD5BYAFYaXERmiMouh81z2jOFNZFRutZRyXsB suiOLTnB27XEAWnm9r+mAhA== X-Received: from ejce24.prod.google.com ([2002:a17:906:3758:b0:c12:5f03:4d7f]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:c248:b0:c24:82b9:361c with SMTP id a640c23a62f3a-c260c9d096cmr355892566b.17.1788540361414; Fri, 04 Sep 2026 09:46:01 -0700 (PDT) Date: Fri, 4 Sep 2026 17:44:48 +0100 In-Reply-To: <20260904164450.1345852-1-vdonnefort@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260904164450.1345852-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog Message-ID: <20260904164450.1345852-3-vdonnefort@google.com> Subject: [PATCH v10 2/4] tracing: Fix subbuf resize races with trace_pipe_raw readers From: Vincent Donnefort To: rostedt@goodmis.org, mhiramat@kernel.org, linux-trace-kernel@vger.kernel.org Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com, linux-kernel@vger.kernel.org, Vincent Donnefort Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Concurrent subbuffer resizes may crash trace_pipe_raw readers or leak uninitialized memory to userspace due to stale size values. Modify ring_buffer_alloc_read_page() to handle the resizing of an existing buffer_data_read_page if necessary and add a new ring_buffer_read_page_size(). This new function enables ring-buffer buffer_data_read_page users to not call the racy ring_buffer_subbuf_size_get(). This makes the spare_size member of ftrace_buffer_info redundant. Finally, handle buffer_data_read_page/reader_page order discrepancy in ring_buffer_read_page(). On a mismatch simply copy manually the data to the buffer_data_read_page. Link: https://lore.kernel.org/all/20260817140812.2C7D41F00A3A@smtp.kernel.o= rg/ Fixes: bce761d75745 ("ring-buffer: Read and write to ring buffers with cust= om sub buffer size") Signed-off-by: Vincent Donnefort diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 0670742b2d60..afc7daa6ee7d 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h @@ -218,14 +218,15 @@ bool ring_buffer_time_stamp_abs(struct trace_buffer *= buffer); size_t ring_buffer_nr_dirty_pages(struct trace_buffer *buffer, int cpu); =20 struct buffer_data_read_page; -struct buffer_data_read_page * -ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu); +int ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu, + struct buffer_data_read_page **rpage); void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, struct buffer_data_read_page *page); int ring_buffer_read_page(struct trace_buffer *buffer, struct buffer_data_read_page *data_page, size_t len, int cpu, int full); void *ring_buffer_read_page_data(struct buffer_data_read_page *page); +unsigned int ring_buffer_read_page_size(struct buffer_data_read_page *rpag= e); =20 struct trace_seq; =20 diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 84fd4cdd486f..2f61cb510b0a 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -330,6 +330,11 @@ struct buffer_data_read_page { struct buffer_data_page *data; /* actual data, stored in this page */ }; =20 +static __always_inline unsigned int rb_read_page_capacity(struct buffer_da= ta_read_page *rpage) +{ + return (PAGE_SIZE << rpage->order) - BUF_PAGE_HDR_SIZE; +} + /* * Note, the buffer_page list must be first. The buffer pages * are allocated in cache lines, which means that each buffer @@ -6993,56 +6998,78 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu); * ring_buffer_alloc_read_page - allocate a page to read from buffer * @buffer: the buffer to allocate for. * @cpu: the cpu buffer to allocate. + * @rpage: pointer to pass in an already allocated page (can be NULL) + * and returns the allocated page. * - * This function is used in conjunction with ring_buffer_read_page. + * This function is used in conjunction with ring_buffer_read_page(). * When reading a full page from the ring buffer, these functions * can be used to speed up the process. The calling function should * allocate a few pages first with this function. Then when it * needs to get pages from the ring buffer, it passes the result - * of this function into ring_buffer_read_page, which will swap + * of this function into ring_buffer_read_page(), which will swap * the page that was allocated, with the read page of the buffer. * + * If @rpage is provided, and it has a different order than the current + * subbuffer order, its payload will be freed and re-allocated. If it + * already matches the order, it is simply returned. + * * Returns: - * The page allocated, or ERR_PTR + * 0 on success, < 0 on error */ -struct buffer_data_read_page * -ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu) +int ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu, + struct buffer_data_read_page **rpage) { struct ring_buffer_per_cpu *cpu_buffer; - struct buffer_data_read_page *bpage =3D NULL; unsigned long flags; + unsigned int order; =20 if (!cpumask_test_cpu(cpu, buffer->cpumask)) - return ERR_PTR(-ENODEV); + return -ENODEV; =20 - bpage =3D kzalloc_obj(*bpage); - if (!bpage) - return ERR_PTR(-ENOMEM); + if (!rpage) + return -EINVAL; =20 - bpage->order =3D buffer->subbuf_order; + order =3D READ_ONCE(buffer->subbuf_order); + + if (*rpage) { + if ((*rpage)->order =3D=3D order) + return 0; + + /* We can reuse rpage, but we discard the payload */ + free_pages((unsigned long)(*rpage)->data, (*rpage)->order); + (*rpage)->data =3D NULL; + } else { + *rpage =3D kzalloc_obj(**rpage); + if (!*rpage) + return -ENOMEM; + } + + (*rpage)->order =3D order; cpu_buffer =3D buffer->buffers[cpu]; + local_irq_save(flags); arch_spin_lock(&cpu_buffer->lock); =20 if (cpu_buffer->free_page.data) { - *bpage =3D cpu_buffer->free_page; + **rpage =3D cpu_buffer->free_page; cpu_buffer->free_page.data =3D NULL; } =20 arch_spin_unlock(&cpu_buffer->lock); local_irq_restore(flags); =20 - if (bpage->data) { - rb_init_data_page(bpage->data); + if ((*rpage)->data) { + rb_init_data_page((*rpage)->data); } else { - bpage->data =3D alloc_cpu_data(cpu, bpage->order); - if (!bpage->data) { - kfree(bpage); - return ERR_PTR(-ENOMEM); + (*rpage)->data =3D alloc_cpu_data(cpu, (*rpage)->order); + if (!(*rpage)->data) { + kfree(*rpage); + *rpage =3D NULL; + return -ENOMEM; } } =20 - return bpage; + return 0; } EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); =20 @@ -7050,21 +7077,30 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); * ring_buffer_free_read_page - free an allocated read page * @buffer: the buffer the page was allocate for * @cpu: the cpu buffer the page came from - * @data_page: the page to free + * @rpage: the buffer_data_read_page to free * * Free a page allocated from ring_buffer_alloc_read_page. */ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, - struct buffer_data_read_page *data_page) + struct buffer_data_read_page *rpage) { struct ring_buffer_per_cpu *cpu_buffer; - struct buffer_data_page *dpage =3D data_page->data; - struct page *page =3D virt_to_page(dpage); + struct buffer_data_page *dpage; unsigned long flags; + struct page *page; =20 if (!buffer || !buffer->buffers || !buffer->buffers[cpu]) return; =20 + if (!rpage) + return; + + dpage =3D rpage->data; + if (!dpage) + goto out; + + page =3D virt_to_page(dpage); + cpu_buffer =3D buffer->buffers[cpu]; =20 /* @@ -7072,14 +7108,14 @@ void ring_buffer_free_read_page(struct trace_buffer= *buffer, int cpu, * is different from the subbuffer order of the buffer - * we can't reuse it */ - if (page_ref_count(page) > 1 || data_page->order !=3D buffer->subbuf_orde= r) + if (page_ref_count(page) > 1 || rpage->order !=3D READ_ONCE(buffer->subbu= f_order)) goto out; =20 local_irq_save(flags); arch_spin_lock(&cpu_buffer->lock); =20 if (!cpu_buffer->free_page.data) { - cpu_buffer->free_page =3D *data_page; + cpu_buffer->free_page =3D *rpage; dpage =3D NULL; } =20 @@ -7087,8 +7123,8 @@ void ring_buffer_free_read_page(struct trace_buffer *= buffer, int cpu, local_irq_restore(flags); =20 out: - free_pages((unsigned long)dpage, data_page->order); - kfree(data_page); + free_pages((unsigned long)dpage, rpage->order); + kfree(rpage); } EXPORT_SYMBOL_GPL(ring_buffer_free_read_page); =20 @@ -7159,10 +7195,9 @@ int ring_buffer_read_page(struct trace_buffer *buffe= r, if (!dpage) return -1; =20 - guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock); + len =3D min_t(size_t, len, rb_read_page_capacity(data_page)); =20 - if (data_page->order !=3D cpu_buffer->reader_page->order) - return -1; + guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock); =20 reader =3D rb_get_reader_page(cpu_buffer); if (!reader) @@ -7177,16 +7212,18 @@ int ring_buffer_read_page(struct trace_buffer *buff= er, /* Check if any events were dropped */ missed_events =3D cpu_buffer->lost_events; =20 - /* - * If this page has been partially read or - * if len is not big enough to read the rest of the page or - * a writer is still on the page, then - * we must copy the data from the page to the buffer. - * Otherwise, we can simply swap the page with the one passed in. - */ + /* + * It is not possible to swap the reader page if: + * - It has been partially read + * - len is not big enough to read it entirely + * - A writer is still on it + * - The ring buffer is static + * - The order doesn't match + */ if (read || (len < (size - read)) || cpu_buffer->reader_page =3D=3D cpu_buffer->commit_page || - rb_is_static(cpu_buffer)) { + rb_is_static(cpu_buffer) || + data_page->order !=3D reader->order) { struct buffer_data_page *rpage =3D cpu_buffer->reader_page->page; unsigned int rpos =3D read; unsigned int pos =3D 0; @@ -7280,7 +7317,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer, * missed events, then record it there. */ if (missed_events > 0 && - rb_page_capacity(reader) - size >=3D sizeof(missed_events)) { + rb_read_page_capacity(data_page) - size >=3D sizeof(missed_events)) { memcpy(&dpage->data[size], &missed_events, sizeof(missed_events)); local_add(RB_MISSED_STORED, &dpage->commit); @@ -7300,8 +7337,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer, /* * This page may be off to user land. Zero it out here. */ - if (size < rb_page_capacity(reader)) - memset(&dpage->data[size], 0, rb_page_capacity(reader) - size); + if (size < rb_read_page_capacity(data_page)) + memset(&dpage->data[size], 0, rb_read_page_capacity(data_page) - size); =20 return read; } @@ -7319,6 +7356,18 @@ void *ring_buffer_read_page_data(struct buffer_data_= read_page *page) } EXPORT_SYMBOL_GPL(ring_buffer_read_page_data); =20 +/** + * ring_buffer_read_page_size - get size of the read page. + * @page: the page to get the size from + * + * Returns size of the page in bytes. + */ +unsigned int ring_buffer_read_page_size(struct buffer_data_read_page *rpag= e) +{ + return rpage ? PAGE_SIZE << rpage->order : 0; +} +EXPORT_SYMBOL_GPL(ring_buffer_read_page_size); + /** * ring_buffer_subbuf_size_get - get size of the sub buffer. * @buffer: the buffer to get the sub buffer size from @@ -7404,7 +7453,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer = *buffer, int order) /* Make sure all commits have finished */ synchronize_rcu(); =20 - buffer->subbuf_order =3D order; + WRITE_ONCE(buffer->subbuf_order, order); =20 /* Make sure all new buffers are allocated, before deleting the old ones = */ for_each_buffer_cpu(buffer, cpu) { @@ -7508,7 +7557,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer = *buffer, int order) return 0; =20 error: - buffer->subbuf_order =3D old_order; + WRITE_ONCE(buffer->subbuf_order, old_order); =20 atomic_dec(&buffer->record_disabled); =20 diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffe= r_benchmark.c index 593e3b59e42e..c3d34c0e64e2 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c @@ -104,7 +104,7 @@ static enum event_status read_event(int cpu) =20 static enum event_status read_page(int cpu) { - struct buffer_data_read_page *bpage; + struct buffer_data_read_page *bpage =3D NULL; struct ring_buffer_event *event; struct rb_page *rpage; unsigned long commit; @@ -114,8 +114,8 @@ static enum event_status read_page(int cpu) int inc; int i; =20 - bpage =3D ring_buffer_alloc_read_page(buffer, cpu); - if (IS_ERR(bpage)) + ret =3D ring_buffer_alloc_read_page(buffer, cpu, &bpage); + if (ret < 0) return EVENT_DROPPED; =20 page_size =3D ring_buffer_subbuf_size_get(buffer); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a946e0183fd1..b53ea3441e32 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -7082,8 +7082,8 @@ ssize_t tracing_buffers_read(struct file *filp, char = __user *ubuf, { struct ftrace_buffer_info *info =3D filp->private_data; struct trace_iterator *iter =3D &info->iter; + unsigned int spare_size; void *trace_data; - int page_size; ssize_t ret =3D 0; ssize_t size; =20 @@ -7093,36 +7093,22 @@ ssize_t tracing_buffers_read(struct file *filp, cha= r __user *ubuf, if (iter->snapshot && tracer_uses_snapshot(iter->tr->current_trace)) return -EBUSY; =20 - page_size =3D ring_buffer_subbuf_size_get(iter->array_buffer->buffer); - - /* Make sure the spare matches the current sub buffer size */ - if (info->spare) { - if (page_size !=3D info->spare_size) { - ring_buffer_free_read_page(iter->array_buffer->buffer, - info->spare_cpu, info->spare); - info->spare =3D NULL; - } - } - - if (!info->spare) { - info->spare =3D ring_buffer_alloc_read_page(iter->array_buffer->buffer, - iter->cpu_file); - if (IS_ERR(info->spare)) { - ret =3D PTR_ERR(info->spare); - info->spare =3D NULL; - } else { - info->spare_cpu =3D iter->cpu_file; - info->spare_size =3D page_size; - } - } - if (!info->spare) - return ret; + spare_size =3D ring_buffer_read_page_size(info->spare); =20 +again: /* Do we have previous read data to read? */ - if (info->read < page_size) + if (info->read < spare_size) goto read; =20 - again: + ret =3D ring_buffer_alloc_read_page(iter->array_buffer->buffer, iter->cpu= _file, + &info->spare); + if (ret) + return ret; + + spare_size =3D ring_buffer_read_page_size(info->spare); + info->read =3D spare_size; + info->spare_cpu =3D iter->cpu_file; + trace_access_lock(iter->cpu_file); ret =3D ring_buffer_read_page(iter->array_buffer->buffer, info->spare, @@ -7148,8 +7134,9 @@ ssize_t tracing_buffers_read(struct file *filp, char = __user *ubuf, } =20 info->read =3D 0; + read: - size =3D page_size - info->read; + size =3D spare_size - info->read; if (size > count) size =3D count; trace_data =3D ring_buffer_read_page_data(info->spare); @@ -7190,26 +7177,24 @@ int tracing_buffers_release(struct inode *inode, st= ruct file *file) =20 __trace_array_put(iter->tr); =20 - if (info->spare) - ring_buffer_free_read_page(iter->array_buffer->buffer, - info->spare_cpu, info->spare); + ring_buffer_free_read_page(iter->array_buffer->buffer, info->spare_cpu, i= nfo->spare); kvfree(info); =20 return 0; } =20 struct buffer_ref { - struct trace_buffer *buffer; - void *page; - int cpu; - refcount_t refcount; + struct trace_buffer *buffer; + struct buffer_data_read_page *rpage; + int cpu; + refcount_t refcount; }; =20 static void buffer_ref_release(struct buffer_ref *ref) { if (!refcount_dec_and_test(&ref->refcount)) return; - ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->page); + ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->rpage); kfree(ref); } =20 @@ -7268,25 +7253,15 @@ ssize_t tracing_buffers_splice_read(struct file *fi= le, loff_t *ppos, .ops =3D &buffer_pipe_buf_ops, .spd_release =3D buffer_spd_release, }; + unsigned int page_size =3D 0; struct buffer_ref *ref; bool woken =3D false; - int page_size; int entries, i; ssize_t ret =3D 0; =20 if (iter->snapshot && tracer_uses_snapshot(iter->tr->current_trace)) return -EBUSY; =20 - page_size =3D ring_buffer_subbuf_size_get(iter->array_buffer->buffer); - if (*ppos & (page_size - 1)) - return -EINVAL; - - if (len & (page_size - 1)) { - if (len < page_size) - return -EINVAL; - len &=3D (~(page_size - 1)); - } - if (splice_grow_spd(pipe, &spd)) return -ENOMEM; =20 @@ -7306,25 +7281,37 @@ ssize_t tracing_buffers_splice_read(struct file *fi= le, loff_t *ppos, =20 refcount_set(&ref->refcount, 1); ref->buffer =3D iter->array_buffer->buffer; - ref->page =3D ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file); - if (IS_ERR(ref->page)) { - ret =3D PTR_ERR(ref->page); - ref->page =3D NULL; + + ret =3D ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file, &ref->r= page); + if (ret) { kfree(ref); break; } ref->cpu =3D iter->cpu_file; =20 - r =3D ring_buffer_read_page(ref->buffer, ref->page, - len, iter->cpu_file, 1); + page_size =3D ring_buffer_read_page_size(ref->rpage); + + r =3D -EINVAL; + if (IS_ALIGNED(*ppos, page_size) && len >=3D page_size) { + r =3D ring_buffer_read_page(ref->buffer, ref->rpage, len, iter->cpu_fil= e, 1); + } else if (!i) { + /* + * We failed to read because the length is too small + * or unaligned. If this is the first iteration, it's + * an invalid userspace input. Otherwise, this is due + * to a subbuf order change. Do not report an error + * and just finish the read. + */ + ret =3D -EINVAL; + } + if (r < 0) { - ring_buffer_free_read_page(ref->buffer, ref->cpu, - ref->page); + ring_buffer_free_read_page(ref->buffer, ref->cpu, ref->rpage); kfree(ref); break; } =20 - page =3D virt_to_page(ring_buffer_read_page_data(ref->page)); + page =3D virt_to_page(ring_buffer_read_page_data(ref->rpage)); =20 spd.pages[i] =3D page; spd.partial[i].len =3D page_size; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 74a7a50d1e78..203d098ee14e 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -745,11 +745,10 @@ static inline int tracing_get_cpu(struct inode *inode) void tracing_reset_cpu(struct array_buffer *buf, int cpu); =20 struct ftrace_buffer_info { - struct trace_iterator iter; - void *spare; - unsigned int spare_cpu; - unsigned int spare_size; - unsigned int read; + struct trace_iterator iter; + struct buffer_data_read_page *spare; + unsigned int spare_cpu; + unsigned int read; }; =20 /** --=20 2.55.0.979.g7e5102b832-goog From nobody Sat Sep 26 04:30:59 2026 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF28B3ED5B9 for ; Fri, 4 Sep 2026 16:46:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.70 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540371; cv=none; b=lnB4LOeGfbd8NrNcKInP9VvCzHKWeviSax1cIXxD/uVciTz162xqQHz1JdE8BgtpbpaFDgZK2p1AEoOp72kYTyQRqMBhquYCvbmticuoDt9Vm+qsnyU+ux5of/76XSPHNH7fPR7dsQW53GfIw37ebJxioJbk6c0Jo6n6PRMn8YA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540371; c=relaxed/simple; bh=zwkR7TgkVeDk0ytufotfdz2f4wLItmcCVvFEhb9aV88=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ROFF5I0jvVgh5D+Zqf2q0mwW1rC+0YyBCH1nrCKntHc3pnu37VkJMQ2ZWk1xBUWB9J3ejojdYXj0by8EMn9cyLHy0zN1qbJW2Bro96PD6WhQ59d9wq4BowlKma5uAfG1SGaWRfJZfbzy7nJpmbTD8hyx690jFnKfeCnXMFER3Q8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=sHmwk9Oc; arc=none smtp.client-ip=209.85.128.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="sHmwk9Oc" Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49cf9df1eadso7819075e9.3 for ; Fri, 04 Sep 2026 09:46:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788540363; x=1789145163; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=VfQOViLj37OZFcHE7Ja+dfLarOMI5STQSlwFxhzFw4w=; b=sHmwk9OcNdAFOT1YumMucnW+EwMwafdJ5pcyqfVU6XeFgP6iBzh4mtwcM01y8N59U8 la6ZUU6PulrMG7qifI91RFWuQWcpzXjU8HKLOCWM3Qhg38/ONfWWsN0JQg4vBY1aZmZ9 xLS/a0DsnRnZ6GB8iWXqi5D4y9FleFzINdZ4t0q6AkzNfnF1XGAcPQXTX9/aE6mzPsTN UX5/r/+4+N3/xzyJPlMkBb/dTwbrZxOKmD2cGtAD/GXAhVzWi6Ra9grFbdtKV7v2Ww3G MGXmV1UnX3TnQoNvS9kENdokuMFxAF6YKuHNbjh8BZhTboh3iPvE46b4S85BL+VxUCcw U5aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788540363; x=1789145163; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=VfQOViLj37OZFcHE7Ja+dfLarOMI5STQSlwFxhzFw4w=; b=mDqgZ8OgiN+B4WLq+bijLTncw4WxMH/6y+CIPO+iUxcBXacXxq24pSSlUg8vkwEwlV WRlsGqzvTfmVVHTR58QwA4zY1pY68kqc7AqZ26WOR9VKO68O2fIv8X3tlLf3AnWOCxqe Zv/JzAR5XqXu04ujJjWevl93vFMOdOCufh2qd6w95w0LMiAgjUkK90HOO72dlvJ7l79r 1P4gLAHDKkS4djtcy0b/FGgYq1779M1MVUzARmjjZ8gQmE094v2poHPsAY41YD69zk37 FOscPc4nrBMf63DredxA+7drvZIkjA5DFXzFjP+fvQVI7PdlxgSglx9Xskfw0nmcOO4X Tn3A== X-Forwarded-Encrypted: i=1; AKwUvBySBWTXRayD8YEWMDz4S/8ZjOOuJWSOuFSqwx45B741vt/CWA1uhsLsYnHGnZdfiHnkGwrhvkTrVsscUAc=@vger.kernel.org X-Gm-Message-State: AFuF++k2gyYbukGryCXPZwJSnYmmEYiYBO1OAMRkzIJgcC5sc8E3CWYk Lj4rNylhG7n7D2TLS3KnmAF7pGPdYgBQNJtlZ/suOi1wXX8lG2twByiHIKn4uIqSdiZl0JMHOCC Fe/VY28C2AbnP5tFfFxjDIw== X-Received: from wrna6.prod.google.com ([2002:adf:e5c6:0:b0:484:3346:46c9]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:6214:b0:49c:edd8:ba35 with SMTP id 5b1f17b1804b1-49cf823b95dmr84082495e9.6.1788540362432; Fri, 04 Sep 2026 09:46:02 -0700 (PDT) Date: Fri, 4 Sep 2026 17:44:49 +0100 In-Reply-To: <20260904164450.1345852-1-vdonnefort@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260904164450.1345852-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog Message-ID: <20260904164450.1345852-4-vdonnefort@google.com> Subject: [PATCH v10 3/4] ring-buffer: Cap static ring buffer nr_pages From: Vincent Donnefort To: rostedt@goodmis.org, mhiramat@kernel.org, linux-trace-kernel@vger.kernel.org Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com, linux-kernel@vger.kernel.org, Vincent Donnefort Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Static ring buffers (i.e. persistent, user-mapped and remote) rely on the bpage::id field. The number of pages for those ring buffers must fit into that variable. Enforce this limit on ring buffer creation or user-mapping. While at it, prevent nr_pages underflow when allocating a persistent buffer. Fixes: be68d63a139b ("ring-buffer: Add ring_buffer_alloc_range()") Signed-off-by: Vincent Donnefort diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 2f61cb510b0a..6b914abd80e3 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -657,6 +657,15 @@ static bool rb_is_static(struct ring_buffer_per_cpu *c= pu_buffer) return cpu_buffer->user_mapped || cpu_buffer->remote || cpu_buffer->ring_= meta; } =20 +static unsigned long rb_static_max_pages(void) +{ + /* + * Static ring buffers are using bpage::id and must account for the + * reader page. + */ + return (1UL << 30) - 1; +} + struct ring_buffer_iter { struct ring_buffer_per_cpu *cpu_buffer; unsigned long head; @@ -2833,6 +2842,8 @@ static struct trace_buffer *alloc_buffer(unsigned lon= g size, unsigned flags, size =3D end - buffers_start; size =3D size / nr_cpu_ids; =20 + if (size < sizeof(struct ring_buffer_cpu_meta)) + goto fail_free_buffers; /* * The number of sub-buffers (nr_pages) is determined by the * total size allocated minus the meta data size. @@ -2842,6 +2853,10 @@ static struct trace_buffer *alloc_buffer(unsigned lo= ng size, unsigned flags, */ nr_pages =3D (size - sizeof(struct ring_buffer_cpu_meta)) / (subbuf_size + sizeof(int)); + + if (nr_pages > rb_static_max_pages()) + goto fail_free_buffers; + /* Need at least two pages plus the reader page */ if (nr_pages < 3) goto fail_free_buffers; @@ -2874,6 +2889,10 @@ static struct trace_buffer *alloc_buffer(unsigned lo= ng size, unsigned flags, /* The writer is remote. This ring-buffer is read-only */ atomic_inc(&buffer->record_disabled); nr_pages =3D desc->nr_page_va - 1; + + if (nr_pages > rb_static_max_pages()) + goto fail_free_buffers; + if (nr_pages < 2) goto fail_free_buffers; } else { @@ -7836,6 +7855,9 @@ int ring_buffer_map(struct trace_buffer *buffer, int = cpu, /* prevent another thread from changing buffer/sub-buffer sizes */ guard(mutex)(&buffer->mutex); =20 + if (cpu_buffer->nr_pages > rb_static_max_pages()) + return -E2BIG; + err =3D rb_alloc_meta_page(cpu_buffer); if (err) return err; --=20 2.55.0.979.g7e5102b832-goog From nobody Sat Sep 26 04:30:59 2026 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 49D7D4FDE4A for ; Fri, 4 Sep 2026 16:46:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540373; cv=none; b=TDWccnbN/vfahl1Wp2LJqAWTwgu1YW4w2v/QrmuMFKbtZz8Zba0vQ9tbmcjS6R/eaMzwmH7YdxGXrkpJF0ovrbDAvVDFYxJLxHxSsxnk1YoCEs/ntfjziSEfc5pBGNiegGKTuPUjs1GM8mTkM/5VYehg3dvpWnKZOWrHCnCrr9I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788540373; c=relaxed/simple; bh=tTkxN6nEVcf2+9kQqPEhjuPbiU+p+OP0Ec8pMvutCwM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lRO1b1OXPE6XUGUAUZHxXs2RTmp0Uv9OLfYYxBdD2QDhK6pX708/+si7qPspmpJVb1ORBK/eignVtnci5UT5TX8bMd0LiG+bBL+OR9KEVCoxpqzLImbjc7UYcfnqEjHr+dPRLaWpXHnKBt8N1ISbMLeieuArR1USlMLOvgF+urM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=R2psTCQw; arc=none smtp.client-ip=209.85.128.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--vdonnefort.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="R2psTCQw" Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-49b7c1dcc82so7778275e9.0 for ; Fri, 04 Sep 2026 09:46:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788540364; x=1789145164; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=lmbeq+6+7aXhj42bquXwzaggywIkbesNWpCKPX7e7W4=; b=R2psTCQwvPP854YtEUgaOA0DjTPihmrvc/H8Cx9fyRNXYHlfRnqoNghy57HTlJS4Rg w+z1oSuoM6EqRiWVAhCDXU/XBAXAw+KevSORjksQYtPakNdsUoZBp7z/4y6hcm4KFPpA fx8DwfUjaGIev9uKzFIH0AkLwDb/zwE9SvpAHNzQH9xAUm8+/Fqp9Gk/I96q/zwtPnn4 29kJ9fjiX6E8FOdxdlOWtCUFPMrcsEPOvrTrDcsKFG/x7gS00nGYiI7yGG8D39XL2vLD rOCvOp2SG03Lom2uagaNy3cqHHymMEcK7G3h43QCIVqu8Rcd31NxI7PBDTrtJiI5P9dt wKZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788540364; x=1789145164; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lmbeq+6+7aXhj42bquXwzaggywIkbesNWpCKPX7e7W4=; b=GCxrj4Fux5x1alp5WQxTulqxZNME/fIqZHMl460R9pZC71cFrSNVOxiAf/DyS/86O2 pYcJQBeHsb+JWi7524BsHFVt4lcle7sNkZ/RYfGjHsHxqIBs24MiaaqUr/KpOy5JDEmn w4HH/RzpdGBmPPTQ63tZfv6JCMKAsbaJpD5r88qtRylq4+93w2r3Xvqyc/4av3NvRAVa wCrHFTyc/voLEBvkvAsH0BeBOfS1hJvq9eT8VWF7y/i3ANK6Y1tXcD0LJrQWAEM8T0JK 8KgBw9T7edHuVrnNqCEbqWcmXoPmYFcDNtjPXd50KUXOy+zk1RgEXEAsgIFdlZhrdXR2 R/+g== X-Forwarded-Encrypted: i=1; AKwUvBxrDX/1mmP8IKi5xAR+tr/Q8xFZq3lRkdpverBTE9SgvI4W+pHzVuGUv3wVOooS2APen+5sQxZ3o0rorM4=@vger.kernel.org X-Gm-Message-State: AFuF++kvJ6jW/weK8N3TY5miR/aai/ui2U+ZJBQYGT5vUBNrcKETgasx r2AUnD55PLqbWIV1hmtMwPi+t64jxAIuMuLNBzbcMClymv/WAhfGzTp/4dgYRBNvzKJv2i3AIhm NuThsFCfq5rI0sLOSQ5GvEQ== X-Received: from wmbgv7.prod.google.com ([2002:a05:600c:80c7:b0:499:8840:6abc]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600d:864a:10b0:49c:fc89:59cb with SMTP id 5b1f17b1804b1-49cfc8960ccmr36232615e9.5.1788540363708; Fri, 04 Sep 2026 09:46:03 -0700 (PDT) Date: Fri, 4 Sep 2026 17:44:50 +0100 In-Reply-To: <20260904164450.1345852-1-vdonnefort@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260904164450.1345852-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog Message-ID: <20260904164450.1345852-5-vdonnefort@google.com> Subject: [PATCH v10 4/4] ring-buffer: Prevent truncation of nr_pages / nr_subbufs From: Vincent Donnefort To: rostedt@goodmis.org, mhiramat@kernel.org, linux-trace-kernel@vger.kernel.org Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com, linux-kernel@vger.kernel.org, Vincent Donnefort Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Although ring_buffer_per_cpu::nr_pages is defined as unsigned long, it is capped to 32-bits in a few places, limiting the operations possible on a very large buffer. Use `unsigned long` where appropriate and prevent truncation of values using nr_pages (or nr_subbufs). While at it, subbuf_size must be at least `unsigned int`. Note that persistent, remote and user-mapped ring buffers are capping the number of pages to 30 bits already, making "int" safe in many places. Signed-off-by: Vincent Donnefort diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 6b914abd80e3..504a01a1d380 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1683,7 +1683,7 @@ static void rb_check_pages(struct ring_buffer_per_cpu= *cpu_buffer) * This is used to help find the next per cpu subbuffer within a mapped ra= nge. */ static unsigned long -rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs) +rb_range_align_subbuf(unsigned long addr, unsigned int subbuf_size, unsign= ed long nr_subbufs) { addr +=3D sizeof(struct ring_buffer_cpu_meta) + sizeof(int) * nr_subbufs; @@ -1693,13 +1693,12 @@ rb_range_align_subbuf(unsigned long addr, int subbu= f_size, int nr_subbufs) /* * Return the ring_buffer_meta for a given @cpu. */ -static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int = cpu) +static void *rb_range_meta(struct trace_buffer *buffer, unsigned long nr_p= ages, int cpu) { - int subbuf_size =3D rb_subbuf_size(buffer); + unsigned int subbuf_size =3D rb_subbuf_size(buffer); struct ring_buffer_cpu_meta *meta; struct ring_buffer_meta *bmeta; - unsigned long ptr; - int nr_subbufs; + unsigned long ptr, nr_subbufs; =20 bmeta =3D buffer->meta; if (!bmeta) @@ -1745,7 +1744,7 @@ static void *rb_range_meta(struct trace_buffer *buffe= r, int nr_pages, int cpu) /* Return the start of subbufs given the meta pointer */ static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta) { - int subbuf_size =3D meta->subbuf_size; + unsigned int subbuf_size =3D meta->subbuf_size; unsigned long ptr; =20 ptr =3D (unsigned long)meta; @@ -1757,11 +1756,11 @@ static void *rb_subbufs_from_meta(struct ring_buffe= r_cpu_meta *meta) /* * Return a specific sub-buffer for a given @cpu defined by @idx. */ -static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int i= dx) +static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, unsig= ned long idx) { struct ring_buffer_cpu_meta *meta; + unsigned int subbuf_size; unsigned long ptr; - int subbuf_size; =20 meta =3D rb_range_meta(cpu_buffer->buffer, 0, cpu_buffer->cpu); if (!meta) @@ -1777,7 +1776,7 @@ static void *rb_range_buffer(struct ring_buffer_per_c= pu *cpu_buffer, int idx) =20 ptr =3D (unsigned long)rb_subbufs_from_meta(meta); =20 - ptr +=3D subbuf_size * idx; + ptr +=3D (unsigned long)subbuf_size * idx; if (ptr + subbuf_size > cpu_buffer->buffer->range_addr_end) return NULL; =20 @@ -1854,13 +1853,12 @@ static bool rb_meta_init(struct trace_buffer *buffe= r, int scratch_size) * must be the same. */ static bool rb_cpu_meta_valid(struct ring_buffer_cpu_meta *meta, int cpu, - struct trace_buffer *buffer, int nr_pages, + struct trace_buffer *buffer, unsigned long nr_pages, unsigned long *subbuf_mask) { - int subbuf_size =3D PAGE_SIZE; unsigned long buffers_start; unsigned long buffers_end; - int i; + unsigned long i; =20 if (!subbuf_mask) return false; @@ -1871,7 +1869,7 @@ static bool rb_cpu_meta_valid(struct ring_buffer_cpu_= meta *meta, int cpu, } =20 buffers_start =3D meta->first_buffer; - buffers_end =3D meta->first_buffer + (subbuf_size * meta->nr_subbufs); + buffers_end =3D meta->first_buffer + (meta->nr_subbufs * PAGE_SIZE); =20 /* Is the head and commit buffers within the range of buffers? */ if (meta->head_buffer < buffers_start || @@ -2109,8 +2107,8 @@ static void rb_meta_validate_events(struct ring_buffe= r_per_cpu *cpu_buffer) struct buffer_page *head_page, *orig_head, *orig_reader; struct rb_validation_state state =3D { 0 }; bool skip =3D false; + unsigned long i; int ret; - int i; =20 if (!meta || !meta->head_buffer) return; @@ -2161,7 +2159,7 @@ static void rb_meta_validate_events(struct ring_buffe= r_per_cpu *cpu_buffer) rb_validate_buffer(head_page, cpu_buffer, meta, &state, 0, state.ts); } if (i) - pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i); + pr_info("Ring buffer [%d] rewound %lu pages\n", cpu_buffer->cpu, i); =20 /* The last rewound page must be skipped. */ if (head_page !=3D orig_head) @@ -2245,7 +2243,8 @@ static void rb_meta_validate_events(struct ring_buffe= r_per_cpu *cpu_buffer) } } =20 -static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages, = int scratch_size) +static void rb_range_meta_init(struct trace_buffer *buffer, unsigned long = nr_pages, + int scratch_size) { struct ring_buffer_cpu_meta *meta; unsigned long *subbuf_mask; @@ -2345,8 +2344,8 @@ static int rbm_show(struct seq_file *m, void *v) rb_meta_subbuf_idx(meta, (void *)meta->head_buffer)); seq_printf(m, "commit_buffer: %d\n", rb_meta_subbuf_idx(meta, (void *)meta->commit_buffer)); - seq_printf(m, "subbuf_size: %d\n", meta->subbuf_size); - seq_printf(m, "nr_subbufs: %d\n", meta->nr_subbufs); + seq_printf(m, "subbuf_size: %u\n", meta->subbuf_size); + seq_printf(m, "nr_subbufs: %u\n", meta->nr_subbufs); return 0; } =20 @@ -2431,7 +2430,7 @@ static void *ring_buffer_desc_page(struct ring_buffer= _desc *desc, unsigned int p } =20 static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer, - long nr_pages, struct list_head *pages) + unsigned long nr_pages, struct list_head *pages) { struct trace_buffer *buffer =3D cpu_buffer->buffer; struct ring_buffer_cpu_meta *meta =3D NULL; @@ -2559,7 +2558,7 @@ static int rb_allocate_pages(struct ring_buffer_per_c= pu *cpu_buffer, } =20 static struct ring_buffer_per_cpu * -rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu) +rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages= , int cpu) { struct ring_buffer_per_cpu *cpu_buffer __free(kfree) =3D alloc_cpu_buffer(cpu); @@ -2716,8 +2715,8 @@ static void rb_test_inject_invalid_pages(struct trace= _buffer *buffer) struct ring_buffer_cpu_meta *meta; struct buffer_data_page *dpage; unsigned long entry_bytes =3D 0; + unsigned int subbuf_size; unsigned long ptr; - int subbuf_size; int invalid =3D 0; int cpu; int i; @@ -2787,8 +2786,8 @@ static struct trace_buffer *alloc_buffer(unsigned lon= g size, unsigned flags, struct ring_buffer_remote *remote) { struct trace_buffer *buffer __free(kfree) =3D NULL; - long nr_pages; - int subbuf_size; + unsigned int subbuf_size; + unsigned long nr_pages; int bsize; int cpu; int ret; @@ -5877,12 +5876,12 @@ __rb_get_reader_page_from_remote(struct ring_buffer= _per_cpu *cpu_buffer) static struct buffer_page * __rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) { - int max_loops =3D cpu_buffer->ring_meta ? cpu_buffer->nr_pages : 3; + unsigned long max_loops =3D cpu_buffer->ring_meta ? cpu_buffer->nr_pages = : 3; struct buffer_page *reader =3D NULL; + unsigned long nr_loops =3D 0; unsigned long overwrite; unsigned long flags; int missed_events =3D 0; - int nr_loops =3D 0; bool ret; =20 local_irq_save(flags); @@ -6200,8 +6199,8 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) struct trace_buffer *buffer; struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_event *event; - int nr_loops =3D 0; - int max_loops; + unsigned long nr_loops =3D 0; + unsigned long max_loops; =20 if (ts) *ts =3D 0; @@ -7441,8 +7440,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer = *buffer, int order) struct ring_buffer_per_cpu *cpu_buffer; struct buffer_page *bpage, *tmp; unsigned int old_capacity; + unsigned long nr_pages; int old_order; - int nr_pages; int psize; int err; int cpu; @@ -7624,10 +7623,10 @@ static void rb_setup_ids_meta_page(struct ring_buff= er_per_cpu *cpu_buffer, struct buffer_page **subbuf_ids) { struct trace_buffer_meta *meta =3D cpu_buffer->meta_page; - unsigned int nr_subbufs =3D cpu_buffer->nr_pages + 1; + unsigned long nr_subbufs =3D cpu_buffer->nr_pages + 1; struct buffer_page *first_subbuf, *subbuf; - int cnt =3D 0; - int id =3D 0; + unsigned int cnt =3D 0; + unsigned int id =3D 0; =20 id =3D rb_page_id(cpu_buffer, cpu_buffer->reader_page, id); subbuf_ids[id++] =3D cpu_buffer->reader_page; --=20 2.55.0.979.g7e5102b832-goog