From nobody Sat Sep 26 12:28:31 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 DF8D843E9DF for ; Tue, 1 Sep 2026 15:54:53 +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=1788278095; cv=none; b=SrgypgGnWrn4cPySrXWaGPFrqV9/TH0d5IO0bbtJYFns6toz0nfj/MHkeYA35txvuT0pDqJdZDpq2/kJ6Zj9P61KFIyRiNx7VrezDtEAEYX3Cp1Y/noSLNSzrd5n8emv7RyQvDKrlnvZpAJBHdKWzDLL7BAM+ZgEcP18MEfX+hA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788278095; c=relaxed/simple; bh=zuja3xdGtmWolyyOp5Lht4+r4a2fV671B1BwSQW5ZG4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=RXaGQyjR7Joen9mYjaYY68pfxojQOy7/CdqQuI0dvaD875Ico0hQtIzwbPKw06vzupxflZkvnk88m66tIFHZfvs4+eMtrDQKSv/UREjOZ8TYi6GuRC+fA+CuFNwv4QHpWhZ+5gaSMYcq+xxqJcHIHwyg8naoCsS43pxqg1BL8Z0= 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=aEK5aUYL; 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="aEK5aUYL" Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49b8c651ac0so12936175e9.2 for ; Tue, 01 Sep 2026 08:54:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788278092; x=1788882892; 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=FsJpjMap89L3xg0Jo/p/SVRBiaT1jMUIMpNMGOQC0kY=; b=aEK5aUYLWMKa7kwbs2b7Lg2IrzwsslTxgWzR2sV7876ACHoCVt9kEi/Zf55klxsbf0 zzApXEIZ01BJKclGms/gLl/9hBTwro6axxqtVhSoyoAk0uQamQeunUxyaLJmwPN2ckWe EjZGcZcH8TNBWgzJNmhV1utDavhlQQVIUFBDrp4tBscbyv743lQKPMDacywvq/4WQt31 6Xa+3yXfrR/rOiFaIBa4RmUU0dFrOmyQzf9PhiHh3bdr6Am2mJo6uxFc+W2hTcH2truF 3eMKC+4hfl5RfRnPI3FIEug5RcpMfcGj2fOYAfv9C4tKOwPn8aD8pQyd/a6Hwdbe5LQQ 9vCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788278092; x=1788882892; 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=FsJpjMap89L3xg0Jo/p/SVRBiaT1jMUIMpNMGOQC0kY=; b=sOuW2blBJcraNmFh+wqjEiM/zEZJGUsF6S07ZZLoA0TLF/9cDvPzhFplNtt9pduusb 78VaG7ciAvcd4JI9cpuB2hlpbZ4c15OihO2E5JFAE6wW6I61Jwx13nji5q6Oku5VEkzv Zk12qp1e755xW5sSjBCNAvZuiZZ+sLDfaJKv8o/MT0GJfoJonx5Kui6FBNTPH6JaFYaN o81/2KKnamYDhYpPsSIsqa0rdKvuDtRSpJq0SJGRHkLr1mkCWYi2qSaWAuxuKfjI9WIu zZr6JscrWpM2bgrr2ThE5tLrcMTURNkeqIA9WRGMiM/cwA8UmeSJd8GyGgoIqHaJEtV8 2kVg== X-Forwarded-Encrypted: i=1; AHgh+Rrq8sd+t3Rx+hZ9jDtnJ17hVNpb8AjzKp6pXndVpvUmvu5BSgRRhuMCXVAXLWrQ21w71ePuTKdLBJgcHC0=@vger.kernel.org X-Gm-Message-State: AFuF++kvZ//r7ccTi0TEMsF/CQ5dSRZTfPpWy7OJMnf0zvwWjwTkF2/L vp7wck9rdO5vNuikAnR87DdJpSSuDEKlXaIje7vBpRzilrvSafgy0BdZQuwCw7Y1fQGLIYK0EWL wDj+sWOc65hGPOCl2cXkstQ== X-Received: from wmbhj9.prod.google.com ([2002:a05:600c:5289:b0:49b:6a4f:11f8]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600d:10f:b0:49c:e3b1:d826 with SMTP id 5b1f17b1804b1-49ce3b1dacdmr20137095e9.13.1788278091873; Tue, 01 Sep 2026 08:54:51 -0700 (PDT) Date: Tue, 1 Sep 2026 16:54:42 +0100 In-Reply-To: <20260901155445.1475405-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: <20260901155445.1475405-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.897.gb25b4bd76c-goog Message-ID: <20260901155445.1475405-2-vdonnefort@google.com> Subject: [PATCH v9 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.897.gb25b4bd76c-goog From nobody Sat Sep 26 12:28:31 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 2FC7F442364 for ; Tue, 1 Sep 2026 15:54:55 +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=1788278098; cv=none; b=odUjuUg4L6unzweOrvPs4cEdbPPtP4J7+FL9QLcNsPY9KmQ6oCnCigDQEd+3l3QZOcMKoA1hCBpjtoJqpPmcAxhzv9xZm9P7+PQzQkfR7eqvBzBvrME2aDegYBg0fzBKomoA8OmE1i6uxUfikaB8905JxcUfFDJe1MYbVv2lHCo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788278098; c=relaxed/simple; bh=FNxs5pCwRARHart0e2CaTOpzOrGphTVRLNOLLCperL4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=G5nERQisEPTQ5UylbZ0Rg4CbrJ5+U/QrFF4lO9zrAxUU/AbV/IAaGfqU1FFffm2X55fHpk0+k4lPOCGybRALHgsGEpr1tqXOxf1kd0LxFxQqUyHgH0qOLNWkdhvnsNWFaTrYC6pFCg/yPvhjHuQKJlAx8xyHo2wILa1yb2KOXpM= 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=wZS9GiWw; 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="wZS9GiWw" Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-499913d1a79so28203675e9.0 for ; Tue, 01 Sep 2026 08:54:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788278093; x=1788882893; 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=TTgJgjeHYOkviSh0AwJCPWEp/KgVduk8utkYvFtIsK4=; b=wZS9GiWwskBnli3wbPtJUZO3QZHWWPzyChKZNx3vhZUvDSgND9zgvpCCs3MFolCYtN 4LDrRostPBIqgTUBa+1ejJlRoMyBSp2T1q9jUQEFcwBcN1D0iqcY1qIowS+tLKw8vDEk O28CZqc+RBd73F3396EBHkHvLtopYFBcRMOyGQKLA10l7w8GiXPIvzsj0X6dcfc2thLJ vBK12Pnyv9gXHyZbduNdsekX5xgvhxsI/BHzlbyqbJIsAbHc2ocEZUbGhdIuS4hq9HAp xwbFV9OyNaprbthzu9L/WXiSjRWcz7x9/ljLsrDVFR1s0CY+snVuOw8H/wo4YQbEylYa 4aJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788278093; x=1788882893; 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=TTgJgjeHYOkviSh0AwJCPWEp/KgVduk8utkYvFtIsK4=; b=HEXQYsDRg0+24mxDtOdUAzbRx006fsaHuGMs72YmBSBZTCLAKcjhM9ftISnPJisU4h 2GogwXYstx2HsCGTP8JPfJ5z2tVqZwrNlxuMBGWU5OFSyZ6tp4mRgv6WZqsXdGa4TX2F NFDaKV13Vp+K2XMXRNqSMcZTYVga4fP+j6owLvePDN5gnahCxFz8lAWIMkA1NI91kflI kh8/o2RspBLtpvycft1jWlko3hy1BID49cUoHY+ea5pa0mSUrVKqkwXQsQw7vzhoB/CC 7wmiEmomVzFUAi6H+cQ9XMVoYRWThHZzFTvUZEwgUQ+Gv3kroTDthWrr43a2yj4Q6ROB qowA== X-Forwarded-Encrypted: i=1; AHgh+RpQqfPn6BQliSU5nOOjwuGv17IZRk1kjokLuZtKW42CcIUp7dC2WrPAedztB2TsAQSpf8CBWjq4iPWeEwE=@vger.kernel.org X-Gm-Message-State: AFuF++mORiEibxb0TWxlnyp1qIHKG21muC1pNG4+Yv7fnF0aNFeapB91 KcHAIPpdHU0C0TmAxzGOTuEY5/84KbNOPIG+OVhrL7SDi4P6ZGcMJODGcWYLnjGIUPCM4RZcqQC ncNhG7g3VQkYKn9ur9swAyg== X-Received: from wmpb24.prod.google.com ([2002:a05:600c:4a98:b0:493:f83f:e304]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:c11c:b0:499:b65d:1250 with SMTP id 5b1f17b1804b1-49cdc422c5bmr173400175e9.2.1788278093177; Tue, 01 Sep 2026 08:54:53 -0700 (PDT) Date: Tue, 1 Sep 2026 16:54:43 +0100 In-Reply-To: <20260901155445.1475405-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: <20260901155445.1475405-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.897.gb25b4bd76c-goog Message-ID: <20260901155445.1475405-3-vdonnefort@google.com> Subject: [PATCH v9 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. 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..28dd76edfecf 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 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_dat_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 buffer->subbuf_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 PAGE_SIZE << rpage->order; +} +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 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..7ba3856daf44 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,24 @@ 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 */ +again: 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; - } + spare_size =3D ring_buffer_read_page_size(info->spare); + /* Do we have previous read data to read? */ + if (info->read < spare_size) + goto read; } =20 - 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) + /* Make sure the read page order is aligned with the current subbuf order= */ + ret =3D ring_buffer_alloc_read_page(iter->array_buffer->buffer, iter->cpu= _file, + &info->spare); + if (ret) return ret; =20 - /* Do we have previous read data to read? */ - if (info->read < page_size) - goto read; + spare_size =3D ring_buffer_read_page_size(info->spare); + info->read =3D spare_size; + info->spare_cpu =3D iter->cpu_file; =20 - again: trace_access_lock(iter->cpu_file); ret =3D ring_buffer_read_page(iter->array_buffer->buffer, info->spare, @@ -7148,8 +7136,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); @@ -7199,17 +7188,17 @@ int tracing_buffers_release(struct inode *inode, st= ruct file *file) } =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 @@ -7270,23 +7259,12 @@ ssize_t tracing_buffers_splice_read(struct file *fi= le, loff_t *ppos, }; 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 @@ -7294,7 +7272,8 @@ ssize_t tracing_buffers_splice_read(struct file *file= , loff_t *ppos, trace_access_lock(iter->cpu_file); entries =3D ring_buffer_entries_cpu(iter->array_buffer->buffer, iter->cpu= _file); =20 - for (i =3D 0; i < spd.nr_pages_max && len && entries; i++, len -=3D page_= size) { + for (i =3D 0; i < spd.nr_pages_max && len && entries; i++) { + unsigned int page_size; struct page *page; int r; =20 @@ -7306,25 +7285,36 @@ 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) { + /* + * If the first iteration fails this is an invalid + * userspace input. Otherwise, this is because the + * subbuf order has been modified. Do not report an + * error and 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; @@ -7332,6 +7322,7 @@ ssize_t tracing_buffers_splice_read(struct file *file= , loff_t *ppos, spd.partial[i].private =3D (unsigned long)ref; spd.nr_pages++; *ppos +=3D page_size; + len -=3D page_size; =20 entries =3D ring_buffer_entries_cpu(iter->array_buffer->buffer, iter->cp= u_file); } 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.897.gb25b4bd76c-goog From nobody Sat Sep 26 12:28:31 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 2353A47255C for ; Tue, 1 Sep 2026 15:54:56 +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=1788278097; cv=none; b=I6iK7XL5Qm43QeYQMKP5TJopL/dC9PN/F2zFFfOFdrpmjxiLaWPT0m4sz1Xb/cWjfn58TcAGJBrdTa+ejiuEU2dKDDRHJoKcKKnyffkmqfoulg0VAx4o7+apIhlORJCyAdGaffGpPUigKz1bZOcfu7ngknFfgl89GQSCgMkqOd4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788278097; c=relaxed/simple; bh=eCijVtsZgcpRsQc0B1yK8vF1aLr7q+Wb3A8QSVFsXf4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=uhgXb5qptLH4ukDn4QoyL32+ideBIZVYCGqt9ttsROlfuPQpIMx35YBis7jYOucKqRpmua+Uzfo9K2/1To4KKlsr43FxAe6TZ1eRaPlfQuiILw009brnvmsWHcjkVEkMJ0KzJT6ELmtad/NZa7MrTFeHj6H5gLTLxoo35YNjaY4= 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=JcuDtybu; 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="JcuDtybu" Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49cc9f5bee2so38429385e9.2 for ; Tue, 01 Sep 2026 08:54:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788278094; x=1788882894; 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=+cEeKicgVWXDi4JHgbduzXqGD43TsssX08z/lbVKR9c=; b=JcuDtybuyEdpyUzmFE5ep7hWA0JlnfjeP9ESGGTAdLW/UlERl9K9TVBuEJUFkYI6BQ JEMtvgxXjPcIRppsFwY2Zw0m+18osTDDuhQWTsA61O7AF4kvxjydeVplzezKca0gfTVu 6gdx5pkLPBYjztaNB3J1dKAxzprVs5rgH7tA9gvOhENTGc1vG+cC18GySlIQ9K8Lg8ao E1mbHFmR1+cDfKhBr/hvEBkt4zRipQ4mjm+bMpYBr7mGZAU1l2I2ID8XMsdKTD9VgvX1 MIkaocALF6dKYpkgIEekvP3FAzdUXWgXrwiuTVLB6H7XEI9gDlWUyA4LYaT3RXBb/NzG eQug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788278094; x=1788882894; 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=+cEeKicgVWXDi4JHgbduzXqGD43TsssX08z/lbVKR9c=; b=kWr1TmL3bv1WLBXKv9l7VPU7/Kgn6x7t/Jkv8l5zBHfShfp7SzH7B3UdBNqQSaUClu g7Z/kFR9Y+Su/C77PuHohjh3c8l90z0KL3mSIcG/xI91Ol4mjkNPpy8IReqNBWq+akcw zLgtMZrkDhyilNXf3oU3AZYNZ15HXanQq7odM3gnWLd6i0tUwBB31ZnX6HzOjpEa9dYI lnLGw4zLISGkAdTASMFeN1v5xCnPpXfie3oXxfD+X3pmql9noKjJtPH6NmoyqqD5oo8S EDiVG4XuwfyqaJJdGrOx0pbcQaL9SuFYlpCdhWzu8NetCz4r2v7wswg+gczQNKeeL3eY Es0A== X-Forwarded-Encrypted: i=1; AHgh+RqhAe8nolhvRt3iQoqJG2zguH+8FCkVqz6djRnS45BLgLq/zE6odyGELRrQUy6TcxELdnzt9Xzo5J9s7CI=@vger.kernel.org X-Gm-Message-State: AFuF++l0O8nLvdTWvmLtpxUylGboiEszxOQa6XgSNfnfOzUApWwslX4r IKLwl6ibhKDksUtEM333r+FJDmpxsMggnPvrXEBNV3ir6yGZDR9NUcEdaphEGDI2FgTy/ZNyIOn E/2dkOW4AxkeaywSlhkIhqQ== X-Received: from wmbz8.prod.google.com ([2002:a05:600c:c088:b0:493:c531:facd]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:a012:b0:49c:d818:8764 with SMTP id 5b1f17b1804b1-49cd81887aemr239798875e9.11.1788278094045; Tue, 01 Sep 2026 08:54:54 -0700 (PDT) Date: Tue, 1 Sep 2026 16:54:44 +0100 In-Reply-To: <20260901155445.1475405-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: <20260901155445.1475405-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.897.gb25b4bd76c-goog Message-ID: <20260901155445.1475405-4-vdonnefort@google.com> Subject: [PATCH v9 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, make buffer_page::id 31 bits. This does not change the struct buffer_page size. 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 28dd76edfecf..c4260d6ecdfc 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -350,7 +350,7 @@ struct buffer_page { local_t entries; /* entries on this page */ unsigned long real_end; /* real end of data */ unsigned order; /* order of the page */ - u32 id:30; /* ID for external mapping */ + u32 id:31; /* ID for external mapping */ u32 range:1; /* Mapped via a range */ struct buffer_data_page *page; /* Actual data page */ }; @@ -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 << 31) - 1; +} + struct ring_buffer_iter { struct ring_buffer_per_cpu *cpu_buffer; unsigned long head; @@ -2842,6 +2851,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 +2887,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 +7853,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.897.gb25b4bd76c-goog From nobody Sat Sep 26 12:28:31 2026 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) (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 90FE3442B1C for ; Tue, 1 Sep 2026 15:54:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788278099; cv=none; b=jPaPFHH6l3bC1Z45G06ieNo3auqcQyn6tOtCg8Ep266F993e9U4IHOxb+j9PPaPEJBNvRLbQUI4WiqfJ6es/d+V6LrnfoQ5zQvRBYGRNfWEdUqENzQ93kYY0LL0/w/oLROoIU00WbAEeJnXWJQQ1d8P7BXJWFrakQhoYz/FKkR8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788278099; c=relaxed/simple; bh=AvJkE5WnUbXl7SSzJ4FzUXZW4f2wy+QUeBEgjGH9bJo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=FWzdXGSFdu9mn2voU0BF96gDDt6eiUuJl08mYgfg6shKqdKK8DS377zoKKtqP8TsKWYMBFtcaolcbZkVMVEOxuMDTSaRTygKMIvn3xY1+n5iGLyL1AFV1VGlWzzSPBiwximx+MuZEk+nEdUjybiO9BP3wZbVWmZtN4X5Lz/WPiU= 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=gFJtNFha; arc=none smtp.client-ip=209.85.128.72 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="gFJtNFha" Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4957287363bso33302745e9.0 for ; Tue, 01 Sep 2026 08:54:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788278096; x=1788882896; 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=SYxx9E8yesdUYjVtGHE8XXuxisz/zZjtPq89YqGSK9k=; b=gFJtNFhavLwZbpC6PgkXKM8iRoeJH8BMKEaFxaq3Nz0Bj+35zaukR05C8+b6CYHA5M vvAxPxxCeamK72mC+EhGnw1wziMdhz16dbHpEL/djWx7Lh6Ckz31COxc2bKpehjMsSiC IQNlRKrvfb7lAXV7ioA1W08O17NK/bUvIQerCbijeKimA5MkuBZwFC0rPbXAJsg5YXj9 oERh1+VHh6sILuILm6FDpy1fGMB6OGFqfZdn95HpndYU72aPtnu/iD4PCtc+xT6XJpXF j/ZtuaEiCuPv49XlLxt7kddZ9n2kjh5N7iUIExpOwJ23MF+8wyo9yrsl382LZbWX9Cfk P9jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788278096; x=1788882896; 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=SYxx9E8yesdUYjVtGHE8XXuxisz/zZjtPq89YqGSK9k=; b=S59VBeNGaoqf/Z6PBT9LNjV4Yvkh8ka+ctnNC05XDOxUZtsTlsXMVlJ47hzuXAGNVm U++hkIpby62iIl3IeQFPH4gjB7xKwOSthp83yhwLhsFFUFyDH2mAi2/ig87xWjB07id8 cyXpdE4KbDU86hoDhzOCtv5kCxeXT/waqvmhME+YooWykaE4ID6Ia39Bf3zsUqnAC2X9 UtoqOYEIEVrRX11ETOdMFzj063cXC35lPECeyG6uPeHiZ4tlaHe3UH81vZyuTKbJbfpo TnuVDi1Pfbec13LhtM7B2U+e5e2RX+OZ2kyTt+JvYnctRZAvqU/dnykNfxGWCsWlx7BT xS4g== X-Forwarded-Encrypted: i=1; AHgh+RoA2tKKVRlQ/Fwx44ubCNKK3SfWWEnJJHGpZ6t29hUew9ea/WjUIYIpR0Gm9B5LVeOG+VhasHrElKqEEV4=@vger.kernel.org X-Gm-Message-State: AFuF++nR8BBLm8NhjsZgbmwuCW26S+AiLp+N8Leo0CWs7YwnK54yrIY8 oQWEnysZrttQDkLgOSnAVyVyXXeGIoMe3xg/kk8aLH0SGmk+tW+RLnH8C6PD8/2HJU+qy/WaVxS 20BgR/FxTgJbceL3PJjhZnA== X-Received: from wmbds11.prod.google.com ([2002:a05:600c:628b:b0:499:8840:6abc]) (user=vdonnefort job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:19c8:b0:49b:c8e:a211 with SMTP id 5b1f17b1804b1-49b91c20bfamr546889925e9.5.1788278095515; Tue, 01 Sep 2026 08:54:55 -0700 (PDT) Date: Tue, 1 Sep 2026 16:54:45 +0100 In-Reply-To: <20260901155445.1475405-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: <20260901155445.1475405-1-vdonnefort@google.com> X-Mailer: git-send-email 2.55.0.897.gb25b4bd76c-goog Message-ID: <20260901155445.1475405-5-vdonnefort@google.com> Subject: [PATCH v9 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 31 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 c4260d6ecdfc..ef66f726e2e2 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 int 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,13 @@ 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 subbuf_size =3D PAGE_SIZE; unsigned long buffers_start; unsigned long buffers_end; - int i; + unsigned long i; =20 if (!subbuf_mask) return false; @@ -2109,8 +2108,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 +2160,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 +2244,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 +2345,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 +2431,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 +2559,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 +2716,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 +2787,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; @@ -5875,12 +5875,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); @@ -6198,8 +6198,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; @@ -7439,8 +7439,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; @@ -7622,10 +7622,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.897.gb25b4bd76c-goog