lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260115180918.21dca431@fedora>
Date: Thu, 15 Jan 2026 18:09:18 -0500
From: Steven Rostedt <rostedt@...dmis.org>
To: Linus Torvalds <torvalds@...ux-foundation.org>
Cc: LKML <linux-kernel@...r.kernel.org>, Masami Hiramatsu
 <mhiramat@...nel.org>, Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
 Guenter Roeck <linux@...ck-us.net>, Mark Rutland <mark.rutland@....com>
Subject: [GIT PULL] ftrace: Fix for v6.19


Linus,

ftrace fixes for v6.19:

- Fix allocation accounting on boot up

  The ftrace records for each function that ftrace can attach to is
  done in a group of pages. At boot up, the number of pages are
  calculated and allocated. After that, the pages are filled with data.
  It may allocate more than needed due to some functions not being
  recorded (because they are unused weak functions), this too is
  recorded.

  After the data is filled in, a check is made to make sure the right
  number of pages were allocated. But this was off due to the
  assumption that the same number of entries fit per every page.
  Because the size of an entry does not evenly divide into PAGE_SIZE,
  there is a rounding error when a large number of pages is allocated
  to hold the events. This causes the check to fail and triggers a
  warning.

  Fix the accounting by finding out how many pages are actually
  allocated from the functions that allocate them and use that to see
  if all the pages allocated were used and the ones not used are
  properly freed.


Please pull the latest ftrace-v6.19-rc5 tree, which can be found at:


  git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
ftrace-v6.19-rc5

Tag SHA1: 39cb242e3a690f3e5cc4d22844fe9e837180268c
Head SHA1: be55257fab181b93af38f8c4b1b3cb453a78d742


Guenter Roeck (1):
      ftrace: Do not over-allocate ftrace memory

----
 kernel/trace/ftrace.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)
---------------------------
commit be55257fab181b93af38f8c4b1b3cb453a78d742
Author: Guenter Roeck <linux@...ck-us.net>
Date:   Tue Jan 13 07:22:42 2026 -0800

    ftrace: Do not over-allocate ftrace memory
    
    The pg_remaining calculation in ftrace_process_locs() assumes that
    ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the
    allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE
    (integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g.
    4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages)
    have significantly more capacity than 256 * 170. This leads to pg_remaining
    being underestimated, which in turn makes skip (derived from skipped -
    pg_remaining) larger than expected, causing the WARN(skip != remaining)
    to trigger.
    
    Extra allocated pages for ftrace: 2 with 654 skipped
    WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0
    
    A similar problem in ftrace_allocate_records() can result in allocating
    too many pages. This can trigger the second warning in
    ftrace_process_locs().
    
    Extra allocated pages for ftrace
    WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580
    
    Use the actual capacity of a page group to determine the number of pages
    to allocate. Have ftrace_allocate_pages() return the number of allocated
    pages to avoid having to calculate it. Use the actual page group capacity
    when validating the number of unused pages due to skipped entries.
    Drop the definition of ENTRIES_PER_PAGE since it is no longer used.
    
    Cc: stable@...r.kernel.org
    Fixes: 4a3efc6baff93 ("ftrace: Update the mcount_loc check of skipped entries")
    Link: https://patch.msgid.link/20260113152243.3557219-1-linux@roeck-us.net
    Signed-off-by: Guenter Roeck <linux@...ck-us.net>
    Signed-off-by: Steven Rostedt (Google) <rostedt@...dmis.org>

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ef2d5dca6f70..aa758efc3731 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1148,7 +1148,6 @@ struct ftrace_page {
 };
 
 #define ENTRY_SIZE sizeof(struct dyn_ftrace)
-#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
 
 static struct ftrace_page	*ftrace_pages_start;
 static struct ftrace_page	*ftrace_pages;
@@ -3834,7 +3833,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
 	return 0;
 }
 
-static int ftrace_allocate_records(struct ftrace_page *pg, int count)
+static int ftrace_allocate_records(struct ftrace_page *pg, int count,
+				   unsigned long *num_pages)
 {
 	int order;
 	int pages;
@@ -3844,7 +3844,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
 		return -EINVAL;
 
 	/* We want to fill as much as possible, with no empty pages */
-	pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
+	pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE);
 	order = fls(pages) - 1;
 
  again:
@@ -3859,6 +3859,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
 	}
 
 	ftrace_number_of_pages += 1 << order;
+	*num_pages += 1 << order;
 	ftrace_number_of_groups++;
 
 	cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
@@ -3887,12 +3888,14 @@ static void ftrace_free_pages(struct ftrace_page *pages)
 }
 
 static struct ftrace_page *
-ftrace_allocate_pages(unsigned long num_to_init)
+ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages)
 {
 	struct ftrace_page *start_pg;
 	struct ftrace_page *pg;
 	int cnt;
 
+	*num_pages = 0;
+
 	if (!num_to_init)
 		return NULL;
 
@@ -3906,7 +3909,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
 	 * waste as little space as possible.
 	 */
 	for (;;) {
-		cnt = ftrace_allocate_records(pg, num_to_init);
+		cnt = ftrace_allocate_records(pg, num_to_init, num_pages);
 		if (cnt < 0)
 			goto free_pages;
 
@@ -7192,8 +7195,6 @@ static int ftrace_process_locs(struct module *mod,
 	if (!count)
 		return 0;
 
-	pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
-
 	/*
 	 * Sorting mcount in vmlinux at build time depend on
 	 * CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in
@@ -7206,7 +7207,7 @@ static int ftrace_process_locs(struct module *mod,
 		test_is_sorted(start, count);
 	}
 
-	start_pg = ftrace_allocate_pages(count);
+	start_pg = ftrace_allocate_pages(count, &pages);
 	if (!start_pg)
 		return -ENOMEM;
 
@@ -7305,27 +7306,27 @@ static int ftrace_process_locs(struct module *mod,
 	/* We should have used all pages unless we skipped some */
 	if (pg_unuse) {
 		unsigned long pg_remaining, remaining = 0;
-		unsigned long skip;
+		long skip;
 
 		/* Count the number of entries unused and compare it to skipped. */
-		pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index;
+		pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index;
 
 		if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) {
 
 			skip = skipped - pg_remaining;
 
-			for (pg = pg_unuse; pg; pg = pg->next)
+			for (pg = pg_unuse; pg && skip > 0; pg = pg->next) {
 				remaining += 1 << pg->order;
+				skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE;
+			}
 
 			pages -= remaining;
 
-			skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE);
-
 			/*
 			 * Check to see if the number of pages remaining would
 			 * just fit the number of entries skipped.
 			 */
-			WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped",
+			WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped",
 			     remaining, skipped);
 		}
 		/* Need to synchronize with ftrace_location_range() */

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ